Ver código fonte

Migrate KtorParameterDecoder

ryoii 2 anos atrás
pai
commit
f45fccba52

+ 2 - 5
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/http/router/dsl.kt

@@ -17,13 +17,11 @@ import io.ktor.server.response.*
 import io.ktor.server.routing.*
 import io.ktor.util.*
 import io.ktor.util.pipeline.*
-import kotlinx.serialization.InternalSerializationApi
-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.plugin.session
-import net.mamoe.mirai.api.http.adapter.http.util.KtorParameterFormat
+import net.mamoe.mirai.api.http.adapter.http.support.receiveParameter
 import net.mamoe.mirai.api.http.adapter.internal.consts.Paths
 import net.mamoe.mirai.api.http.adapter.internal.dto.AuthedDTO
 import net.mamoe.mirai.api.http.adapter.internal.dto.BindDTO
@@ -108,13 +106,12 @@ internal inline fun <reified T : AuthedDTO> Route.httpAuthedPost(
  * Get,用于获取bot的属性
  * 验证请求参数中sessionKey参数的有效性
  */
-@OptIn(InternalSerializationApi::class)
 @KtorDsl
 internal inline fun <reified T : AuthedDTO> Route.httpAuthedGet(
     path: String,
     crossinline body: Strategy<T>
 ) = routeWithHandle(path, HttpMethod.Get) {
-    val dto = KtorParameterFormat.DEFAULT.decode(context.parameters, T::class.serializer())
+    val dto = call.receiveParameter<T>()
 
     getAuthedSession(dto.sessionKey).also { dto.session = it }
     this.body(dto)

+ 16 - 8
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/http/util/KtorParameterFormat.kt → mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/adapter/http/support/KtorParameterFormat.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 Mamoe Technologies and contributors.
+ * 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.
@@ -7,9 +7,10 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.api.http.adapter.http.util
+package net.mamoe.mirai.api.http.adapter.http.support
 
 import io.ktor.http.*
+import io.ktor.server.application.*
 import kotlinx.serialization.*
 import kotlinx.serialization.descriptors.SerialDescriptor
 import kotlinx.serialization.descriptors.StructureKind
@@ -18,22 +19,28 @@ import kotlinx.serialization.encoding.CompositeDecoder.Companion.DECODE_DONE
 import kotlinx.serialization.modules.EmptySerializersModule
 import kotlinx.serialization.modules.SerializersModule
 
+/**
+ * ktor parameter support
+ */
+@OptIn(InternalSerializationApi::class)
+internal inline fun <reified T : Any> ApplicationCall.receiveParameter(): T =
+    KtorParameterFormat.DEFAULT.decode(parameters, T::class.serializer())
+
 /**
  * ktor parameter 序列化器
  *
  * 简单实现, 后续可追加配置
  */
-@OptIn(ExperimentalSerializationApi::class)
 internal class KtorParameterFormat : SerialFormat {
 
-    override val serializersModule = EmptySerializersModule
+    override val serializersModule = EmptySerializersModule()
 
     companion object {
         val DEFAULT = KtorParameterFormat()
     }
 
     internal inline fun <reified T : Any> decode(parameters: Parameters, s: KSerializer<T>): T {
-        return s.deserialize(KtorParameterDecoder(parameters))
+        return s.deserialize(KtorParameterDecoder(parameters, serializersModule))
     }
 }
 
@@ -44,14 +51,15 @@ internal class KtorParameterFormat : SerialFormat {
  * + 级联
  */
 @OptIn(ExperimentalSerializationApi::class)
-internal class KtorParameterDecoder(parameters: Parameters) : AbstractDecoder() {
+internal class KtorParameterDecoder(
+    parameters: Parameters,
+    override val serializersModule: SerializersModule
+) : AbstractDecoder() {
 
     private lateinit var entryHolder: Map.Entry<String, List<String>>
     private val iterator = parameters.entries().iterator()
     private var curPos = 0
 
-    override val serializersModule: SerializersModule = EmptySerializersModule
-
     override fun decodeValue(): String {
         return entryHolder.value[(curPos - 1).coerceAtLeast(0)]
     }

+ 36 - 7
mirai-api-http/src/test/kotlin/net/mamoe/mirai/api/http/adapter/internal/serializer/KtorParameterFormatTest.kt → mirai-api-http/src/test/kotlin/net/mamoe/mirai/api/http/adapter/http/support/KtorParameterFormatTest.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 Mamoe Technologies and contributors.
+ * 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.
@@ -7,16 +7,21 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.api.http.adapter.internal.serializer
+package net.mamoe.mirai.api.http.adapter.http.support
 
+import io.ktor.client.request.*
 import io.ktor.http.*
+import io.ktor.server.application.*
+import io.ktor.server.response.*
+import io.ktor.server.routing.*
+import io.ktor.server.testing.*
 import kotlinx.serialization.Serializable
-import net.mamoe.mirai.api.http.adapter.http.util.KtorParameterFormat
-import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.MessageIdDTO
 import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.NudgeDTO
 import net.mamoe.mirai.api.http.context.MahContext
 import kotlin.test.Test
 import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
 
 class KtorParameterFormatTest {
 
@@ -29,7 +34,7 @@ class KtorParameterFormatTest {
             "kind" to listOf("k"),
             "sessionKey" to listOf("ss")
         )
-        val dto = KtorParameterFormat.DEFAULT.decode(param, NudgeDTO.serializer())
+        val dto = KtorParameterFormat().decode(param, NudgeDTO.serializer())
         assertEquals(expected, dto, "KtorParameterSerializer decode failed")
         assertEquals("ss", dto.sessionKey, "KtorParameterSerializer default value decode failed")
     }
@@ -45,7 +50,7 @@ class KtorParameterFormatTest {
             "subject" to listOf("321"),
             "kind" to listOf("k"),
         )
-        val dto = KtorParameterFormat.DEFAULT.decode(param, NudgeDTO.serializer())
+        val dto = KtorParameterFormat().decode(param, NudgeDTO.serializer())
         assertEquals(expected, dto, "KtorParameterSerializer decode failed")
         assertEquals(MahContext.SINGLE_SESSION_KEY, dto.sessionKey, "KtorParameterSerializer default value decode failed")
     }
@@ -57,7 +62,7 @@ class KtorParameterFormatTest {
             "target" to listOf("1"),
             "memberIds" to listOf("5", "1", "4"),
         )
-        val dto = KtorParameterFormat.DEFAULT.decode(param, TestMulti.serializer())
+        val dto = KtorParameterFormat().decode(param, TestMulti.serializer())
         assertEquals(expected, dto, "KtorParameterSerializer decode failed")
     }
 
@@ -66,4 +71,28 @@ class KtorParameterFormatTest {
         val target: Long,
         val memberIds: List<String>?
     )
+
+    @Test
+    fun testWithCall() = testApplication {
+
+        routing {
+            get("/test") {
+                val dto = call.receiveParameter<TestMulti>()
+                assertEquals(123, dto.target)
+                assertNotNull(dto.memberIds)
+                assertTrue(dto.memberIds.containsAll(listOf("id1", "id2", "id3")))
+
+                call.respond(HttpStatusCode.OK)
+            }
+        }
+
+        client.get("/test") {
+            parameter("target", 123)
+            parameter("memberIds", "id1")
+            parameter("memberIds", "id2")
+            parameter("memberIds", "id3")
+        }.also {
+            assertEquals(HttpStatusCode.OK, it.status)
+        }
+    }
 }