fix(napplet): unify DataStore cache key to file path, fixing connected-apps crash

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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hTFpoExYYLYEGGtXBx6ZT
This commit is contained in:
Claude
2026-06-27 22:58:53 +00:00
parent 94ac370379
commit 1086f4cf5e
@@ -50,12 +50,12 @@ class DataStoreNostrSignerPermissionStore(
private val cache = LargeCache<String, DataStore<Preferences>>()
private fun storeFor(coordinate: String): DataStore<Preferences> =
cache.getOrCreate(coordinate) {
PreferenceDataStoreFactory.create(
produceFile = { File(filesDir, "datastore/nsp_${hash(coordinate)}.preferences_pb") },
)
private fun storeFor(coordinate: String): DataStore<Preferences> {
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<String, AppSignerPolicy>()
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
}