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 7, 2023
1 parent 6cf81ae commit 1d8c5c7
Show file tree
Hide file tree
Showing 10 changed files with 302 additions and 174 deletions.

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,20 @@
package net.mamoe.mirai.api.http.adapter.http.plugin

import io.ktor.server.application.*
import io.ktor.util.*
import io.ktor.utils.io.*

private val doubleReceiveAttrKey: AttributeKey<Any> = AttributeKey("doubleReceiveBody")
val DoubleReceive = createApplicationPlugin("DoubleReceive") {

on(ReceiveBodyTransformed) { call, body ->
if (body is ByteReadChannel) return@on body

call.attributes.getOrNull(doubleReceiveAttrKey)?.let {
return@on it
}

call.attributes.put(doubleReceiveAttrKey, body)
return@on body
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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.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 -> receive<String>()
else -> "<method: $request.httpMethod>"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package net.mamoe.mirai.api.http.adapter.http.plugin

import io.ktor.server.application.*
import io.ktor.server.request.*

internal object Monitor : Hook<suspend (ApplicationCall) -> Unit> {
override fun install(pipeline: ApplicationCallPipeline, handler: suspend (ApplicationCall) -> Unit) {
pipeline.intercept(ApplicationCallPipeline.Monitoring) {
handler(call)
}
}
}

internal object ReceiveBodyTransformed : Hook<suspend (ApplicationCall, Any) -> Any> {
override fun install(
pipeline: ApplicationCallPipeline,
handler: suspend (call: ApplicationCall, state: Any) -> Any
) {
pipeline.receivePipeline.intercept(ApplicationReceivePipeline.After) {
val body = handler(call, it)
proceedWith(body)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import io.ktor.server.application.*
import io.ktor.server.plugins.cors.routing.*
import io.ktor.server.plugins.defaultheaders.*
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.DoubleReceive
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 1d8c5c7

Please sign in to comment.