From 2e79496c4c6286a2cd4e33fa441be7556d94167d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 14:17:56 +0000 Subject: [PATCH 1/4] Initial plan From 0e6a726fb1cf9c2f2e8606fcdb6b49c8b49685cb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 14:20:02 +0000 Subject: [PATCH 2/4] fix(manager): persist config in device-protected storage for boot startup Co-authored-by: ItosEO <83892149+ItosEO@users.noreply.github.com> --- .../src/main/kotlin/roro/stellar/manager/db/AppDatabase.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/manager/src/main/kotlin/roro/stellar/manager/db/AppDatabase.kt b/manager/src/main/kotlin/roro/stellar/manager/db/AppDatabase.kt index a2bb775..6d22ae0 100644 --- a/manager/src/main/kotlin/roro/stellar/manager/db/AppDatabase.kt +++ b/manager/src/main/kotlin/roro/stellar/manager/db/AppDatabase.kt @@ -15,7 +15,9 @@ abstract class AppDatabase : RoomDatabase() { @Volatile private var instance: AppDatabase? = null fun get(context: Context): AppDatabase = instance ?: synchronized(this) { - instance ?: Room.databaseBuilder(context, AppDatabase::class.java, "stellar.db") + val deviceContext = context.applicationContext.createDeviceProtectedStorageContext() + deviceContext.moveDatabaseFrom(context.applicationContext, "stellar.db") + instance ?: Room.databaseBuilder(deviceContext, AppDatabase::class.java, "stellar.db") .fallbackToDestructiveMigration() .build().also { instance = it } } From 2e610a0835f94002e39029b193b0781c1cdb11f3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 14:20:51 +0000 Subject: [PATCH 3/4] refactor(manager): harden protected-storage database migration Co-authored-by: ItosEO <83892149+ItosEO@users.noreply.github.com> --- .../src/main/kotlin/roro/stellar/manager/db/AppDatabase.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/manager/src/main/kotlin/roro/stellar/manager/db/AppDatabase.kt b/manager/src/main/kotlin/roro/stellar/manager/db/AppDatabase.kt index 6d22ae0..701030e 100644 --- a/manager/src/main/kotlin/roro/stellar/manager/db/AppDatabase.kt +++ b/manager/src/main/kotlin/roro/stellar/manager/db/AppDatabase.kt @@ -16,10 +16,12 @@ abstract class AppDatabase : RoomDatabase() { fun get(context: Context): AppDatabase = instance ?: synchronized(this) { val deviceContext = context.applicationContext.createDeviceProtectedStorageContext() - deviceContext.moveDatabaseFrom(context.applicationContext, "stellar.db") - instance ?: Room.databaseBuilder(deviceContext, AppDatabase::class.java, "stellar.db") + runCatching { deviceContext.moveDatabaseFrom(context.applicationContext, DATABASE_NAME) } + instance ?: Room.databaseBuilder(deviceContext, AppDatabase::class.java, DATABASE_NAME) .fallbackToDestructiveMigration() .build().also { instance = it } } + + private const val DATABASE_NAME = "stellar.db" } } From 7765555e90b8759cce7db35f2763e1a15be90200 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 14:44:44 +0000 Subject: [PATCH 4/4] fix(server): avoid treating failed config load as empty config Co-authored-by: ItosEO <83892149+ItosEO@users.noreply.github.com> --- server/src/main/kotlin/roro/stellar/server/ConfigManager.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/src/main/kotlin/roro/stellar/server/ConfigManager.kt b/server/src/main/kotlin/roro/stellar/server/ConfigManager.kt index 5ff9792..2526588 100644 --- a/server/src/main/kotlin/roro/stellar/server/ConfigManager.kt +++ b/server/src/main/kotlin/roro/stellar/server/ConfigManager.kt @@ -342,7 +342,11 @@ class ConfigManager { fun loadFromManagerWithStatus(): Pair { return try { val reply = callProvider("loadConfig", null) - val json = reply?.getString("configJson") + if (reply == null) { + LOGGER.w("从 manager 加载配置失败: 返回 null,使用默认值并跳过初始化写入") + return Pair(StellarConfig(), false) + } + val json = reply.getString("configJson") if (json != null) { val config = GSON_IN.fromJson(json, StellarConfig::class.java) ?: StellarConfig() Pair(config, true)