From bbb9d185006c568d1aefafc6be197015f4fb6f3a Mon Sep 17 00:00:00 2001 From: Kgothatso Ngako Date: Tue, 5 May 2026 13:37:38 +0200 Subject: [PATCH] Improve sync --- .../1.json | 12 +- .../compose/database/dao/NostrDao.kt | 383 +++++------------- .../model/NegentropySynchronizeRequest.kt | 15 +- .../ui/view/model/FeedListViewModel.kt | 4 + .../ui/view/model/FollowersListViewModel.kt | 4 + .../ui/view/model/FollowingListViewModel.kt | 4 + .../ui/view/model/InReplyToViewModel.kt | 4 + .../ui/view/model/NavigationViewModel.kt | 5 +- 8 files changed, 142 insertions(+), 289 deletions(-) diff --git a/composeApp/schemas/ac.cord.auxiliary.compose.database.AuxDatabase/1.json b/composeApp/schemas/ac.cord.auxiliary.compose.database.AuxDatabase/1.json index a875ce1f..6fea3997 100644 --- a/composeApp/schemas/ac.cord.auxiliary.compose.database.AuxDatabase/1.json +++ b/composeApp/schemas/ac.cord.auxiliary.compose.database.AuxDatabase/1.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 1, - "identityHash": "5df12f022a01cc28ca4f7e06383826a4", + "identityHash": "e3fd82a42262f8b5acb481175a99a3e0", "entities": [ { "tableName": "BroadcastNostrEventReceipt", @@ -475,7 +475,7 @@ }, { "tableName": "NegentropySynchronizeRequest", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `purpose` TEXT NOT NULL, `status` TEXT NOT NULL, `relayURL` TEXT NOT NULL, `isRecommendedRelay` INTEGER NOT NULL, `level` INTEGER NOT NULL, `synchronizationFilter` TEXT NOT NULL, `nostrEventId` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `uuid` TEXT NOT NULL, `purpose` TEXT NOT NULL, `status` TEXT NOT NULL, `relayURL` TEXT NOT NULL, `isRecommendedRelay` INTEGER NOT NULL, `level` INTEGER NOT NULL, `synchronizationFilter` TEXT NOT NULL, `nostrEventId` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { "fieldPath": "id", @@ -483,6 +483,12 @@ "affinity": "TEXT", "notNull": true }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, { "fieldPath": "purpose", "columnName": "purpose", @@ -2048,7 +2054,7 @@ ], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5df12f022a01cc28ca4f7e06383826a4')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e3fd82a42262f8b5acb481175a99a3e0')" ] } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/dao/NostrDao.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/dao/NostrDao.kt index 69b5c2eb..88aa7329 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/dao/NostrDao.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/dao/NostrDao.kt @@ -5,6 +5,7 @@ import ac.cord.auxiliary.compose.database.GENESIS_AT import ac.cord.auxiliary.compose.database.model.BroadcastNostrEventRequest import ac.cord.auxiliary.compose.database.model.Connection import ac.cord.auxiliary.compose.database.model.Mention +import ac.cord.auxiliary.compose.database.model.NegentropySynchronizeRequest import ac.cord.auxiliary.compose.database.model.NostrEvent import ac.cord.auxiliary.compose.database.model.NostrEventRelay import ac.cord.auxiliary.compose.database.model.Post @@ -12,6 +13,7 @@ import ac.cord.auxiliary.compose.database.model.Profile import ac.cord.auxiliary.compose.database.model.SynchronizeNostrEventRequest import ac.cord.auxiliary.compose.database.model.UnsignedNostrEvent import ac.cord.auxiliary.compose.database.model.types.SynchronizationFilter +import ac.cord.auxiliary.compose.network.serialization.encodeToJsonString import ac.cord.auxiliary.compose.nostr.Relays import androidx.room3.Dao import androidx.room3.Transaction @@ -24,6 +26,7 @@ import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import com.vitorpamplona.quartz.nip18Reposts.quotes.QAddressableTag import com.vitorpamplona.quartz.nip18Reposts.quotes.QEventTag import com.vitorpamplona.quartz.nip18Reposts.quotes.firstTaggedQuote +import kotlin.math.ceil import kotlin.time.Clock @Dao @@ -83,6 +86,7 @@ abstract class NostrDao( indexNostrEvent( nostrEvent = nostrEvent, + relayURL = relayURLs.first(), synchronizationRelayURLs = relayURLs, level = 0 ) @@ -139,6 +143,7 @@ abstract class NostrDao( logger.i("Index Nostr Event: ${nostrEvent.id}") indexNostrEvent( nostrEvent = nostrEvent, + relayURL = relayURL, synchronizationRelayURLs = synchronizationRelayURLs, level = level ) @@ -146,13 +151,12 @@ abstract class NostrDao( private suspend fun indexNostrEvent( nostrEvent: NostrEvent, + relayURL: String, synchronizationRelayURLs: List, level: Int ) { - val synchronizationFilters = mutableSetOf() // Might want to use a RelayURL -> SynchronizationFilters hashMap... - - val profilePublicKeysToSync = mutableSetOf() - val eventIdsToSync = mutableSetOf() + val profilePublicKeysToSync = mutableMapOf>() + val eventIdsToSync = mutableMapOf>() if (nostrEvent.unsignedNostrEventId == null) { // Find or create profile with the pubKey... if not found submit a sync request... @@ -166,137 +170,22 @@ abstract class NostrDao( nostrEventId = nostrEvent.id, // Will get overwriting by sync, ) database.profileDao().insertPlaceholderProfile(placeHolderProfile) - -// database.synchronizeNostrEventRequestDao().insert( -// synchronizationRelayURLs.take(1).map { synchronizationRelayURL -> // TODO: Take all relayURLS instead of 1 -// SynchronizeNostrEventRequest( -// purpose = "synchronization", -// synchronizationFilters = arrayOf( -// SynchronizationFilter( -// authors = arrayOf(nostrEvent.pubKey), -// kinds = profileEventKinds -// ) -// ), -// relayURL = synchronizationRelayURL -// ) -// } -// ) -// synchronizationFilters.add( -// SynchronizationFilter( -// authors = arrayOf(nostrEvent.pubKey), -// kinds = profileEventKinds -// ) -// ) - profilePublicKeysToSync.add(nostrEvent.pubKey) + if (profilePublicKeysToSync[relayURL] == null) { + profilePublicKeysToSync[relayURL] = mutableSetOf() + } + profilePublicKeysToSync[relayURL]?.add(nostrEvent.pubKey) } else if (profile.createdAt == GENESIS_AT && level == 0) { logger.i("This is a placeholder profile... that might need to get synced...: $profile") - profilePublicKeysToSync.add(nostrEvent.pubKey) + if (profilePublicKeysToSync[relayURL] == null) { + profilePublicKeysToSync[relayURL] = mutableSetOf() + } + profilePublicKeysToSync[relayURL]?.add(nostrEvent.pubKey) } } else { logger.w("We somehow have an unsignedNostrEvent: $nostrEvent") } // Sync tagged events and authors... -// nostrEvent.tags.firstTaggedQuote()?.let { taggedQuote -> -// when (taggedQuote) { -// is QEventTag -> { -// Triple( -// taggedQuote.eventId, -// taggedQuote.author, -// taggedQuote.relay, -// ) -// } -// is QAddressableTag -> { -// Triple( -// taggedQuote.address.dTag, -// taggedQuote.address.pubKeyHex, -// taggedQuote.relay, -// ) -// } -// else -> null -// }?.let { quotedEventData -> -// val quotedNostrEvent = database.nostrEventDao().getNostrEventById(quotedEventData.first) -// -// if (quotedNostrEvent == null) { -//// val quotedPost = database.postDao().getPostById(quotedEventData.first) -// -//// if (quotedPost == null) { -//// // Persist PlaceHolder and sync -//// database.postDao().insert( -//// Post( -//// id = quotedEventData.first, -//// createdAt = GENESIS_AT, -//// nostrEventId = nostrEvent.id, // Will get overwriting by sync handled by tagged events... -//// content = "sync required", -//// profilePublicKey = nostrEvent.pubKey // Will get overwriting by sync handled by tagged events... -//// ) -//// ) -//// } -//// -//// quotedEventData.second?.let { authorPubkey -> -//// val repostedPostProfile = database.profileDao().getProfileByPublicKey(authorPubkey) -//// -//// if (repostedPostProfile == null) { -//// // Persist PlaceHolder and sync -//// database.profileDao().insertPlaceholderProfile( -//// Profile( -//// publicKey = authorPubkey, -//// createdAt = GENESIS_AT, -//// nostrEventId = nostrEvent.id, // Will get overwriting by sync handled by tagged events... -//// ) -//// ) -//// profilePublicKeysToSync.add( -//// authorPubkey -//// ) -//// } else if (repostedPostProfile.createdAt == GENESIS_AT && level == 0) { -//// logger.i("${level} This is a placeholder profile... that might need to get synced...: $repostedPostProfile") -//// profilePublicKeysToSync.add(authorPubkey) -//// } -//// } -//// -//// database.quotedPostDao() -// -// val recommendRelayUrl = quotedEventData.third?.url -// -// val synchronizeNostrEventRequests = if (recommendRelayUrl != null) { -// eventIdsToSync.add(quotedEventData.first) -// -// listOf( -// SynchronizeNostrEventRequest( -// purpose = "synchronization", -// synchronizationFilters = arrayOf( -// SynchronizationFilter( -// ids = arrayOf(quotedEventData.first) -// ) -// ), -// relayURL = recommendRelayUrl, -// isRecommendedRelay = true, -// level = level + 1 -// ) -// ) -// } else { -// eventIdsToSync.add(quotedEventData.first) -// synchronizationRelayURLs.map { synchronizationRelayURL -> -// SynchronizeNostrEventRequest( -// purpose = "synchronization", -// synchronizationFilters = arrayOf( -// SynchronizationFilter( -// ids = arrayOf(quotedEventData.first) -// ) -// ), -// relayURL = synchronizationRelayURL, -// level = level + 1 -// ) -// } -// } -// -// database.synchronizeNostrEventRequestDao().insert( -// synchronizeNostrEventRequests -// ) -// } -// } -// } - nostrEvent.tags.taggedEvents().take(4).forEach { taggedEvent -> // We only look at the first 3 tagged events... val taggedNostrEvent = database.nostrEventDao().getNostrEventById(taggedEvent.eventId) if (taggedNostrEvent == null) { @@ -314,40 +203,18 @@ abstract class NostrDao( val recommendRelayUrl = taggedEvent.relay?.url - val synchronizeNostrEventRequests = if (recommendRelayUrl != null) { - eventIdsToSync.add(taggedEvent.eventId) - listOf( - SynchronizeNostrEventRequest( - purpose = "synchronization", - synchronizationFilters = arrayOf( - SynchronizationFilter( - ids = arrayOf(taggedEvent.eventId) - ) - ), - relayURL = recommendRelayUrl, - isRecommendedRelay = true, - level = level + 1 - ) - ) - } else { - eventIdsToSync.add(taggedEvent.eventId) - synchronizationRelayURLs.map { synchronizationRelayURL -> - SynchronizeNostrEventRequest( - purpose = "synchronization", - synchronizationFilters = arrayOf( - SynchronizationFilter( - ids = arrayOf(taggedEvent.eventId) - ) - ), - relayURL = synchronizationRelayURL, - level = level + 1 - ) + if (recommendRelayUrl != null) { + if (eventIdsToSync[recommendRelayUrl] == null) { + eventIdsToSync[recommendRelayUrl] = mutableSetOf() } - } + eventIdsToSync[recommendRelayUrl]?.add(taggedEvent.eventId) + } else { + if (eventIdsToSync[relayURL] == null) { + eventIdsToSync[relayURL] = mutableSetOf() + } + eventIdsToSync[relayURL]?.add(taggedEvent.eventId) - database.synchronizeNostrEventRequestDao().insert( - synchronizeNostrEventRequests - ) + } } } @@ -375,54 +242,20 @@ abstract class NostrDao( relayUrl = taggedUser.relayHint?.url ) ) - val synchronizeNostrEventRequests = if (recommendedRelay != null) { -// listOf( -// SynchronizeNostrEventRequest( -// purpose = "synchronization", -// synchronizationFilters = arrayOf( -// SynchronizationFilter( -// authors = arrayOf(taggedUser.pubKey), -// kinds = profileEventKinds -// ) -// ), -// relayURL = recommendedRelay, -// isRecommendedRelay = true, -// ) -// ) -// synchronizationFilters.add( -// SynchronizationFilter( -// authors = arrayOf(taggedUser.pubKey), -// kinds = profileEventKinds -// ) -// ) - profilePublicKeysToSync.add(taggedUser.pubKey) + if (recommendedRelay != null) { + if (profilePublicKeysToSync[relayURL] == null) { + profilePublicKeysToSync[relayURL] = mutableSetOf() + } + profilePublicKeysToSync[relayURL]?.add(taggedUser.pubKey) + } else { -// synchronizationRelayURLs.take(1).map { synchronizationRelayURL -> -// SynchronizeNostrEventRequest( -// purpose = "synchronization", -// synchronizationFilters = arrayOf( -// SynchronizationFilter( -// authors = arrayOf(taggedUser.pubKey), -// kinds = profileEventKinds -// ) -// ), -// relayURL = synchronizationRelayURL -// ) -// } - profilePublicKeysToSync.add( + if (profilePublicKeysToSync[relayURL] == null) { + profilePublicKeysToSync[relayURL] = mutableSetOf() + } + profilePublicKeysToSync[relayURL]?.add( taggedUser.pubKey ) -// synchronizationFilters.add( -// SynchronizationFilter( -// authors = arrayOf(taggedUser.pubKey), -// kinds = profileEventKinds -// ) -// ) } - -// database.synchronizeNostrEventRequestDao().insert( -// synchronizeNostrEventRequests -// ) } nostrEvent.toProfile()?.let { profile -> @@ -474,7 +307,10 @@ abstract class NostrDao( val quotedNostrEvent = database.nostrEventDao().getNostrEventById(quotedRelation.quotedNostrEventId) val quotedProfilePublicKey = if (quotedNostrEvent == null) { - eventIdsToSync.add(quotedRelation.quotedNostrEventId) + if (eventIdsToSync[relayURL] == null) { + eventIdsToSync[relayURL] = mutableSetOf() + } + eventIdsToSync[relayURL]?.add(quotedRelation.quotedNostrEventId) database.nostrEventDao().insert( NostrEvent( @@ -519,7 +355,10 @@ abstract class NostrDao( val repostedProfilePublicKey = if (repostedNostrEvent == null) { // Sync event... - eventIdsToSync.add(repostedRelation.repostedNostrEventId) + if (eventIdsToSync[relayURL] == null) { + eventIdsToSync[relayURL] = mutableSetOf() + } + eventIdsToSync[relayURL]?.add(repostedRelation.repostedNostrEventId) database.nostrEventDao().insert( NostrEvent( @@ -562,7 +401,10 @@ abstract class NostrDao( val inReplyToNostrEvent = database.nostrEventDao().getNostrEventById(inReplyToRelation.inReplyToNostrEventId) val inReplyToProfilePublicKey = if (inReplyToNostrEvent == null) { - eventIdsToSync.add(inReplyToRelation.inReplyToNostrEventId) + if (eventIdsToSync[relayURL] == null) { + eventIdsToSync[relayURL] = mutableSetOf() + } + eventIdsToSync[relayURL]?.add(inReplyToRelation.inReplyToNostrEventId) database.nostrEventDao().insert( NostrEvent( @@ -584,7 +426,10 @@ abstract class NostrDao( val inReplyToRootNostrEvent = inReplyToRelation.inReplyToRootNostrEventId?.let { database.nostrEventDao().getNostrEventById(it) } val inReplyToRootProfilePublicKey = if (inReplyToRootNostrEvent == null) { - eventIdsToSync.add(inReplyToRelation.inReplyToNostrEventId) + if (eventIdsToSync[relayURL] == null) { + eventIdsToSync[relayURL] = mutableSetOf() + } + eventIdsToSync[relayURL]?.add(inReplyToRelation.inReplyToNostrEventId) inReplyToRelation.inReplyToRootProfilePublicKey // Might need to save place holder... @@ -630,22 +475,10 @@ abstract class NostrDao( ) // Request a sync for the post being replied to - eventIdsToSync.add(zap.postId) -// database.synchronizeNostrEventRequestDao().insert( -// synchronizationRelayURLs.map { synchronizationRelayURL -> -// -// SynchronizeNostrEventRequest( -// purpose = "synchronization", -// synchronizationFilters = arrayOf( -// SynchronizationFilter( -// ids = arrayOf(zap.postId) -// ) -// ), -// relayURL = synchronizationRelayURL, -// level = level + 1 -// ) -// } -// ) + if (eventIdsToSync[relayURL] == null) { + eventIdsToSync[relayURL] = mutableSetOf() + } + eventIdsToSync[relayURL]?.add(zap.postId) } database.zapDao().upsert(zap) @@ -675,25 +508,17 @@ abstract class NostrDao( nostrEventId = nostrEvent.id, // Will get overwriting by sync, ) database.profileDao().insertPlaceholderProfile(placeHolderProfile) - -// database.synchronizeNostrEventRequestDao().insert( -// synchronizationRelayURLs.take(1).map { synchronizationRelayURL -> // TODO: Get all relayURLs instead of 1 -// SynchronizeNostrEventRequest( -// purpose = "synchronization", -// synchronizationFilters = arrayOf( -// SynchronizationFilter( -// authors = arrayOf(followedHexKEys), -// kinds = profileEventKinds -// ) -// ), -// relayURL = synchronizationRelayURL -// ) -// } -// ) - profilePublicKeysToSync.add(followedHexKEys) + if (profilePublicKeysToSync[relayURL] == null) { + profilePublicKeysToSync[relayURL] = mutableSetOf() + } + profilePublicKeysToSync[relayURL]?.add(followedHexKEys) } else if (profile.createdAt == GENESIS_AT && level == 0) { logger.i("${level} This is a placeholder profile... that might need to get synced...: $profile") - profilePublicKeysToSync.add(followedHexKEys) + + if (profilePublicKeysToSync[relayURL] == null) { + profilePublicKeysToSync[relayURL] = mutableSetOf() + } + profilePublicKeysToSync[relayURL]?.add(followedHexKEys) } // Save profile connections... @@ -709,59 +534,51 @@ abstract class NostrDao( } if (level == 0) { - if (profilePublicKeysToSync.isNotEmpty()) { - synchronizationFilters.add( - SynchronizationFilter( - authors = profilePublicKeysToSync.take(21).toTypedArray(), // We only sync 21 profiles at a time... - kinds = profileEventKinds + val negentropySynchronizeRequests = mutableListOf() + profilePublicKeysToSync.forEach { relayUrlProfilePublicKey -> + val synchronizationFilter = SynchronizationFilter( + authors = relayUrlProfilePublicKey.value.toTypedArray(), + kinds = profileEventKinds + ) + negentropySynchronizeRequests.add( + NegentropySynchronizeRequest( + id = NegentropySynchronizeRequest.computeId( + relayUrlProfilePublicKey.key, + synchronizationFilter + ), + purpose = "synchronization", + synchronizationFilter = synchronizationFilter, + relayURL = relayUrlProfilePublicKey.key, + level = level + 1 ) ) } - if (eventIdsToSync.isNotEmpty()) { - synchronizationFilters.add( - SynchronizationFilter( - ids = eventIdsToSync.take(21).toTypedArray(), // We should only sync 21 profiles at a time... + eventIdsToSync.forEach { relayUrlEventIds -> + // TODO: Hash relayUrl + synchronicationFilter + ephocMinutes + val synchronizationFilter = SynchronizationFilter( + ids = relayUrlEventIds.value.toTypedArray(), + ) + Clock.System.now().toEpochMilliseconds() + negentropySynchronizeRequests.add( + NegentropySynchronizeRequest( + id = NegentropySynchronizeRequest.computeId( + relayUrlEventIds.key, + synchronizationFilter + ), + purpose = "synchronization", + synchronizationFilter = synchronizationFilter, + relayURL = relayUrlEventIds.key, + level = level + 1 ) ) } - } else { - logger.d("We shouldn't sync profiles on level ${level} so we dropping: $profilePublicKeysToSync") - } - - - if (synchronizationFilters.size > 1) { - logger.d("We have a lot to sync") - } - - if (synchronizationFilters.isNotEmpty()) { - logger.d("Synchronize ${level}: $synchronizationFilters") - - val relays = if( profilePublicKeysToSync.isNotEmpty()) { - // If we are syncing profilePublicKeys we might want - Relays.eventFinderRelaySet.map { it.url } - } else { - - synchronizationRelayURLs - } - - synchronizationFilters.forEach { synchronizationFilter -> - database.synchronizeNostrEventRequestDao().insert( - - relays.take(3).map { synchronizationRelayURL -> // TODO: Get all relayURLs instead of 1 - SynchronizeNostrEventRequest( - purpose = "synchronization", - synchronizationFilters = arrayOf( - synchronizationFilter - ), - relayURL = synchronizationRelayURL, - level = level + 1 - ) - } + if (negentropySynchronizeRequests.isNotEmpty()) { + database.negentropySynchronizeRequestDao().insert( + negentropySynchronizeRequests ) } } - } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/NegentropySynchronizeRequest.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/NegentropySynchronizeRequest.kt index 3c0ea0e8..107c21a0 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/NegentropySynchronizeRequest.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/NegentropySynchronizeRequest.kt @@ -3,11 +3,13 @@ package ac.cord.auxiliary.compose.database.model import ac.cord.auxiliary.compose.database.model.traits.OptionalNostrEventEntity import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity import ac.cord.auxiliary.compose.database.model.types.SynchronizationFilter +import ac.cord.auxiliary.compose.network.serialization.encodeToJsonString import androidx.room3.Entity import androidx.room3.ForeignKey import androidx.room3.Index import androidx.room3.PrimaryKey import com.vitorpamplona.quartz.nip01Core.core.HexKey +import kotlin.math.ceil import kotlin.time.Clock import kotlin.time.Instant import kotlin.uuid.ExperimentalUuidApi @@ -30,7 +32,8 @@ import kotlin.uuid.Uuid ) data class NegentropySynchronizeRequest( @PrimaryKey - val id: String = Uuid.Companion.generateV4().toHexDashString(), + val id: String, + val uuid: String = Uuid.generateV4().toHexDashString(), val purpose: String, val status: String = "pending", val relayURL: String, @@ -45,4 +48,14 @@ data class NegentropySynchronizeRequest( override val updatedAt: Instant = createdAt, ): OptionalNostrEventEntity, TimestampedEntity { + companion object { + fun computeId( + relayURL: String, + synchronizationFilter: SynchronizationFilter, + ): String { + val id = relayURL + synchronizationFilter + ceil(Clock.System.now().epochSeconds/60.0) + + return Uuid.generateV4().toHexDashString() + } + } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FeedListViewModel.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FeedListViewModel.kt index 4112b19a..4ecbc26e 100755 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FeedListViewModel.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FeedListViewModel.kt @@ -55,6 +55,10 @@ class FeedListViewModel( val negentropySynchronizeRequests = Relays.negentropicRelaySet.shuffled().take(1).map { normalizedRelayUrl -> NegentropySynchronizeRequest( + id = NegentropySynchronizeRequest.computeId( + normalizedRelayUrl.url, + synchronizationFilter = synchronizationFilter + ), purpose = "feed", synchronizationFilter = synchronizationFilter, relayURL = normalizedRelayUrl.url, diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowersListViewModel.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowersListViewModel.kt index f841ad16..7e67053a 100755 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowersListViewModel.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowersListViewModel.kt @@ -78,6 +78,10 @@ class FollowersListViewModel( nostrRepository.queueNegentropySynchronizeRequest( Relays.eventPublishRelaySet.take(1).map { normalizedRelayUrl -> NegentropySynchronizeRequest( + id = NegentropySynchronizeRequest.computeId( + relayURL = normalizedRelayUrl.url, + synchronizationFilter = synchronizationFilter + ), purpose = "followers", synchronizationFilter = synchronizationFilter, relayURL = normalizedRelayUrl.url, diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowingListViewModel.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowingListViewModel.kt index e0d7efff..3acbe147 100755 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowingListViewModel.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowingListViewModel.kt @@ -77,6 +77,10 @@ class FollowingListViewModel( nostrRepository.queueNegentropySynchronizeRequest( Relays.eventPublishRelaySet.take(1).map { normalizedRelayUrl -> NegentropySynchronizeRequest( + id = NegentropySynchronizeRequest.computeId( + relayURL = normalizedRelayUrl.url, + synchronizationFilter = synchronizationFilter + ), purpose = "following", synchronizationFilter = synchronizationFilter, relayURL = normalizedRelayUrl.url, diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/InReplyToViewModel.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/InReplyToViewModel.kt index 87301fd5..447ad0e8 100755 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/InReplyToViewModel.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/InReplyToViewModel.kt @@ -82,6 +82,10 @@ class InReplyToViewModel( nostrRepository.queueNegentropySynchronizeRequest( Relays.eventPublishRelaySet.take(1).map { normalizedRelayUrl -> NegentropySynchronizeRequest( + id = NegentropySynchronizeRequest.computeId( + relayURL = normalizedRelayUrl.url, + synchronizationFilter = synchronizationFilter + ), purpose = "inReplyTo", synchronizationFilter = synchronizationFilter, relayURL = normalizedRelayUrl.url, diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/NavigationViewModel.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/NavigationViewModel.kt index cbd3fbb6..fff549bc 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/NavigationViewModel.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/NavigationViewModel.kt @@ -245,7 +245,7 @@ class NavigationViewModel( ) val negOpenCmd = NegOpenCmd( - subId = negentropySynchronizeRequest.id, + subId = negentropySynchronizeRequest.uuid, filter = Filter( ids = negentropySynchronizeRequest.synchronizationFilter.ids?.toList(), authors = negentropySynchronizeRequest.synchronizationFilter.authors?.toList(), @@ -266,7 +266,7 @@ class NavigationViewModel( scope.launch(Dispatchers.IO) { try { val negCloseCmd = NegCloseCmd( - subId = negentropySynchronizeRequest.id, + subId = negentropySynchronizeRequest.uuid, ) relaysSocketManager.negentropySync( @@ -308,6 +308,7 @@ class NavigationViewModel( is NostrIncomingMessage.NegentropyError -> { logger.d("Negentropy Error (need to synchronize like normal): ${nostrIncomingMessage.negentropyReason}") + // TODO: Don't schedule a sync when on mobile internet. val since = negentropySynchronizeRequest.synchronizationFilter.since // TODO: Update since -> until based on what we have in the local db... val until = negentropySynchronizeRequest.synchronizationFilter.until