refactor: http server, snapshot

This commit is contained in:
lisonge 2024-06-10 17:59:27 +08:00
parent 978552b4b2
commit 59ad7b7355
8 changed files with 74 additions and 32 deletions

View File

@ -21,6 +21,10 @@ data class AppInfo(
val hidden: Boolean,
)
val selfAppInfo by lazy {
app.packageManager.getPackageInfo(app.packageName, 0).toAppInfo()!!
}
/**
* 平均单次调用时间 11ms
*/

View File

@ -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

View File

@ -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<NodeInfo>,
) : 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,
)
}

View File

@ -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,
)
}
}

View File

@ -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)

View File

@ -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,

View File

@ -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) { "<script type='module' src='$SERVER_SCRIPT_URL'></script>" } }
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<ReqId>()
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<ReqId>()
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 ?: "未知")
}
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

View File

@ -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 -> {