From aeabc66067d329b0a55d969865a99e009a2f4b21 Mon Sep 17 00:00:00 2001 From: WhiteChi Date: Wed, 20 Dec 2023 18:52:24 +0800 Subject: [PATCH] =?UTF-8?q?`Shamrock`:=20=E5=85=BC=E5=AE=B9=E6=80=A7?= =?UTF-8?q?=E6=AD=A3=E5=8F=8D=E5=90=91HTTP=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/service/DashboardInitializer.kt | 3 +- .../fuqiuluo/qqinterface/servlet/QFavSvc.kt | 8 ++++ .../fuqiuluo/shamrock/remote/api/MainRoute.kt | 43 +++++++++++++++++++ .../remote/service/api/HttpTransmitServlet.kt | 7 ++- .../moe/fuqiuluo/shamrock/tools/KtorServer.kt | 27 +++++++++++- 5 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/QFavSvc.kt diff --git a/app/src/main/java/moe/fuqiuluo/shamrock/ui/service/DashboardInitializer.kt b/app/src/main/java/moe/fuqiuluo/shamrock/ui/service/DashboardInitializer.kt index 3742dd7..ab8d8b4 100644 --- a/app/src/main/java/moe/fuqiuluo/shamrock/ui/service/DashboardInitializer.kt +++ b/app/src/main/java/moe/fuqiuluo/shamrock/ui/service/DashboardInitializer.kt @@ -8,6 +8,7 @@ import android.os.Bundle import androidx.core.content.ContextCompat.startActivity import io.ktor.client.request.get import io.ktor.client.request.header +import io.ktor.client.request.parameter import io.ktor.client.request.url import io.ktor.client.statement.bodyAsText import io.ktor.http.HttpStatusCode @@ -58,7 +59,7 @@ object DashboardInitializer { url("http://127.0.0.1:$servicePort/get_account_info") val token = ShamrockConfig.getToken(context) if (token.isNotBlank()) { - header("Authorization", "Bearer $token") + parameter("token", token) } }.let { if (it.status == HttpStatusCode.OK) { diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/QFavSvc.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/QFavSvc.kt new file mode 100644 index 0000000..5d71101 --- /dev/null +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/QFavSvc.kt @@ -0,0 +1,8 @@ +package moe.fuqiuluo.qqinterface.servlet + +/** + * QQ收藏相关接口 + */ +internal object QFavSvc: BaseSvc() { + +} \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/MainRoute.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/MainRoute.kt index 0e0a3c4..039ade9 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/MainRoute.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/MainRoute.kt @@ -1,6 +1,7 @@ package moe.fuqiuluo.shamrock.remote.api import io.ktor.http.ContentType +import io.ktor.server.application.ApplicationCall import io.ktor.server.application.call import io.ktor.server.request.httpVersion import io.ktor.server.response.respondText @@ -8,8 +9,12 @@ import io.ktor.server.routing.Routing import io.ktor.server.routing.get import io.ktor.server.routing.post import io.ktor.server.routing.route +import io.ktor.util.pipeline.PipelineContext import kotlinx.serialization.Contextual import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.jsonObject import moe.fuqiuluo.shamrock.remote.HTTPServer import moe.fuqiuluo.shamrock.remote.action.ActionManager import moe.fuqiuluo.shamrock.remote.action.ActionSession @@ -18,12 +23,16 @@ import moe.fuqiuluo.shamrock.remote.entries.EmptyObject import moe.fuqiuluo.shamrock.remote.entries.IndexData import moe.fuqiuluo.shamrock.remote.entries.Status import moe.fuqiuluo.shamrock.tools.EmptyJsonObject +import moe.fuqiuluo.shamrock.tools.asJsonObjectOrNull +import moe.fuqiuluo.shamrock.tools.asString import moe.fuqiuluo.shamrock.tools.fetchOrNull import moe.fuqiuluo.shamrock.tools.fetchOrThrow import moe.fuqiuluo.shamrock.tools.fetchPostJsonElement +import moe.fuqiuluo.shamrock.tools.fetchPostJsonElementOrNull import moe.fuqiuluo.shamrock.tools.fetchPostJsonObject import moe.fuqiuluo.shamrock.tools.fetchPostJsonObjectOrNull import moe.fuqiuluo.shamrock.tools.isJsonArray +import moe.fuqiuluo.shamrock.tools.isJsonData import moe.fuqiuluo.shamrock.tools.isJsonObject import moe.fuqiuluo.shamrock.tools.isJsonString import moe.fuqiuluo.shamrock.tools.json @@ -39,6 +48,31 @@ data class OldApiResult( val data: T? = null ) +suspend fun PipelineContext.handleAsJsonObject(data: JsonObject) { + val action = data["action"].asString + val echo = data["echo"]!! + call.attributes.put(ECHO_KEY, echo) + + val params = data["params"].asJsonObjectOrNull ?: EmptyJsonObject + + val handler = ActionManager[action] + if (handler == null) { + respond(false, Status.UnsupportedAction, EmptyObject, "不支持的Action", echo = echo) + } else { + call.respondText(handler.handle(ActionSession(params, echo)), ContentType.Application.Json) + } +} + +suspend fun PipelineContext.handleAsJsonArray(data: JsonArray) { + data.forEach { + when (it) { + is JsonArray -> handleAsJsonArray(it) + is JsonObject -> handleAsJsonObject(it) + else -> handleAsJsonObject(it.jsonObject) + } + } +} + fun Routing.echoVersion() { route("/") { get { @@ -49,6 +83,15 @@ fun Routing.echoVersion() { ) } post { + fetchPostJsonElementOrNull()?.let { + if (it is JsonArray) { + handleAsJsonArray(it) + return@post + } else if (it is JsonObject) { + handleAsJsonObject(it) + return@post + } + } val action = fetchOrThrow("action") val echo = if (isJsonObject("echo") || isJsonArray("echo")) { fetchPostJsonElement("echo") diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/HttpTransmitServlet.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/HttpTransmitServlet.kt index 3a277ea..7652263 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/HttpTransmitServlet.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/HttpTransmitServlet.kt @@ -30,7 +30,7 @@ internal abstract class HttpTransmitServlet : BaseTransmitServlet { if (!allowTransmit()) return null try { if (address.startsWith("http://") || address.startsWith("https://")) { - return GlobalClient.post(address) { + val response = GlobalClient.post(address) { contentType(ContentType.Application.Json) setBody(body) @@ -44,6 +44,11 @@ internal abstract class HttpTransmitServlet : BaseTransmitServlet { header("X-Client-Role", "Universal") header("Sec-WebSocket-Protocol", "11.Shamrock") } + return if (response.status.value == 204) { + null + } else { + response + } } else { LogCenter.log("HTTP推送地址错误: ${address}。", Level.ERROR) } diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/tools/KtorServer.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/tools/KtorServer.kt index 625ef4c..51099de 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/tools/KtorServer.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/tools/KtorServer.kt @@ -37,6 +37,8 @@ annotation class ShamrockDsl private val keyIsJson = AttributeKey("isJson") private val keyJsonObject = AttributeKey("paramsJson") +private val keyJsonArray = AttributeKey("paramsJsonArray") +private val keyJsonElement = AttributeKey("paramsJsonElement") private val keyParts = AttributeKey("paramsParts") suspend fun ApplicationCall.fetch(key: String): String { @@ -167,7 +169,9 @@ suspend fun PipelineContext.fetchPostOrThrow(key: String) } fun PipelineContext.isJsonData(): Boolean { - return ContentType.Application.Json == call.request.contentType() || (keyIsJson in call.attributes && call.attributes[keyIsJson]) + return ContentType.Application.Json == call.request.contentType() + || (keyIsJson in call.attributes && call.attributes[keyIsJson]) + || (keyJsonElement in call.attributes) } suspend fun PipelineContext.isJsonString(key: String): Boolean { @@ -245,12 +249,33 @@ suspend fun PipelineContext.fetchPostJsonObjectOrNull(key call.attributes[keyJsonObject] } else { Json.parseToJsonElement(call.receiveText()).jsonObject.also { + call.attributes.put(keyIsJson, true) call.attributes.put(keyJsonObject, it) } } return data[key].asJsonObjectOrNull } +suspend fun PipelineContext.fetchPostJsonElementOrNull(): JsonElement? { + return runCatching { + if (call.attributes.contains(keyJsonObject)) { + call.attributes[keyJsonObject] + } else if (call.attributes.contains(keyJsonArray)) { + call.attributes[keyJsonArray] + } else if (call.attributes.contains(keyJsonElement)) { + call.attributes[keyJsonElement] + } else { + Json.parseToJsonElement(call.receiveText()).also { + call.attributes.put(keyJsonElement, it) + if (it is JsonObject) { + call.attributes.put(keyJsonObject, it) + } else if (it is JsonArray) { + call.attributes.put(keyJsonArray, it) + } + } + } + }.getOrNull() +} suspend fun PipelineContext.fetchPostJsonArray(key: String): JsonArray { val data = if (call.attributes.contains(keyJsonObject)) {