Merge branch 'http-refactor'

This commit is contained in:
ryoii 2020-02-08 18:18:53 +08:00
commit 2687b55f8b
13 changed files with 171 additions and 174 deletions

View File

@ -0,0 +1,38 @@
package net.mamoe.mirai.api.http.data
/**
* 错误请求. 抛出这个异常后将会返回错误给一个请求
*/
@Suppress("unused")
open class IllegalAccessException : Exception {
override val message: String get() = super.message!!
constructor(message: String) : super(message, null)
constructor(cause: Throwable) : super(cause.toString(), cause)
constructor(message: String, cause: Throwable?) : super(message, cause)
}
/**
* Session失效或不存在
*/
object IllegalSessionException : IllegalAccessException("Session失效或不存在")
/**
* Session未激活
*/
object NotVerifiedSessionException : IllegalAccessException("Session未激活")
/**
* 指定Bot不存在
*/
object NoSuchBotException: IllegalAccessException("指定Bot不存在")
/**
* 指定Bot不存在
*/
object PermissionDeniedException: IllegalAccessException("无操作限权")
/**
* 错误参数
*/
class IllegalParamException(message: String) : IllegalAccessException(message)

View File

@ -0,0 +1,21 @@
package net.mamoe.mirai.api.http.data
import kotlinx.serialization.Serializable
@Serializable
open class StateCode(val code: Int, var msg: String) {
object Success : StateCode(0, "success") // 成功
object NoBot : StateCode(2, "指定Bot不存在")
object IllegalSession : StateCode(3, "Session失效或不存在")
object NotVerifySession : StateCode(4, "Session未认证")
object NoElement : StateCode(5, "指定对象不存在")
object PermissionDenied : StateCode(10, "无操作权限")
// KS bug: 主构造器中不能有非字段参数 https://github.com/Kotlin/kotlinx.serialization/issues/575
@Serializable
class IllegalAccess() : StateCode(400, "") { // 非法访问
constructor(msg: String) : this() {
this.msg = msg
}
}
}

View File

@ -1,4 +1,4 @@
package net.mamoe.mirai.api.http.dto package net.mamoe.mirai.api.http.data.common
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Group
@ -30,7 +30,8 @@ data class MemberDTO(
val group: GroupDTO val group: GroupDTO
) : ContactDTO() { ) : ContactDTO() {
constructor(member: Member) : this ( constructor(member: Member) : this (
member.id, member.groupCard, member.permission, GroupDTO(member.group) member.id, member.groupCard, member.permission,
GroupDTO(member.group)
) )
} }

View File

@ -0,0 +1,18 @@
package net.mamoe.mirai.api.http.data.common
import kotlinx.serialization.*
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import net.mamoe.mirai.api.http.AuthedSession
interface DTO
@Serializable
data class AuthDTO(val authKey: String) : DTO
@Serializable
abstract class VerifyDTO : DTO {
abstract val sessionKey: String
@Transient
lateinit var session: AuthedSession // 反序列化验证成功后传入
}

View File

@ -1,4 +1,4 @@
package net.mamoe.mirai.api.http.dto package net.mamoe.mirai.api.http.data.common
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@ -1,6 +0,0 @@
package net.mamoe.mirai.api.http.dto
import kotlinx.serialization.Serializable
@Serializable
data class AuthDTO(val authKey: String) : DTO

View File

@ -1,97 +0,0 @@
package net.mamoe.mirai.api.http.dto
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import net.mamoe.mirai.api.http.AuthedSession
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.Member
@Serializable
abstract class VerifyDTO : DTO {
abstract val sessionKey: String
@Transient
lateinit var session: AuthedSession // 反序列化验证后传入
}
@Serializable
data class BindDTO(override val sessionKey: String, val qq: Long) : VerifyDTO()
@Serializable
data class SendDTO(
override val sessionKey: String,
val target: Long,
val messageChain: MessageChainDTO
) : VerifyDTO()
typealias GroupTargetDTO = FriendTargetDTO
@Serializable
data class FriendTargetDTO(
override val sessionKey: String,
val target: Long
) : VerifyDTO()
@Serializable
data class MuteDTO(
override val sessionKey: String,
val target: Long,
val member: Long = 0,
val time: Int = 0
) : VerifyDTO()
@Serializable
data class GroupConfigDTO(
override val sessionKey: String,
val target: Long,
val config: GroupInfoDTO
) : VerifyDTO()
@Serializable
data class GroupInfoDTO(
val name: String? = null,
val announcement: String? = null,
val confessTalk: Boolean? = null,
val allowMemberInvite: Boolean? = null,
val autoApprove: Boolean? = null,
val anonymousChat: Boolean? = null
) : DTO {
constructor(group: Group) : this(
group.name, group.announcement, group.confessTalk, group.allowMemberInvite,
group.autoApprove, group.anonymousChat
)
}
@Serializable
data class MemberConfigDTO(
override val sessionKey: String,
val target: Long,
val memberId: Long,
val config: MemberInfoDTO
) : VerifyDTO()
@Serializable
data class MemberInfoDTO(
val name: String? = null,
val specialTitle: String? = null
) : DTO {
constructor(member: Member) : this(member.groupCard, member.specialTitle)
}
@Serializable
open class StateCode(val code: Int, var msg: String) {
object Success : StateCode(0, "success") // 成功
object NoBot : StateCode(2, "指定Bot不存在")
object IllegalSession : StateCode(3, "Session失效或不存在")
object NotVerifySession : StateCode(4, "Session未认证")
object NoElement : StateCode(5, "指定对象不存在")
object PermissionDenied : StateCode(10, "无操作权限")
// KS bug: 主构造器中不能有非字段参数 https://github.com/Kotlin/kotlinx.serialization/issues/575
@Serializable
class IllegalAccess() : StateCode(400, "") { // 非法访问
constructor(msg: String) : this() {
this.msg = msg
}
}
}

View File

@ -3,10 +3,12 @@ package net.mamoe.mirai.api.http.route
import io.ktor.application.Application import io.ktor.application.Application
import io.ktor.application.call import io.ktor.application.call
import io.ktor.routing.routing import io.ktor.routing.routing
import kotlinx.serialization.Serializable
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.api.http.AuthedSession import net.mamoe.mirai.api.http.AuthedSession
import net.mamoe.mirai.api.http.SessionManager import net.mamoe.mirai.api.http.SessionManager
import net.mamoe.mirai.api.http.dto.* import net.mamoe.mirai.api.http.data.*
import net.mamoe.mirai.api.http.data.common.VerifyDTO
import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.EmptyCoroutineContext
@ -43,6 +45,9 @@ fun Application.authModule() {
} }
} }
@Serializable
private data class BindDTO(override val sessionKey: String, val qq: Long) : VerifyDTO()
private fun getBotOrThrow(qq: Long) = try { private fun getBotOrThrow(qq: Long) = try {
Bot.instanceWhose(qq) Bot.instanceWhose(qq)
} catch (e: NoSuchElementException) { } catch (e: NoSuchElementException) {

View File

@ -19,7 +19,10 @@ import io.ktor.util.pipeline.PipelineContext
import net.mamoe.mirai.api.http.AuthedSession import net.mamoe.mirai.api.http.AuthedSession
import net.mamoe.mirai.api.http.SessionManager import net.mamoe.mirai.api.http.SessionManager
import net.mamoe.mirai.api.http.TempSession import net.mamoe.mirai.api.http.TempSession
import net.mamoe.mirai.api.http.dto.* import net.mamoe.mirai.api.http.data.*
import net.mamoe.mirai.api.http.data.common.*
import net.mamoe.mirai.api.http.util.jsonParseOrNull
import net.mamoe.mirai.api.http.util.toJson
fun Application.mirai() { fun Application.mirai() {
install(DefaultHeaders) install(DefaultHeaders)
@ -136,14 +139,13 @@ internal suspend fun ApplicationCall.respondJson(json: String, status: HttpStatu
internal suspend inline fun <reified T : DTO> ApplicationCall.receiveDTO(): T? = receive<String>().jsonParseOrNull() internal suspend inline fun <reified T : DTO> ApplicationCall.receiveDTO(): T? = receive<String>().jsonParseOrNull()
fun PipelineContext<Unit, ApplicationCall>.illegalParam( fun PipelineContext<Unit, ApplicationCall>.illegalParam(
expectingType: String?, expectingType: String?,
paramName: String, paramName: String,
actualValue: String? = call.parameters[paramName] actualValue: String? = call.parameters[paramName]
): Nothing = throw IllegalParamException("Illegal param. A $expectingType is required for `$paramName` while `$actualValue` is given") ): Nothing = throw IllegalParamException("Illegal param. A $expectingType is required for `$paramName` while `$actualValue` is given")
@Suppress("IMPLICIT_CAST_TO_ANY") @Suppress("IMPLICIT_CAST_TO_ANY")
@UseExperimental(ExperimentalUnsignedTypes::class) @UseExperimental(ExperimentalUnsignedTypes::class)
internal inline fun <reified R> PipelineContext<Unit, ApplicationCall>.paramOrNull(name: String): R = internal inline fun <reified R> PipelineContext<Unit, ApplicationCall>.paramOrNull(name: String): R =
@ -171,42 +173,3 @@ internal inline fun <reified R> PipelineContext<Unit, ApplicationCall>.paramOrNu
else -> error(name::class.simpleName + " is not supported") else -> error(name::class.simpleName + " is not supported")
} as R ?: illegalParam(R::class.simpleName, name) } as R ?: illegalParam(R::class.simpleName, name)
/**
* 错误请求. 抛出这个异常后将会返回错误给一个请求
*/
@Suppress("unused")
open class IllegalAccessException : Exception {
override val message: String get() = super.message!!
constructor(message: String) : super(message, null)
constructor(cause: Throwable) : super(cause.toString(), cause)
constructor(message: String, cause: Throwable?) : super(message, cause)
}
/**
* Session失效或不存在
*/
object IllegalSessionException : IllegalAccessException("Session失效或不存在")
/**
* Session未激活
*/
object NotVerifiedSessionException : IllegalAccessException("Session未激活")
/**
* 指定Bot不存在
*/
object NoSuchBotException: IllegalAccessException("指定Bot不存在")
/**
* 指定Bot不存在
*/
object PermissionDeniedException: IllegalAccessException("无操作限权")
/**
* 错误参数
*/
class IllegalParamException(message: String) : IllegalAccessException(message)

View File

@ -3,7 +3,12 @@ package net.mamoe.mirai.api.http.route
import io.ktor.application.Application import io.ktor.application.Application
import io.ktor.application.call import io.ktor.application.call
import io.ktor.routing.routing import io.ktor.routing.routing
import net.mamoe.mirai.api.http.dto.* import kotlinx.serialization.Serializable
import net.mamoe.mirai.api.http.data.*
import net.mamoe.mirai.api.http.data.common.DTO
import net.mamoe.mirai.api.http.data.common.VerifyDTO
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.Member
fun Application.groupManageModule() { fun Application.groupManageModule() {
@ -23,14 +28,14 @@ fun Application.groupManageModule() {
} }
miraiVerify<MuteDTO>("/mute") { miraiVerify<MuteDTO>("/mute") {
when(it.session.bot.getGroup(it.target)[it.member].mute(it.time)) { when(it.session.bot.getGroup(it.target)[it.memberId].mute(it.time)) {
true -> call.respondStateCode(StateCode.Success) true -> call.respondStateCode(StateCode.Success)
else -> throw PermissionDeniedException else -> throw PermissionDeniedException
} }
} }
miraiVerify<MuteDTO>("/unmute") { miraiVerify<MuteDTO>("/unmute") {
when(it.session.bot.getGroup(it.target).members[it.member].unmute()) { when(it.session.bot.getGroup(it.target).members[it.memberId].unmute()) {
true -> call.respondStateCode(StateCode.Success) true -> call.respondStateCode(StateCode.Success)
else -> throw PermissionDeniedException else -> throw PermissionDeniedException
} }
@ -41,7 +46,7 @@ fun Application.groupManageModule() {
*/ */
miraiGet("/groupConfig") { miraiGet("/groupConfig") {
val group = it.bot.getGroup(paramOrNull("target")) val group = it.bot.getGroup(paramOrNull("target"))
call.respondDTO(GroupInfoDTO(group)) call.respondDTO(GroupDetailDTO(group))
} }
miraiVerify<GroupConfigDTO>("/groupConfig") { dto -> miraiVerify<GroupConfigDTO>("/groupConfig") { dto ->
@ -62,13 +67,13 @@ fun Application.groupManageModule() {
* 群员信息管理需要相关权限 * 群员信息管理需要相关权限
*/ */
miraiGet("/memberInfo") { miraiGet("/memberInfo") {
val member = it.bot.getGroup(paramOrNull("target"))[paramOrNull("memberID")] val member = it.bot.getGroup(paramOrNull("target"))[paramOrNull("memberId")]
call.respondDTO(MemberInfoDTO(member)) call.respondDTO(MemberDetailDTO(member))
} }
miraiVerify<MemberConfigDTO>("/memberInfo") { dto -> miraiVerify<MemberInfoDTO>("/memberInfo") { dto ->
val member = dto.session.bot.getGroup(dto.target)[dto.memberId] val member = dto.session.bot.getGroup(dto.target)[dto.memberId]
with(dto.config) { with(dto.info) {
name?.let { member.groupCard = it } name?.let { member.groupCard = it }
specialTitle?.let { member.specialTitle = it } specialTitle?.let { member.specialTitle = it }
} }
@ -76,4 +81,51 @@ fun Application.groupManageModule() {
} }
} }
}
@Serializable
private data class MuteDTO(
override val sessionKey: String,
val target: Long,
val memberId: Long = 0,
val time: Int = 0
) : VerifyDTO()
@Serializable
private data class GroupConfigDTO(
override val sessionKey: String,
val target: Long,
val config: GroupDetailDTO
) : VerifyDTO()
@Serializable
private data class GroupDetailDTO(
val name: String? = null,
val announcement: String? = null,
val confessTalk: Boolean? = null,
val allowMemberInvite: Boolean? = null,
val autoApprove: Boolean? = null,
val anonymousChat: Boolean? = null
) : DTO {
constructor(group: Group) : this(
group.name, group.announcement, group.confessTalk, group.allowMemberInvite,
group.autoApprove, group.anonymousChat
)
}
@Serializable
private data class MemberInfoDTO(
override val sessionKey: String,
val target: Long,
val memberId: Long,
val info: MemberDetailDTO
) : VerifyDTO()
@Serializable
private data class MemberDetailDTO(
val name: String? = null,
val specialTitle: String? = null
) : DTO {
constructor(member: Member) : this(member.groupCard, member.specialTitle)
} }

View File

@ -3,10 +3,10 @@ package net.mamoe.mirai.api.http.route
import io.ktor.application.Application import io.ktor.application.Application
import io.ktor.application.call import io.ktor.application.call
import io.ktor.routing.routing import io.ktor.routing.routing
import net.mamoe.mirai.api.http.dto.GroupDTO import net.mamoe.mirai.api.http.data.common.GroupDTO
import net.mamoe.mirai.api.http.dto.MemberDTO import net.mamoe.mirai.api.http.data.common.MemberDTO
import net.mamoe.mirai.api.http.dto.QQDTO import net.mamoe.mirai.api.http.data.common.QQDTO
import net.mamoe.mirai.api.http.dto.toJson import net.mamoe.mirai.api.http.util.toJson
import net.mamoe.mirai.contact.toMutableList import net.mamoe.mirai.contact.toMutableList
fun Application.infoModule() { fun Application.infoModule() {

View File

@ -3,7 +3,10 @@ package net.mamoe.mirai.api.http.route
import io.ktor.application.Application import io.ktor.application.Application
import io.ktor.application.call import io.ktor.application.call
import io.ktor.routing.routing import io.ktor.routing.routing
import net.mamoe.mirai.api.http.dto.* import kotlinx.serialization.Serializable
import net.mamoe.mirai.api.http.data.*
import net.mamoe.mirai.api.http.data.common.*
import net.mamoe.mirai.api.http.util.toJson
fun Application.messageModule() { fun Application.messageModule() {
routing { routing {
@ -26,12 +29,12 @@ fun Application.messageModule() {
call.respondStateCode(StateCode.Success) call.respondStateCode(StateCode.Success)
} }
miraiVerify<VerifyDTO>("/event/message") {
}
miraiVerify<VerifyDTO>("/addFriend") {
}
} }
} }
@Serializable
private data class SendDTO(
override val sessionKey: String,
val target: Long,
val messageChain: MessageChainDTO
) : VerifyDTO()

View File

@ -1,10 +1,9 @@
package net.mamoe.mirai.api.http.dto package net.mamoe.mirai.api.http.util
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.SerializersModule
import net.mamoe.mirai.api.http.data.common.*
interface DTO
// 解析失败时直接返回null由路由判断响应400状态 // 解析失败时直接返回null由路由判断响应400状态
@UseExperimental(ImplicitReflectionSerializer::class) @UseExperimental(ImplicitReflectionSerializer::class)
@ -20,7 +19,7 @@ inline fun <reified T : Any> String.jsonParseOrNull(
inline fun <reified T : Any> T.toJson( inline fun <reified T : Any> T.toJson(
serializer: SerializationStrategy<T>? = null serializer: SerializationStrategy<T>? = null
): String = if (serializer == null) MiraiJson.json.stringify(this) ): String = if (serializer == null) MiraiJson.json.stringify(this)
else MiraiJson.json.stringify(serializer, this) else MiraiJson.json.stringify(serializer, this)
// 序列化列表时stringify需要使用的泛型是T而非List<T> // 序列化列表时stringify需要使用的泛型是T而非List<T>