Skip to content

Commit

Permalink
Http CommonRouter and echo
Browse files Browse the repository at this point in the history
  • Loading branch information
ryoii committed Oct 10, 2023
1 parent 235e18a commit 9e4ba4e
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 2 deletions.
44 changes: 43 additions & 1 deletion docs/adapter/HttpAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ adapterSettings:
#### 专有接口
专有接口为该 `adapter` 特有的接口

+ **[测试](#测试接口)**
+ [路由](#路由)
+ [回响](#回响)
+ **[认证与会话](#认证与会话)**
+ [认证](#认证)
+ [绑定](#绑定)
Expand Down Expand Up @@ -104,6 +106,46 @@ adapterSettings:
+ [注册命令](#注册命令)
+ [命令接收](#命令接收)

## 测试

### 路由

#### 接口名称
```
[GET] /router/{path}
[GET] /router?router={path}
[GET} /router/{path1}?router={path2} // 使用 path1

[POST] /router
[POST] /router/{path}
```
此方法为万能路由,通过 path 参数将请求 **转发** 到其他接口
+ 对于 [GET] 请求,通过 query 传递参数
+ 对于 [POST] 请求,通过 body 传递参数
+ 对于 [POST] multi-part 请求,建议通过 `/router/{path}` 请求
#### Post Body 请求:
```json5
{
"router": "/sendFriendMessage",
"body": {}
}
```

### 回响

#### 接口名称
```
[GET] /echo
[POST] /echo
```
此方法将请求的 query 或 body 原样返回

> 为保证 server 不按不确定的格式解析传入参数,统一以字符串形式返回
>
> POST 请求返回 Content-Type: text/plain
## 认证与会话

### 认证
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import io.ktor.server.plugins.doublereceive.*
import net.mamoe.mirai.api.http.adapter.http.HttpAdapter
import net.mamoe.mirai.api.http.adapter.http.plugin.Authorization
import net.mamoe.mirai.api.http.adapter.http.plugin.GlobalExceptionHandler
import net.mamoe.mirai.api.http.adapter.http.plugin.HttpForward
import net.mamoe.mirai.api.http.adapter.http.plugin.HttpRouterMonitor
import net.mamoe.mirai.api.http.adapter.internal.serializer.BuiltinJsonSerializer
import net.mamoe.mirai.api.http.context.MahContextHolder
Expand All @@ -34,7 +35,10 @@ fun Application.httpModule(adapter: HttpAdapter) {
}
}

install(ContentNegotiation) { json(json = BuiltinJsonSerializer.buildJson()) }
val jsonSerializer = BuiltinJsonSerializer.buildJson()

install(ContentNegotiation) { json(jsonSerializer) }
install(HttpForward) { jsonElementBodyConvertor(jsonSerializer) }
install(GlobalExceptionHandler) { printTrace = MahContextHolder.debug }
install(Authorization)
if (MahContextHolder.debug) {
Expand All @@ -52,4 +56,5 @@ fun Application.httpModule(adapter: HttpAdapter) {
fileRouter()
commandRouter()
announcementRouter()
commonRouter()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* 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.router

import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement
import net.mamoe.mirai.api.http.adapter.http.plugin.forward

@Serializable
internal data class CommonRouter(
val router: String,
val body: JsonElement?
)

internal fun Application.commonRouter() = routing {

route("/router") {
get("/{pathRouter}") {
val router = call.parameters["pathRouter"] ?: return@get
call.forward(router + "?" + call.request.queryString())
}

get {
val router = call.request.queryParameters["router"] ?: return@get
call.forward(router + "?" + call.request.queryString())
}

post("/{router}") {
call.forward(call.parameters["router"] ?: "")
}

post {
val router = call.receive<CommonRouter>()
call.forward(router.router, router.body)
}
}

route("/echo") {
get {
call.respondText(call.request.queryString())
}

post {
call.respondText(call.receive<String>())
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* 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.router

import framework.testHttpApplication
import io.ktor.client.call.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import net.mamoe.mirai.api.http.adapter.common.StateCode
import net.mamoe.mirai.api.http.adapter.internal.dto.LongListRestfulResult
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class CommonRouterTest {

@Test
fun testGetRouterWithPath() = testHttpApplication {

client.get("/router/botList").also {
assertEquals(HttpStatusCode.OK, it.status)

val body = it.body<LongListRestfulResult>()
assertEquals(StateCode.Success.code, body.code)
assertTrue(body.data.isEmpty())
}
}

@Test
fun testGetRouterWithQuery() = testHttpApplication {
client.get("/router?router=botList").also {
assertEquals(HttpStatusCode.OK, it.status)

val body = it.body<LongListRestfulResult>()
assertEquals(StateCode.Success.code, body.code)
assertTrue(body.data.isEmpty())
}
}

@Test
fun testGetRouterWithPathAndQuery() = testHttpApplication {
client.get("/router/xxx?router=botList").also {
assertEquals(HttpStatusCode.NotFound, it.status)
println(it.bodyAsText())
}

client.get("/router/botList?router=xxx").also {
val body = it.body<LongListRestfulResult>()
assertEquals(StateCode.Success.code, body.code)
assertTrue(body.data.isEmpty())
}
}

@Test
fun testGetRouterPassQuery() = testHttpApplication {
client.get("/router/echo?qq=123").also {
assertEquals(HttpStatusCode.OK, it.status)
assertEquals("qq=123", it.bodyAsText())
}

client.get("/router?router=echo&qq=123").also {
assertEquals(HttpStatusCode.OK, it.status)
assertEquals("router=echo&qq=123", it.bodyAsText())
}

client.get("/router?router=/echo&qq=123").also {
assertEquals(HttpStatusCode.OK, it.status)
assertEquals("router=/echo&qq=123", it.bodyAsText())
}

client.get("/router?router=%2Fecho&qq=123").also {
assertEquals(HttpStatusCode.OK, it.status)
assertEquals("router=%2Fecho&qq=123", it.bodyAsText())
}
}

@Test
fun testPostRouter() = testHttpApplication {
client.post {
url("/router/echo?qq=123")
setBody("hello world")
}.also {
assertEquals(HttpStatusCode.OK, it.status)
assertEquals("hello world", it.bodyAsText())
}
}

@Test
fun testPostRouterWithJson() = testHttpApplication {
client.post("/router") {
contentType(ContentType.Application.Json)
setBody("""{"router": "echo", "body": "hello world"}""")
}.also {
assertEquals(HttpStatusCode.OK, it.status)
assertEquals("\"hello world\"", it.bodyAsText())
}

client.post("/router") {
contentType(ContentType.Application.Json)
setBody("""{"router": "echo", "body": null}""")
}.also {
assertEquals(HttpStatusCode.OK, it.status)
assertEquals("null", it.bodyAsText())
}
}
}

0 comments on commit 9e4ba4e

Please sign in to comment.