From 1086f4cf5eaad600e438cdb929d629a69dee73ba Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 27 Jun 2026 21:20:12 +0000 Subject: [PATCH] fix(napplet): unify DataStore cache key to file path, fixing connected-apps crash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit allPolicies() keyed the LargeCache on the filename ("nsp_HASH") while storeFor() keyed it on the coordinate string. Both point at the same .preferences_pb file, so getOrCreate created two live DataStore instances for one file — DataStore's own singleton guard then threw IllegalStateException. Fix: use file.absolutePath as the cache key in both code paths so the second call always returns the already-open DataStore instance instead of creating a new one. Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_013hTFpoExYYLYEGGtXBx6ZT --- .../DataStoreNostrSignerPermissionStore.kt | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/DataStoreNostrSignerPermissionStore.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/DataStoreNostrSignerPermissionStore.kt index 0812466778..fa64ed6378 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/DataStoreNostrSignerPermissionStore.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/DataStoreNostrSignerPermissionStore.kt @@ -50,12 +50,12 @@ class DataStoreNostrSignerPermissionStore( private val cache = LargeCache>() - private fun storeFor(coordinate: String): DataStore = - cache.getOrCreate(coordinate) { - PreferenceDataStoreFactory.create( - produceFile = { File(filesDir, "datastore/nsp_${hash(coordinate)}.preferences_pb") }, - ) + private fun storeFor(coordinate: String): DataStore { + val file = File(filesDir, "datastore/nsp_${hash(coordinate)}.preferences_pb") + return cache.getOrCreate(file.absolutePath) { + PreferenceDataStoreFactory.create(produceFile = { file }) } + } override suspend fun loadPolicy(coordinate: String): AppSignerPolicy? { val raw = storeFor(coordinate).data.first()[KEY_POLICY] ?: return null @@ -107,15 +107,11 @@ class DataStoreNostrSignerPermissionStore( if (!dir.exists()) return emptyMap() val result = mutableMapOf() for (file in dir.listFiles { f -> f.name.startsWith("nsp_") } ?: emptyArray()) { - val coordinate = - file.nameWithoutExtension.let { name -> - // Derive the DataStore by re-opening the file; we stored the coordinate inside. - val ds = - cache.getOrCreate(name) { - PreferenceDataStoreFactory.create(produceFile = { file }) - } - ds.data.first()[KEY_COORDINATE] - } ?: continue + val ds = + cache.getOrCreate(file.absolutePath) { + PreferenceDataStoreFactory.create(produceFile = { file }) + } + val coordinate = ds.data.first()[KEY_COORDINATE] ?: continue val policy = loadPolicy(coordinate) ?: continue result[coordinate] = policy }