From 59ad7b73551b3926e0a0c8aa89734753ad272205 Mon Sep 17 00:00:00 2001 From: lisonge Date: Mon, 10 Jun 2024 17:59:27 +0800 Subject: [PATCH] refactor: http server, snapshot --- .../main/kotlin/li/songe/gkd/data/AppInfo.kt | 4 ++ .../kotlin/li/songe/gkd/data/BaseSnapshot.kt | 2 +- .../li/songe/gkd/data/ComplexSnapshot.kt | 32 +++++------ .../kotlin/li/songe/gkd/data/DeviceInfo.kt | 5 -- .../main/kotlin/li/songe/gkd/data/RpcError.kt | 1 + .../main/kotlin/li/songe/gkd/data/Snapshot.kt | 2 +- .../kotlin/li/songe/gkd/debug/HttpService.kt | 57 ++++++++++++++++--- .../li/songe/gkd/debug/KtorErrorPlugin.kt | 3 +- 8 files changed, 74 insertions(+), 32 deletions(-) diff --git a/app/src/main/kotlin/li/songe/gkd/data/AppInfo.kt b/app/src/main/kotlin/li/songe/gkd/data/AppInfo.kt index c62d546..e5aa959 100644 --- a/app/src/main/kotlin/li/songe/gkd/data/AppInfo.kt +++ b/app/src/main/kotlin/li/songe/gkd/data/AppInfo.kt @@ -21,6 +21,10 @@ data class AppInfo( val hidden: Boolean, ) +val selfAppInfo by lazy { + app.packageManager.getPackageInfo(app.packageName, 0).toAppInfo()!! +} + /** * 平均单次调用时间 11ms */ diff --git a/app/src/main/kotlin/li/songe/gkd/data/BaseSnapshot.kt b/app/src/main/kotlin/li/songe/gkd/data/BaseSnapshot.kt index df1cf94..9bd1a41 100644 --- a/app/src/main/kotlin/li/songe/gkd/data/BaseSnapshot.kt +++ b/app/src/main/kotlin/li/songe/gkd/data/BaseSnapshot.kt @@ -6,7 +6,7 @@ interface BaseSnapshot { val appId: String? val activityId: String? val appName: String? - val appVersionCode: Int? + val appVersionCode: Long? val appVersionName: String? val screenHeight: Int diff --git a/app/src/main/kotlin/li/songe/gkd/data/ComplexSnapshot.kt b/app/src/main/kotlin/li/songe/gkd/data/ComplexSnapshot.kt index f5ee219..db3c41e 100644 --- a/app/src/main/kotlin/li/songe/gkd/data/ComplexSnapshot.kt +++ b/app/src/main/kotlin/li/songe/gkd/data/ComplexSnapshot.kt @@ -1,9 +1,8 @@ package li.songe.gkd.data -import com.blankj.utilcode.util.AppUtils import com.blankj.utilcode.util.ScreenUtils import kotlinx.serialization.Serializable -import li.songe.gkd.BuildConfig +import li.songe.gkd.app import li.songe.gkd.service.GkdAbService import li.songe.gkd.service.getAndUpdateCurrentRules import li.songe.gkd.service.safeActiveWindow @@ -14,18 +13,22 @@ data class ComplexSnapshot( override val appId: String?, override val activityId: String?, - override val appName: String?, - override val appVersionCode: Int?, - override val appVersionName: String?, override val screenHeight: Int, override val screenWidth: Int, override val isLandscape: Boolean, - val gkdVersionCode: Int = BuildConfig.VERSION_CODE, - val gkdVersionName: String = BuildConfig.VERSION_NAME, + val appInfo: AppInfo? = appId?.let { app.packageManager.getPackageInfo(appId, 0)?.toAppInfo() }, + val gkdAppInfo: AppInfo? = selfAppInfo, + val device: DeviceInfo = DeviceInfo.instance, + + @Deprecated("use appInfo") + override val appName: String? = appInfo?.name, + @Deprecated("use appInfo") + override val appVersionCode: Long? = appInfo?.versionCode, + @Deprecated("use appInfo") + override val appVersionName: String? = appInfo?.versionName, - val device: DeviceInfo, val nodes: List, ) : BaseSnapshot @@ -34,21 +37,17 @@ fun createComplexSnapshot(): ComplexSnapshot { val currentAbNode = GkdAbService.service?.safeActiveWindow val appId = currentAbNode?.packageName?.toString() val currentActivityId = getAndUpdateCurrentRules().topActivity.activityId - val appInfo = if (appId == null) null else AppUtils.getAppInfo(appId) return ComplexSnapshot( id = System.currentTimeMillis(), appId = appId, activityId = currentActivityId, - appName = appInfo?.name, - appVersionCode = appInfo?.versionCode, - appVersionName = appInfo?.versionName, screenHeight = ScreenUtils.getScreenHeight(), screenWidth = ScreenUtils.getScreenWidth(), isLandscape = ScreenUtils.isLandscape(), - device = DeviceInfo.instance, + nodes = NodeInfo.info2nodeList(currentAbNode) ) } @@ -59,13 +58,14 @@ fun ComplexSnapshot.toSnapshot(): Snapshot { appId = appId, activityId = activityId, - appName = appName, - appVersionCode = appVersionCode, - appVersionName = appVersionName, screenHeight = screenHeight, screenWidth = screenWidth, isLandscape = isLandscape, + + appName = appInfo?.name, + appVersionCode = appInfo?.versionCode, + appVersionName = appInfo?.versionName, ) } diff --git a/app/src/main/kotlin/li/songe/gkd/data/DeviceInfo.kt b/app/src/main/kotlin/li/songe/gkd/data/DeviceInfo.kt index b11fe91..a7d3156 100644 --- a/app/src/main/kotlin/li/songe/gkd/data/DeviceInfo.kt +++ b/app/src/main/kotlin/li/songe/gkd/data/DeviceInfo.kt @@ -2,7 +2,6 @@ package li.songe.gkd.data import android.os.Build import kotlinx.serialization.Serializable -import li.songe.gkd.BuildConfig @Serializable data class DeviceInfo( @@ -12,8 +11,6 @@ data class DeviceInfo( val brand: String, val sdkInt: Int, val release: String, - val gkdVersionCode: Int, - val gkdVersionName: String ) { companion object { val instance by lazy { @@ -24,8 +21,6 @@ data class DeviceInfo( brand = Build.BRAND, sdkInt = Build.VERSION.SDK_INT, release = Build.VERSION.RELEASE, - gkdVersionCode = BuildConfig.VERSION_CODE, - gkdVersionName = BuildConfig.VERSION_NAME, ) } } diff --git a/app/src/main/kotlin/li/songe/gkd/data/RpcError.kt b/app/src/main/kotlin/li/songe/gkd/data/RpcError.kt index 798ceaf..459304b 100644 --- a/app/src/main/kotlin/li/songe/gkd/data/RpcError.kt +++ b/app/src/main/kotlin/li/songe/gkd/data/RpcError.kt @@ -7,4 +7,5 @@ import kotlinx.serialization.Serializable data class RpcError( override val message: String, @SerialName("__error") val error: Boolean = true, + val unknown: Boolean = false, ) : Exception(message) diff --git a/app/src/main/kotlin/li/songe/gkd/data/Snapshot.kt b/app/src/main/kotlin/li/songe/gkd/data/Snapshot.kt index 724a736..040b448 100644 --- a/app/src/main/kotlin/li/songe/gkd/data/Snapshot.kt +++ b/app/src/main/kotlin/li/songe/gkd/data/Snapshot.kt @@ -25,7 +25,7 @@ data class Snapshot( @ColumnInfo(name = "app_id") override val appId: String?, @ColumnInfo(name = "activity_id") override val activityId: String?, @ColumnInfo(name = "app_name") override val appName: String?, - @ColumnInfo(name = "app_version_code") override val appVersionCode: Int?, + @ColumnInfo(name = "app_version_code") override val appVersionCode: Long?, @ColumnInfo(name = "app_version_name") override val appVersionName: String?, @ColumnInfo(name = "screen_height") override val screenHeight: Int, diff --git a/app/src/main/kotlin/li/songe/gkd/debug/HttpService.kt b/app/src/main/kotlin/li/songe/gkd/debug/HttpService.kt index e6a39ea..93d20b5 100644 --- a/app/src/main/kotlin/li/songe/gkd/debug/HttpService.kt +++ b/app/src/main/kotlin/li/songe/gkd/debug/HttpService.kt @@ -30,12 +30,14 @@ import kotlinx.serialization.Serializable import li.songe.gkd.app import li.songe.gkd.appScope import li.songe.gkd.composition.CompositionService +import li.songe.gkd.data.AppInfo import li.songe.gkd.data.DeviceInfo import li.songe.gkd.data.GkdAction import li.songe.gkd.data.RawSubscription import li.songe.gkd.data.RpcError import li.songe.gkd.data.SubsItem import li.songe.gkd.data.deleteSubscription +import li.songe.gkd.data.selfAppInfo import li.songe.gkd.db.DbSet import li.songe.gkd.debug.SnapshotExt.captureSnapshot import li.songe.gkd.notif.createNotif @@ -74,7 +76,12 @@ class HttpService : CompositionService({ routing { get("/") { call.respondText(ContentType.Text.Html) { "" } } route("/api") { + // Deprecated get("/device") { call.respond(DeviceInfo.instance) } + + post("/getServerInfo") { call.respond(ServerInfo()) } + + // Deprecated get("/snapshot") { val id = call.request.queryParameters["id"]?.toLongOrNull() ?: throw RpcError("miss id") @@ -84,6 +91,16 @@ class HttpService : CompositionService({ } call.respondFile(fp) } + post("/getSnapshot") { + val data = call.receive() + val fp = File(SnapshotExt.getSnapshotPath(data.id)) + if (!fp.exists()) { + throw RpcError("对应快照不存在") + } + call.respond(fp) + } + + // Deprecated get("/screenshot") { val id = call.request.queryParameters["id"]?.toLongOrNull() ?: throw RpcError("miss id") @@ -93,12 +110,31 @@ class HttpService : CompositionService({ } call.respondFile(fp) } + post("/getScreenshot") { + val data = call.receive() + val fp = File(SnapshotExt.getScreenshotPath(data.id)) + if (!fp.exists()) { + throw RpcError("对应截图不存在") + } + call.respondFile(fp) + } + + // Deprecated get("/captureSnapshot") { call.respond(captureSnapshot()) } + post("/captureSnapshot") { + call.respond(captureSnapshot()) + } + + // Deprecated get("/snapshots") { call.respond(DbSet.snapshotDao.query().first()) } + post("/getSnapshots") { + call.respond(DbSet.snapshotDao.query().first()) + } + post("/updateSubscription") { val subscription = RawSubscription.parse(call.receiveText(), json5 = false) @@ -108,13 +144,9 @@ class HttpService : CompositionService({ version = 0, author = "@gkd-kit/inspect" ) - try { - updateSubscription(subscription) - DbSet.subsItemDao.insert((subsItemsFlow.value.find { s -> s.id == httpSubsItem.id } - ?: httpSubsItem).copy(mtime = System.currentTimeMillis())) - } catch (e: Exception) { - throw RpcError(e.message ?: "未知") - } + updateSubscription(subscription) + DbSet.subsItemDao.insert((subsItemsFlow.value.find { s -> s.id == httpSubsItem.id } + ?: httpSubsItem).copy(mtime = System.currentTimeMillis())) call.respond(RpcOk()) } post("/execSelector") { @@ -190,6 +222,17 @@ data class RpcOk( val message: String? = null, ) +@Serializable +data class ReqId( + val id: Long, +) + +@Serializable +data class ServerInfo( + val device: DeviceInfo = DeviceInfo.instance, + val gkdAppInfo: AppInfo = selfAppInfo +) + fun clearHttpSubs() { // 如果 app 被直接在任务列表划掉, HTTP订阅会没有清除, 所以在后续的第一次启动时清除 if (HttpService.isRunning.value) return diff --git a/app/src/main/kotlin/li/songe/gkd/debug/KtorErrorPlugin.kt b/app/src/main/kotlin/li/songe/gkd/debug/KtorErrorPlugin.kt index ff541c6..4a244f9 100644 --- a/app/src/main/kotlin/li/songe/gkd/debug/KtorErrorPlugin.kt +++ b/app/src/main/kotlin/li/songe/gkd/debug/KtorErrorPlugin.kt @@ -2,7 +2,6 @@ package li.songe.gkd.debug import android.util.Log import com.blankj.utilcode.util.LogUtils -import io.ktor.http.HttpStatusCode import io.ktor.server.application.createApplicationPlugin import io.ktor.server.application.hooks.CallFailed import io.ktor.server.plugins.origin @@ -29,7 +28,7 @@ val KtorErrorPlugin = createApplicationPlugin(name = "KtorErrorPlugin") { // 未知错误 LogUtils.d(call.request.uri, cause.message) cause.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, cause) + call.respond(RpcError(message = cause.message ?: "unknown error", unknown = true)) } else -> {