This commit is contained in:
2026-07-02 20:00:55 +07:00
parent 785afbca08
commit e631d7ae8d
4 changed files with 22 additions and 31 deletions

View File

@@ -79,6 +79,8 @@ class Nostr {
// Initialize configurations for nostr client
val lmdb = NostrDatabase.lmdb(dbPath)
val gossip = NostrGossip.inMemory()
// Initialize the authenticator
val authenticator = SignerAuthenticator(signer)
val idleTimeout = Duration.parse("5m")
@@ -208,7 +210,7 @@ class Nostr {
if (isSignedByUser(event = event)) {
val pubkeys = event.tags().publicKeys()
// Get mutual contacts
profiles.getMutualContacts(pubkeys)
profiles.syncMutualContacts(pubkeys)
// Emit contact list update
onContactListUpdate(pubkeys)
}

View File

@@ -74,22 +74,13 @@ class ProfileManager(private val nostr: Nostr) {
}
}
suspend fun getMutualContacts(pubkeys: List<PublicKey>) {
suspend fun syncMutualContacts(pubkeys: List<PublicKey>) {
try {
val kind = Kind.fromStd(KindStandard.CONTACT_LIST)
val filter = Filter().kind(kind).authors(pubkeys).limit(pubkeys.size.toULong())
val opts = SubscribeAutoCloseOptions().exitPolicy(ReqExitPolicy.ExitOnEose)
val relays = NostrManager.BOOTSTRAP_RELAYS.map { RelayUrl.parse(it) }
val target = mutableMapOf<RelayUrl, List<Filter>>()
NostrManager.BOOTSTRAP_RELAYS.forEach { relay ->
target[RelayUrl.parse(relay)] = listOf(filter)
}
client?.subscribe(
target = ReqTarget.manual(target),
id = "mutual-contacts",
closeOn = opts,
)
client?.sync(filter, relays)
} catch (e: Exception) {
throw IllegalStateException("Failed to fetch mutual contacts: ${e.message}", e)
}

View File

@@ -134,8 +134,9 @@ class RelayManager(private val nostr: Nostr) {
val kind = Kind.fromStd(KindStandard.INBOX_RELAYS)
val filter = Filter().kind(kind).author(publicKey).limit(1u)
val events = client?.database()?.query(filter)
val event = events?.first() ?: return emptyList()
return nip17ExtractRelayList(events?.toVec()?.firstOrNull() ?: return emptyList())
return nip17ExtractRelayList(event)
} catch (e: Exception) {
throw IllegalStateException("Failed to get msg relays: ${e.message}", e)
}

View File

@@ -11,6 +11,8 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
@@ -159,8 +161,7 @@ class NostrViewModel(private val nostr: Nostr) : BaseViewModel() {
// Wait until the client is ready
nostr.waitUntilInitialized()
val results = nostr.profiles.getAllCacheMetadata()
results.forEach { (pubkey, metadata) ->
nostr.profiles.getAllCacheMetadata().forEach { (pubkey, metadata) ->
// Update the metadata state
updateMetadata(pubkey, Profile(pubkey, metadata))
// Update seenPublicKeys to avoid duplicate requests
@@ -171,25 +172,21 @@ class NostrViewModel(private val nostr: Nostr) : BaseViewModel() {
private fun observeSignerAndCheckRelays() {
viewModelScope.launch {
while (true) {
val currentUser = nostr.signer.getPublicKeyAsync()
// Wait until the client is ready
nostr.waitUntilInitialized()
if (currentUser != null) {
// Get all metadata for the current user
nostr.profiles.getUserMetadata()
// Wait until a signer is explicitly set (which updates publicKeyFlow)
val currentUser = nostr.signer.publicKeyFlow.filterNotNull().first()
// Small delay to ensure all relays are connected
delay(2.seconds)
// Get all metadata for the current user
nostr.profiles.getUserMetadata()
// Check if the relay list is empty
val relays = nostr.relays.getMsgRelays(currentUser)
if (relays.isEmpty()) _appState.update { it.copy(isRelayListEmpty = true) }
// Small delay to ensure all relays are connected
delay(2.seconds)
break
}
delay(500.milliseconds)
}
// Check if the relay list is empty
val relays = nostr.relays.getMsgRelays(currentUser)
if (relays.isEmpty()) _appState.update { it.copy(isRelayListEmpty = true) }
}
}