From 08374fed49c3abc46539775ed0c7a89f1559bffd Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Tue, 19 May 2026 08:26:50 +0700 Subject: [PATCH] load all cache metadata on startup --- .../commonMain/kotlin/su/reya/coop/Nostr.kt | 52 +++++++++++++++++-- .../kotlin/su/reya/coop/NostrViewModel.kt | 27 ++++++---- 2 files changed, 66 insertions(+), 13 deletions(-) diff --git a/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt b/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt index 20c7e6d..ad93f65 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt @@ -278,6 +278,7 @@ class Nostr { when (val message = notification.message.asEnum()) { is RelayMessageEnum.EventMsg -> { val event = message.event + val id = message.subscriptionId // Prevent processing duplicate events if (processedEvent.contains(event.id())) continue @@ -299,9 +300,18 @@ class Nostr { } if (event.kind().asStd()?.equals(KindStandard.INBOX_RELAYS) == true) { + // Get all gift wrap events for current user if (isSignedByUser(event = event)) { getUserMessages(msgRelayList = event) } + + // Connect to all msg relays for the currently active chat room + if (id.startsWith("room-")) { + launch { + chatRoomAuth(event) + } + } + // Cache the relay list for future use setMsgRelay(pubkey = event.author(), event = event) } @@ -525,6 +535,23 @@ class Nostr { setSigner(keys) } + suspend fun getAllCacheMetadata(): Map { + try { + val filter = Filter().kind(Kind.fromStd(KindStandard.METADATA)).limit(200u) + val events = client?.database()?.query(filter) + val results = mutableMapOf() + + events?.toVec()?.forEach { event -> + val metadata = Metadata.fromJson(event.content()) + results[event.author()] = metadata + } + + return results + } catch (e: Exception) { + throw IllegalStateException("Failed to get cache metadata: ${e.message}", e) + } + } + suspend fun fetchMetadataBatch(keys: List) { try { val limit = keys.size.toULong() * 4u; @@ -611,7 +638,7 @@ class Nostr { } } - suspend fun chatRoomConnect(members: List) { + suspend fun chatRoomConnect(id: Long, members: List) { try { members.forEach { member -> val kind = Kind.fromStd(KindStandard.INBOX_RELAYS) @@ -620,7 +647,8 @@ class Nostr { client?.subscribe( target = ReqTarget.auto(listOf(filter)), - closeOn = opts + closeOn = opts, + id = "room-${id}" ) } } catch (e: Exception) { @@ -628,6 +656,18 @@ class Nostr { } } + suspend fun chatRoomAuth(event: Event) { + try { + val urls = nip17ExtractRelayList(event); + for (url in urls) { + client?.addRelay(url) + client?.connectRelay(url) + } + } catch (e: Exception) { + throw IllegalStateException("Failed to authenticate chat room: ${e.message}", e) + } + } + suspend fun sendMessage( to: List, content: String, @@ -694,9 +734,13 @@ class Nostr { ) if (output != null) { + // Keep track of sent events sentEvents[output.id] = emptyList() - if (rumor.id() != null) { - rumorMap[rumor.id()!!] = output.id + if (rumor.id() != null) rumorMap[rumor.id()!!] = output.id + + // Collect failed outputs + output.failed.forEach { (relayUrl, reason) -> + println("Failed to send event to relay $relayUrl: $reason") } } } diff --git a/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt b/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt index a680e41..036a523 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt @@ -63,6 +63,7 @@ class NostrViewModel( init { startMetadataBatchProcessor() + getCacheMetadata() } override fun onCleared() { @@ -78,10 +79,7 @@ class NostrViewModel( private fun showError(message: String) { viewModelScope.launch { _errorEvents.send(message) - - if (isCreating.value) { - _isCreating.value = false - } + if (isCreating.value) _isCreating.value = false } } @@ -116,6 +114,17 @@ class NostrViewModel( } } + private fun getCacheMetadata() { + viewModelScope.launch { + val results = nostr.getAllCacheMetadata() + results.forEach { (pubkey, metadata) -> + println("Cache metadata for pubkey $pubkey: $metadata") + updateMetadata(pubkey, metadata) + seenPublicKeys.add(pubkey) + } + } + } + private fun requestMetadata(pubkey: PublicKey) { if (seenPublicKeys.add(pubkey)) { viewModelScope.launch { @@ -124,6 +133,10 @@ class NostrViewModel( } } + private fun updateMetadata(pubkey: PublicKey, metadata: Metadata) { + _metadataStore.getOrPut(pubkey) { MutableStateFlow(null) }.value = metadata + } + fun getMetadata(pubkey: PublicKey): StateFlow { val flow = _metadataStore.getOrPut(pubkey) { MutableStateFlow(null) } if (flow.value == null) { @@ -132,10 +145,6 @@ class NostrViewModel( return flow.asStateFlow() } - private fun updateMetadata(pubkey: PublicKey, metadata: Metadata) { - _metadataStore.getOrPut(pubkey) { MutableStateFlow(null) }.value = metadata - } - suspend fun login() { try { getUserSecret() @@ -355,7 +364,7 @@ class NostrViewModel( val room = getChatRoom(roomId) val members = room.members - nostr.chatRoomConnect(members.toList()) + nostr.chatRoomConnect(roomId, members.toList()) } catch (e: Exception) { showError("Error: ${e.message}") }