Add signer caching to Account model to improve performance

- Introduce `signerCache` using a `WeakReference` and a `Mutex` to safely cache the `NostrSignerInternal` instance.
- Update `getSigner()` to check the cache before retrieving the encrypted key and creating a new signer.
- Add `clearSignerCache()` to explicitly clear the cache on logout.
This commit is contained in:
greenart7c3
2025-12-17 07:35:17 -03:00
parent c255cc3e89
commit 3acbc08f4b
2 changed files with 32 additions and 2 deletions
@@ -363,6 +363,7 @@ object LocalPreferences {
*/
@SuppressLint("ApplySharedPref")
fun updatePrefsForLogout(npub: String, context: Context): Boolean {
accountCache.get(npub)?.clearSignerCache()
accountCache.remove(npub)
val userPrefs = sharedPrefs(context, npub)
userPrefs.edit(commit = true) { clear() }
@@ -24,11 +24,14 @@ import com.vitorpamplona.quartz.nip49PrivKeyEnc.Nip49
import com.vitorpamplona.quartz.nip55AndroidSigner.signString
import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent
import com.vitorpamplona.quartz.nip57Zaps.PrivateZapRequestBuilder
import java.lang.ref.WeakReference
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
@Stable
class Account(
@@ -41,9 +44,30 @@ class Account(
) {
val saveable: AccountLiveData = AccountLiveData(this)
@Volatile
private var signerCache: WeakReference<NostrSignerInternal>? = null
private val signerMutex = Mutex()
private suspend fun getSigner(): NostrSignerInternal {
val privKey = DataStoreAccess.getEncryptedKey(Amber.instance, npub, DataStoreAccess.NOSTR_PRIVKEY)!!
return NostrSignerInternal(KeyPair(privKey.hexToByteArray()))
signerCache?.get()?.let { return it }
return signerMutex.withLock {
signerCache?.get()?.let { return it }
val privKey = DataStoreAccess.getEncryptedKey(
Amber.instance,
npub,
DataStoreAccess.NOSTR_PRIVKEY,
) ?: throw CancellationException("Signer unavailable")
val signer = NostrSignerInternal(
KeyPair(privKey.hexToByteArray()),
)
signerCache = WeakReference(signer)
signer
}
}
suspend fun <T : Event> sign(eventTemplate: EventTemplate<T>): T {
@@ -138,6 +162,11 @@ class Account(
}
}
}
fun clearSignerCache() {
signerCache?.clear()
signerCache = null
}
}
class AccountLiveData(account: Account) : LiveData<AccountState>(AccountState(account))