Skip to content

Commit

Permalink
Migrate ktor http plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
ryoii committed Oct 8, 2023
1 parent 6cf81ae commit 6ffa578
Show file tree
Hide file tree
Showing 10 changed files with 293 additions and 174 deletions.
1 change: 1 addition & 0 deletions mirai-api-http/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dependencies {
ktorApi("server-websockets")
ktorApi("server-default-headers")
ktorApi("server-cors")
ktorApi("server-double-receive")
ktorApi("client-okhttp")
ktorApi("client-websockets")
ktorApi("client-content-negotiation")
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/

package net.mamoe.mirai.api.http.adapter.http.plugin

import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.util.*
import net.mamoe.mirai.api.http.context.MahContextHolder
import net.mamoe.mirai.api.http.context.session.Session

private val sessionAttr: AttributeKey<Session> = AttributeKey("session")
val Authorization = createApplicationPlugin("Authorization") {

onCall { call ->
if (MahContextHolder.singleMode) {
return@onCall
}

val sessionKey = call.sessionKeyFromHeader() ?: call.sessionKeyFromAuthorization()
if (sessionKey != null) {
MahContextHolder[sessionKey]?.let {
call.attributes.put(sessionAttr, it)
}
}
}
}

val ApplicationCall.session: Session?
get() {
return this.attributes.getOrNull(sessionAttr)
}

private fun ApplicationCall.sessionKeyFromHeader(): String? {
return request.header("sessionKey")
}

private fun ApplicationCall.sessionKeyFromAuthorization(): String? {
return request.header("Authorization")?.run {
val (type, value) = split(' ', limit = 2)

return if (type.equals("session", ignoreCase = true) || type.equals("sessionKey", ignoreCase = true)) {
value
} else {
null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2023 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/

package net.mamoe.mirai.api.http.adapter.http.plugin

import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.plugins.*
import io.ktor.server.request.*
import net.mamoe.mirai.utils.MiraiLogger

val logger by lazy { MiraiLogger.Factory.create(HttpRouterMonitor::class, "MAH Access") }
val HttpRouterMonitor = createApplicationPlugin("HttpRouterAccessMonitor") {
on(Monitor) { call ->
call.logAccess()
}
}

private suspend fun ApplicationCall.logAccess() {
logger.debug("requesting [${request.origin.version}] [${request.httpMethod.value}] ${request.uri}")
if (!request.isMultipart()) {
logger.debug("with ${parseRequestParameter()}")
}
}

private suspend fun ApplicationCall.parseRequestParameter(): String =
when (request.httpMethod) {
HttpMethod.Get -> request.queryString()
HttpMethod.Post -> receiveText()
else -> "<method: $request.httpMethod>"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright 2023 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/

package net.mamoe.mirai.api.http.adapter.http.plugin

import io.ktor.server.application.*

internal object Monitor : Hook<suspend (ApplicationCall) -> Unit> {
override fun install(pipeline: ApplicationCallPipeline, handler: suspend (ApplicationCall) -> Unit) {
pipeline.intercept(ApplicationCallPipeline.Monitoring) {
handler(call)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ package net.mamoe.mirai.api.http.adapter.http.router
import io.ktor.server.application.*
import io.ktor.server.plugins.cors.routing.*
import io.ktor.server.plugins.defaultheaders.*
import io.ktor.server.plugins.doublereceive.*
import net.mamoe.mirai.api.http.adapter.http.HttpAdapter
import net.mamoe.mirai.api.http.adapter.http.feature.auth.Authorization
import net.mamoe.mirai.api.http.adapter.http.feature.handler.HttpRouterAccessHandler
import net.mamoe.mirai.api.http.adapter.http.plugin.Authorization
import net.mamoe.mirai.api.http.adapter.http.plugin.HttpRouterMonitor
import net.mamoe.mirai.api.http.context.MahContextHolder


Expand All @@ -30,7 +31,10 @@ fun Application.httpModule(adapter: HttpAdapter) {
}

install(Authorization)
install(HttpRouterAccessHandler) { enableAccessLog = MahContextHolder.debug }
if (MahContextHolder.debug) {
install(DoubleReceive)
install(HttpRouterMonitor)
}

authRouter(adapter.setting)
messageRouter()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@

package net.mamoe.mirai.api.http.adapter.http.router

import io.ktor.server.application.*
import io.ktor.http.*
import io.ktor.http.content.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
Expand All @@ -22,8 +22,7 @@ import kotlinx.serialization.serializer
import net.mamoe.mirai.api.http.adapter.common.IllegalParamException
import net.mamoe.mirai.api.http.adapter.common.IllegalSessionException
import net.mamoe.mirai.api.http.adapter.common.StateCode
import net.mamoe.mirai.api.http.adapter.http.feature.auth.Authorization.headerSession
import net.mamoe.mirai.api.http.adapter.http.feature.handler.HttpRouterAccessHandler.Feature.bodyContent
import net.mamoe.mirai.api.http.adapter.http.plugin.session
import net.mamoe.mirai.api.http.adapter.http.util.KtorParameterFormat
import net.mamoe.mirai.api.http.adapter.internal.consts.Paths
import net.mamoe.mirai.api.http.adapter.internal.dto.AuthedDTO
Expand Down Expand Up @@ -140,7 +139,7 @@ internal inline fun Route.httpAuthedMultiPart(
* 获取 session 并进行类型校验
*/
private fun PipelineContext<*, ApplicationCall>.getAuthedSession(sessionKey: String): Session {
return headerSession ?: MahContextHolder[sessionKey]
return call.session ?: MahContextHolder[sessionKey]
?: throw IllegalSessionException
}

Expand Down Expand Up @@ -169,8 +168,8 @@ internal suspend fun ApplicationCall.respondJson(json: String, status: HttpStatu
/**
* 接收 http body 指定类型 [T] 的 [DTO]
*/
internal inline fun <reified T : DTO> ApplicationCall.receiveDTO(): T? =
bodyContent().jsonParseOrNull()
internal suspend inline fun <reified T : DTO> ApplicationCall.receiveDTO(): T? =
receive<String>().jsonParseOrNull()

/**
* 接收 http multi part 值类型
Expand Down
Loading

0 comments on commit 6ffa578

Please sign in to comment.