refactor: simplify NostrClient API for beginner-friendliness
Comprehensive rename of the NostrClient relay infrastructure to use intuitive, self-documenting names instead of protocol-level jargon. Interface/class renames: - INostrClient → NostrClient (interface) - NostrClient → DefaultNostrClient (implementation) - IRequestListener → SubscriptionListener - IRelayClientListener → RelayConnectionListener - IOpenNostrRequest → SubscriptionHandle - NostrClientStaticReq → StaticSubscription - NostrClientDynamicReq → DynamicSubscription Method renames: - openReqSubscription() → subscribe() - close(subId) → unsubscribe(subId) - send() → publish() - queryCount() → count() - subscribe/unsubscribe(listener) → addConnectionListener/removeConnectionListener - renewFilters() → syncFilters() Callback renames: - onEose → onCaughtUp - isLive → isRealTime - onStartReq → onSubscriptionStarted - onCloseReq → onSubscriptionClosed Extension function renames: - query() → fetchAll() - downloadFirstEvent() → fetchFirst() - req() → subscribe() - reqAsFlow() → subscribeAsFlow() - reqUntilEoseAsFlow() → fetchAsFlow() - sendAndWaitForResponse() → publishAndConfirm() - queryCountSuspend() → count() - queryCountMergedHll() → countMerged() - reqBypassingRelayLimits() → fetchAllPages() - updateFilter() → refresh() on SubscriptionHandle https://claude.ai/code/session_01JPcYCcRx5eZN4GvgGxGwbf
This commit is contained in:
@@ -193,7 +193,7 @@ fun main() {
|
||||
}
|
||||
|
||||
Window(
|
||||
onCloseRequest = ::exitApplication,
|
||||
onSubscriptionCloseduest = ::exitApplication,
|
||||
state = windowState,
|
||||
title = "Amethyst",
|
||||
) {
|
||||
|
||||
+13
-14
@@ -30,8 +30,7 @@ import com.vitorpamplona.amethyst.desktop.network.DesktopHttpClient
|
||||
import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray
|
||||
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.RelayConnectionListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.Message
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.Command
|
||||
@@ -132,11 +131,11 @@ class AccountManager internal constructor(
|
||||
// --- Dedicated NIP-46 client (isolated from general relay pool) ---
|
||||
|
||||
private val nip46ClientMutex = Mutex()
|
||||
private var nip46Client: NostrClient? = null
|
||||
private var nip46Client: DefaultDefaultNostrClient? = null
|
||||
|
||||
private suspend fun getOrCreateNip46Client(): NostrClient =
|
||||
private suspend fun getOrCreateNip46Client(): DefaultNostrClient =
|
||||
nip46ClientMutex.withLock {
|
||||
nip46Client ?: NostrClient(
|
||||
nip46Client ?: DefaultNostrClient(
|
||||
BasicOkHttpWebSocket.Builder(DesktopHttpClient::getHttpClient),
|
||||
).also {
|
||||
nip46Client = it
|
||||
@@ -156,7 +155,7 @@ class AccountManager internal constructor(
|
||||
* but we must wait for the websocket to be ready before sending requests.
|
||||
*/
|
||||
private suspend fun awaitNip46RelayConnection(
|
||||
client: NostrClient,
|
||||
client: DefaultNostrClient,
|
||||
targetRelays: Set<NormalizedRelayUrl>,
|
||||
) {
|
||||
withTimeout(NIP46_RELAY_CONNECT_TIMEOUT_MS) {
|
||||
@@ -180,8 +179,8 @@ class AccountManager internal constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun createLoginRelayListener(): IRelayClientListener =
|
||||
object : IRelayClientListener {
|
||||
private fun createLoginRelayListener(): RelayConnectionListener =
|
||||
object : RelayConnectionListener {
|
||||
override fun onConnected(
|
||||
relay: IRelayClient,
|
||||
pingMillis: Int,
|
||||
@@ -303,7 +302,7 @@ class AccountManager internal constructor(
|
||||
|
||||
suspend fun loginWithBunker(bunkerUri: String): Result<AccountState.LoggedIn> {
|
||||
val listener = createLoginRelayListener()
|
||||
var client: NostrClient? = null
|
||||
var client: DefaultDefaultNostrClient? = null
|
||||
try {
|
||||
val ephemeralKeyPair = KeyPair()
|
||||
val ephemeralSigner = NostrSignerInternal(ephemeralKeyPair)
|
||||
@@ -316,7 +315,7 @@ class AccountManager internal constructor(
|
||||
LoginProgress.ConnectingToRelays(
|
||||
relaysFromUri.associateWith { RelayLoginStatus.CONNECTING },
|
||||
)
|
||||
nip46Client.subscribe(listener)
|
||||
nip46Client.addConnectionListener(listener)
|
||||
|
||||
_loginProgress.value =
|
||||
LoginProgress.WaitingForSigner(
|
||||
@@ -356,7 +355,7 @@ class AccountManager internal constructor(
|
||||
return Result.failure(Exception("Connection failed: ${e.message}"))
|
||||
} finally {
|
||||
_loginProgress.value = null
|
||||
client?.unsubscribe(listener)
|
||||
client?.removeConnectionListener(listener)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,7 +363,7 @@ class AccountManager internal constructor(
|
||||
|
||||
suspend fun loginWithNostrConnect(onUriGenerated: (String) -> Unit): Result<AccountState.LoggedIn> {
|
||||
val listener = createLoginRelayListener()
|
||||
var client: NostrClient? = null
|
||||
var client: DefaultDefaultNostrClient? = null
|
||||
try {
|
||||
val ephemeralKeyPair = KeyPair()
|
||||
val uriData = NostrConnectLoginUseCase.generateUri(ephemeralKeyPair, NIP46_RELAYS, "Amethyst%20Desktop")
|
||||
@@ -376,7 +375,7 @@ class AccountManager internal constructor(
|
||||
LoginProgress.ConnectingToRelays(
|
||||
uriData.relays.associateWith { RelayLoginStatus.CONNECTING },
|
||||
)
|
||||
nip46Client.subscribe(listener)
|
||||
nip46Client.addConnectionListener(listener)
|
||||
|
||||
onUriGenerated(uriData.uri)
|
||||
|
||||
@@ -415,7 +414,7 @@ class AccountManager internal constructor(
|
||||
return Result.failure(Exception("Connection failed: ${e.message}"))
|
||||
} finally {
|
||||
_loginProgress.value = null
|
||||
client?.unsubscribe(listener)
|
||||
client?.removeConnectionListener(listener)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -140,7 +140,7 @@ fun ChessScreen(
|
||||
onEvent = { event, _, _, _ ->
|
||||
viewModel.handleIncomingEvent(event)
|
||||
},
|
||||
onEose = { _, _ ->
|
||||
onCaughtUp = { _, _ ->
|
||||
// ChessLobbyLogic handles loading state internally
|
||||
},
|
||||
)
|
||||
|
||||
+19
-19
@@ -22,8 +22,8 @@ package com.vitorpamplona.amethyst.desktop.network
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.IRequestListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.RelayConnectionListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.SubscriptionListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.Message
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.Command
|
||||
@@ -43,11 +43,11 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||
*/
|
||||
open class RelayConnectionManager(
|
||||
websocketBuilder: WebsocketBuilder,
|
||||
) : IRelayClientListener {
|
||||
private val _client = NostrClient(websocketBuilder)
|
||||
) : RelayConnectionListener {
|
||||
private val _client = DefaultNostrClient(websocketBuilder)
|
||||
|
||||
/** Exposes the underlying INostrClient for subscription coordinators */
|
||||
val client: com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient get() = _client
|
||||
/** Exposes the underlying NostrClient for subscription coordinators */
|
||||
val client: com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient get() = _client
|
||||
|
||||
private val _relayStatuses = MutableStateFlow<Map<NormalizedRelayUrl, RelayStatus>>(emptyMap())
|
||||
val relayStatuses: StateFlow<Map<NormalizedRelayUrl, RelayStatus>> = _relayStatuses.asStateFlow()
|
||||
@@ -56,7 +56,7 @@ open class RelayConnectionManager(
|
||||
val availableRelays: StateFlow<Set<NormalizedRelayUrl>> = _client.availableRelaysFlow()
|
||||
|
||||
init {
|
||||
_client.subscribe(this)
|
||||
_client.addConnectionListener(this)
|
||||
}
|
||||
|
||||
fun connect() {
|
||||
@@ -85,21 +85,21 @@ open class RelayConnectionManager(
|
||||
subId: String,
|
||||
filters: List<Filter>,
|
||||
relays: Set<NormalizedRelayUrl> = availableRelays.value,
|
||||
listener: IRequestListener? = null,
|
||||
listener: SubscriptionListener? = null,
|
||||
) {
|
||||
val filterMap = relays.associateWith { filters }
|
||||
_client.openReqSubscription(subId, filterMap, listener)
|
||||
_client.subscribe(subId, filterMap, listener)
|
||||
}
|
||||
|
||||
fun unsubscribe(subId: String) {
|
||||
_client.close(subId)
|
||||
_client.unsubscribe(subId)
|
||||
}
|
||||
|
||||
fun send(
|
||||
fun publish(
|
||||
event: Event,
|
||||
relays: Set<NormalizedRelayUrl> = connectedRelays.value,
|
||||
) {
|
||||
_client.send(event, relays)
|
||||
_client.publish(event, relays)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,21 +107,21 @@ open class RelayConnectionManager(
|
||||
*/
|
||||
fun broadcastToAll(event: Event) {
|
||||
val connected = connectedRelays.value
|
||||
send(event, connected)
|
||||
publish(event, connected)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an event to a specific relay (for NWC).
|
||||
* Adds the relay if not already in the list.
|
||||
*/
|
||||
fun sendToRelay(
|
||||
fun publishToRelay(
|
||||
relay: NormalizedRelayUrl,
|
||||
event: Event,
|
||||
) {
|
||||
if (relay !in availableRelays.value) {
|
||||
updateRelayStatus(relay) { it.copy(connected = false, error = null) }
|
||||
}
|
||||
_client.send(event, setOf(relay))
|
||||
_client.publish(event, setOf(relay))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,14 +138,14 @@ open class RelayConnectionManager(
|
||||
updateRelayStatus(relay) { it.copy(connected = false, error = null) }
|
||||
}
|
||||
val filterMap = mapOf(relay to filters)
|
||||
_client.openReqSubscription(
|
||||
_client.subscribe(
|
||||
subId = subId,
|
||||
filters = filterMap,
|
||||
listener =
|
||||
object : IRequestListener {
|
||||
object : SubscriptionListener {
|
||||
override fun onEvent(
|
||||
event: Event,
|
||||
isLive: Boolean,
|
||||
isRealTime: Boolean,
|
||||
relay: NormalizedRelayUrl,
|
||||
forFilters: List<Filter>?,
|
||||
) {
|
||||
@@ -162,7 +162,7 @@ open class RelayConnectionManager(
|
||||
relay: NormalizedRelayUrl,
|
||||
subId: String,
|
||||
) {
|
||||
_client.close(subId)
|
||||
_client.unsubscribe(subId)
|
||||
}
|
||||
|
||||
private fun updateRelayStatus(
|
||||
|
||||
+1
-1
@@ -103,7 +103,7 @@ class NwcPaymentHandler(
|
||||
zappedNote?.addZapPayment(requestNote, null)
|
||||
|
||||
// Send request to wallet's relay
|
||||
relayManager.sendToRelay(nwcConnection.relayUri, requestEvent)
|
||||
relayManager.publishToRelay(nwcConnection.relayUri, requestEvent)
|
||||
|
||||
// Subscribe and wait for response with timeout
|
||||
return withTimeoutOrNull(timeoutMs) {
|
||||
|
||||
+13
-13
@@ -27,7 +27,7 @@ import com.vitorpamplona.amethyst.desktop.chess.DesktopChessEventCache
|
||||
import com.vitorpamplona.amethyst.desktop.network.RelayConnectionManager
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.pool.groupByRelay
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.IRequestListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.SubscriptionListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip64Chess.challenge.accept.LiveChessGameAcceptEvent
|
||||
@@ -58,7 +58,7 @@ private val CHESS_EVENT_KINDS =
|
||||
class DesktopChessSubscriptionController(
|
||||
private val relayManager: RelayConnectionManager,
|
||||
private val onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
private val onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
private val onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
) : ChessSubscriptionController {
|
||||
private val _currentState = MutableStateFlow<ChessSubscriptionState?>(null)
|
||||
override val currentState: StateFlow<ChessSubscriptionState?> = _currentState.asStateFlow()
|
||||
@@ -95,10 +95,10 @@ class DesktopChessSubscriptionController(
|
||||
filters = allFilters,
|
||||
relays = state.relays,
|
||||
listener =
|
||||
object : IRequestListener {
|
||||
object : SubscriptionListener {
|
||||
override fun onEvent(
|
||||
event: Event,
|
||||
isLive: Boolean,
|
||||
isRealTime: Boolean,
|
||||
relay: NormalizedRelayUrl,
|
||||
forFilters: List<Filter>?,
|
||||
) {
|
||||
@@ -106,16 +106,16 @@ class DesktopChessSubscriptionController(
|
||||
if (event.kind in CHESS_EVENT_KINDS) {
|
||||
DesktopChessEventCache.add(event)
|
||||
}
|
||||
onEvent(event, isLive, relay, forFilters)
|
||||
onEvent(event, isRealTime, relay, forFilters)
|
||||
}
|
||||
|
||||
override fun onEose(
|
||||
override fun onCaughtUp(
|
||||
relay: NormalizedRelayUrl,
|
||||
forFilters: List<Filter>?,
|
||||
) {
|
||||
// Track EOSE time for this relay for efficient re-subscription
|
||||
relayEoseTimes[relay] = TimeUtils.now()
|
||||
onEose(relay, forFilters)
|
||||
onCaughtUp(relay, forFilters)
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -162,7 +162,7 @@ class DesktopChessSubscriptionController(
|
||||
* @param activeGameIds Set of game IDs the user is actively playing (for game-specific filters)
|
||||
* @param opponentPubkeys Set of opponent pubkeys for active games (for move filtering)
|
||||
* @param onEvent Callback for incoming events
|
||||
* @param onEose Callback for EOSE (End of Stored Events)
|
||||
* @param onCaughtUp Callback for EOSE (End of Stored Events)
|
||||
*/
|
||||
fun createChessSubscriptionWithGames(
|
||||
relays: Set<NormalizedRelayUrl>,
|
||||
@@ -170,7 +170,7 @@ fun createChessSubscriptionWithGames(
|
||||
activeGameIds: Set<String> = emptySet(),
|
||||
opponentPubkeys: Set<String> = emptySet(),
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
if (relays.isEmpty()) return null
|
||||
|
||||
@@ -197,7 +197,7 @@ fun createChessSubscriptionWithGames(
|
||||
filters = filters,
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -207,11 +207,11 @@ fun createChessSubscriptionWithGames(
|
||||
*/
|
||||
@Deprecated(
|
||||
"Use createChessSubscriptionWithGames for active game support",
|
||||
ReplaceWith("createChessSubscriptionWithGames(relays, userPubkey, emptySet(), emptySet(), onEvent, onEose)"),
|
||||
ReplaceWith("createChessSubscriptionWithGames(relays, userPubkey, emptySet(), emptySet(), onEvent, onCaughtUp)"),
|
||||
)
|
||||
fun createChessSubscription(
|
||||
relays: Set<NormalizedRelayUrl>,
|
||||
userPubkey: String,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? = createChessSubscriptionWithGames(relays, userPubkey, emptySet(), emptySet(), onEvent, onEose)
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? = createChessSubscriptionWithGames(relays, userPubkey, emptySet(), emptySet(), onEvent, onCaughtUp)
|
||||
|
||||
+16
-16
@@ -30,8 +30,8 @@ import com.vitorpamplona.amethyst.desktop.model.DesktopDmRelayState
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.IRequestListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.SubscriptionListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -73,7 +73,7 @@ import kotlin.time.Duration.Companion.seconds
|
||||
* ```
|
||||
*/
|
||||
class DesktopRelaySubscriptionsCoordinator(
|
||||
private val client: INostrClient,
|
||||
private val client: NostrClient,
|
||||
private val scope: CoroutineScope,
|
||||
private val indexRelays: Set<NormalizedRelayUrl>,
|
||||
private val localCache: DesktopLocalCache,
|
||||
@@ -153,7 +153,7 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
|
||||
// Cancel any existing subscription with this ID
|
||||
screenSubscriptions.remove(subId)?.cancel()
|
||||
client.close(subId)
|
||||
client.unsubscribe(subId)
|
||||
|
||||
if (noteIds.isEmpty() || relays.isEmpty()) return subId
|
||||
|
||||
@@ -177,10 +177,10 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
)
|
||||
|
||||
val listener =
|
||||
object : IRequestListener {
|
||||
object : SubscriptionListener {
|
||||
override fun onEvent(
|
||||
event: Event,
|
||||
isLive: Boolean,
|
||||
isRealTime: Boolean,
|
||||
relay: NormalizedRelayUrl,
|
||||
forFilters: List<Filter>?,
|
||||
) {
|
||||
@@ -190,7 +190,7 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
|
||||
val job =
|
||||
scope.launch {
|
||||
client.openReqSubscription(
|
||||
client.subscribe(
|
||||
subId = subId,
|
||||
filters = relays.associateWith { filters },
|
||||
listener = listener,
|
||||
@@ -206,7 +206,7 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
*/
|
||||
fun releaseInteractions(subId: String) {
|
||||
screenSubscriptions.remove(subId)?.cancel()
|
||||
client.close(subId)
|
||||
client.unsubscribe(subId)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,7 +217,7 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
// Start rate limiter to process queued metadata requests
|
||||
rateLimiter.start { pubkey ->
|
||||
// When rate limiter dequeues a pubkey, subscribe to its metadata
|
||||
client.openReqSubscription(
|
||||
client.subscribe(
|
||||
filters =
|
||||
indexRelays.associateWith {
|
||||
listOf(
|
||||
@@ -281,10 +281,10 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
if (inboxRelays.isEmpty() && outboxRelays.isEmpty()) return
|
||||
|
||||
val listener =
|
||||
object : IRequestListener {
|
||||
object : SubscriptionListener {
|
||||
override fun onEvent(
|
||||
event: Event,
|
||||
isLive: Boolean,
|
||||
isRealTime: Boolean,
|
||||
relay: NormalizedRelayUrl,
|
||||
forFilters: List<Filter>?,
|
||||
) {
|
||||
@@ -296,7 +296,7 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
if (inboxRelays.isNotEmpty()) {
|
||||
val inboxSubId = generateSubId("dm-inbox-${userPubKeyHex.take(8)}")
|
||||
activeDmSubIds.add(inboxSubId)
|
||||
client.openReqSubscription(
|
||||
client.subscribe(
|
||||
subId = inboxSubId,
|
||||
filters =
|
||||
inboxRelays.associateWith {
|
||||
@@ -310,7 +310,7 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
if (outboxRelays.isNotEmpty()) {
|
||||
val outboxSubId = generateSubId("dm-outbox-${userPubKeyHex.take(8)}")
|
||||
activeDmSubIds.add(outboxSubId)
|
||||
client.openReqSubscription(
|
||||
client.subscribe(
|
||||
subId = outboxSubId,
|
||||
filters =
|
||||
outboxRelays.associateWith {
|
||||
@@ -324,7 +324,7 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
if (inboxRelays.isNotEmpty()) {
|
||||
val giftWrapSubId = generateSubId("giftwrap-${userPubKeyHex.take(8)}")
|
||||
activeDmSubIds.add(giftWrapSubId)
|
||||
client.openReqSubscription(
|
||||
client.subscribe(
|
||||
subId = giftWrapSubId,
|
||||
filters =
|
||||
inboxRelays.associateWith {
|
||||
@@ -340,7 +340,7 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
*/
|
||||
fun unsubscribeFromDms() {
|
||||
activeDmSubIds.forEach { subId ->
|
||||
client.close(subId)
|
||||
client.unsubscribe(subId)
|
||||
}
|
||||
activeDmSubIds.clear()
|
||||
}
|
||||
@@ -353,7 +353,7 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
// Clean up screen-triggered subscriptions
|
||||
screenSubscriptions.forEach { (subId, job) ->
|
||||
job.cancel()
|
||||
client.close(subId)
|
||||
client.unsubscribe(subId)
|
||||
}
|
||||
screenSubscriptions.clear()
|
||||
_lastEventAt.value = null
|
||||
|
||||
+28
-28
@@ -39,14 +39,14 @@ fun createGlobalFeedSubscription(
|
||||
relays: Set<NormalizedRelayUrl>,
|
||||
limit: Int = 50,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig =
|
||||
SubscriptionConfig(
|
||||
subId = generateSubId("global-feed"),
|
||||
filters = listOf(FilterBuilders.textNotesGlobal(limit = limit)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -57,7 +57,7 @@ fun createFollowingFeedSubscription(
|
||||
followedUsers: List<String>,
|
||||
limit: Int = 50,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
if (followedUsers.isEmpty()) return null
|
||||
|
||||
@@ -66,7 +66,7 @@ fun createFollowingFeedSubscription(
|
||||
filters = listOf(FilterBuilders.textNotesFromAuthors(followedUsers, limit = limit)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -77,14 +77,14 @@ fun createContactListSubscription(
|
||||
relays: Set<NormalizedRelayUrl>,
|
||||
pubKeyHex: String,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig =
|
||||
SubscriptionConfig(
|
||||
subId = generateSubId("contacts-${pubKeyHex.take(8)}"),
|
||||
filters = listOf(FilterBuilders.contactList(pubKeyHex)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -94,14 +94,14 @@ fun createNoteSubscription(
|
||||
relays: Set<NormalizedRelayUrl>,
|
||||
noteId: String,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig =
|
||||
SubscriptionConfig(
|
||||
subId = generateSubId("note-${noteId.take(8)}"),
|
||||
filters = listOf(FilterBuilders.byIds(listOf(noteId))),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -115,7 +115,7 @@ fun createThreadRepliesSubscription(
|
||||
noteId: String,
|
||||
limit: Int = 200,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig =
|
||||
SubscriptionConfig(
|
||||
subId = generateSubId("thread-${noteId.take(8)}"),
|
||||
@@ -129,7 +129,7 @@ fun createThreadRepliesSubscription(
|
||||
),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -144,7 +144,7 @@ fun createSearchPeopleSubscription(
|
||||
searchQuery: String,
|
||||
limit: Int = 50,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onClosed: (NormalizedRelayUrl, String, List<Filter>?) -> Unit = { _, _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
if (searchQuery.isBlank()) return null
|
||||
@@ -154,7 +154,7 @@ fun createSearchPeopleSubscription(
|
||||
filters = listOf(FilterBuilders.searchPeople(searchQuery, limit)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
onClosed = onClosed,
|
||||
)
|
||||
}
|
||||
@@ -171,7 +171,7 @@ fun createSearchNotesSubscription(
|
||||
searchQuery: String,
|
||||
limit: Int = 50,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
if (searchQuery.isBlank()) return null
|
||||
|
||||
@@ -180,7 +180,7 @@ fun createSearchNotesSubscription(
|
||||
filters = listOf(FilterBuilders.searchNotes(searchQuery, limit)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ fun createZapsSubscription(
|
||||
eventIds: List<String>,
|
||||
limit: Int = 100,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
if (eventIds.isEmpty()) return null
|
||||
|
||||
@@ -204,7 +204,7 @@ fun createZapsSubscription(
|
||||
filters = listOf(FilterBuilders.zapsForEvents(eventIds, limit)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ fun createReactionsSubscription(
|
||||
eventIds: List<String>,
|
||||
limit: Int = 100,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
if (eventIds.isEmpty()) return null
|
||||
|
||||
@@ -228,7 +228,7 @@ fun createReactionsSubscription(
|
||||
filters = listOf(FilterBuilders.reactionsForEvents(eventIds, limit)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ fun createRepliesSubscription(
|
||||
eventIds: List<String>,
|
||||
limit: Int = 100,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
if (eventIds.isEmpty()) return null
|
||||
|
||||
@@ -252,7 +252,7 @@ fun createRepliesSubscription(
|
||||
filters = listOf(FilterBuilders.repliesForEvents(eventIds, limit)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ fun createRepostsSubscription(
|
||||
eventIds: List<String>,
|
||||
limit: Int = 100,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
if (eventIds.isEmpty()) return null
|
||||
|
||||
@@ -276,7 +276,7 @@ fun createRepostsSubscription(
|
||||
filters = listOf(FilterBuilders.repostsForEvents(eventIds, limit)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -287,14 +287,14 @@ fun createLongFormFeedSubscription(
|
||||
relays: Set<NormalizedRelayUrl>,
|
||||
limit: Int = 30,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig =
|
||||
SubscriptionConfig(
|
||||
subId = generateSubId("longform-feed"),
|
||||
filters = listOf(FilterBuilders.longFormGlobal(limit = limit)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -305,7 +305,7 @@ fun createFollowingLongFormFeedSubscription(
|
||||
followedUsers: List<String>,
|
||||
limit: Int = 30,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
if (followedUsers.isEmpty()) return null
|
||||
|
||||
@@ -314,7 +314,7 @@ fun createFollowingLongFormFeedSubscription(
|
||||
filters = listOf(FilterBuilders.longFormFromAuthors(followedUsers, limit = limit)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ fun createChessSubscription(
|
||||
userPubkey: String,
|
||||
limit: Int = 100,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig =
|
||||
SubscriptionConfig(
|
||||
subId = generateSubId("chess-${userPubkey.take(8)}"),
|
||||
@@ -348,5 +348,5 @@ fun createChessSubscription(
|
||||
),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
|
||||
+8
-8
@@ -144,7 +144,7 @@ fun createNip04DmInboxSubscription(
|
||||
since: Long? = null,
|
||||
limit: Int? = null,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
if (relays.isEmpty() || userPubKeyHex.length != 64) return null
|
||||
|
||||
@@ -153,7 +153,7 @@ fun createNip04DmInboxSubscription(
|
||||
filters = listOf(FilterDMs.nip04ToMe(userPubKeyHex, since, limit)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ fun createNip04DmOutboxSubscription(
|
||||
since: Long? = null,
|
||||
limit: Int? = null,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
if (relays.isEmpty() || userPubKeyHex.length != 64) return null
|
||||
|
||||
@@ -176,7 +176,7 @@ fun createNip04DmOutboxSubscription(
|
||||
filters = listOf(FilterDMs.nip04FromMe(userPubKeyHex, since, limit)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ fun createGiftWrapSubscription(
|
||||
userPubKeyHex: HexKey,
|
||||
since: Long? = null,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
if (relays.isEmpty() || userPubKeyHex.length != 64) return null
|
||||
|
||||
@@ -198,7 +198,7 @@ fun createGiftWrapSubscription(
|
||||
filters = listOf(FilterDMs.giftWrapsToMe(userPubKeyHex, since)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ fun createDmConversationSubscription(
|
||||
conversationPubKeys: Set<HexKey>,
|
||||
since: Long? = null,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
if (conversationPubKeys.isEmpty() || userPubKeyHex.length != 64) return null
|
||||
|
||||
@@ -225,6 +225,6 @@ fun createDmConversationSubscription(
|
||||
filters = FilterDMs.nip04Conversation(userPubKeyHex, conversationPubKeys, since),
|
||||
relays = allRelays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
+10
-10
@@ -32,7 +32,7 @@ fun createMetadataSubscription(
|
||||
relays: Set<NormalizedRelayUrl>,
|
||||
pubKeyHex: String,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
// Validate pubkey length
|
||||
if (pubKeyHex.length != 64) {
|
||||
@@ -43,7 +43,7 @@ fun createMetadataSubscription(
|
||||
filters = listOf(FilterBuilders.userMetadata(pubKeyHex)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ fun createBatchMetadataSubscription(
|
||||
relays: Set<NormalizedRelayUrl>,
|
||||
pubKeyHexList: List<String>,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
// Filter out invalid pubkeys
|
||||
val validPubkeys = pubKeyHexList.filter { it.length == 64 }
|
||||
@@ -67,7 +67,7 @@ fun createBatchMetadataSubscription(
|
||||
filters = listOf(FilterBuilders.userMetadataBatch(validPubkeys)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ fun createMetadataListSubscription(
|
||||
relays: Set<NormalizedRelayUrl>,
|
||||
pubKeys: List<String>,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig? {
|
||||
if (pubKeys.isEmpty()) return null
|
||||
|
||||
@@ -88,7 +88,7 @@ fun createMetadataListSubscription(
|
||||
filters = listOf(FilterBuilders.userMetadataMultiple(pubKeys)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ fun createUserPostsSubscription(
|
||||
pubKeyHex: String,
|
||||
limit: Int = 50,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig =
|
||||
SubscriptionConfig(
|
||||
subId = generateSubId("posts-${pubKeyHex.take(8)}"),
|
||||
@@ -111,7 +111,7 @@ fun createUserPostsSubscription(
|
||||
),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -122,12 +122,12 @@ fun createNotificationsSubscription(
|
||||
pubKeyHex: String,
|
||||
limit: Int = 100,
|
||||
onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
): SubscriptionConfig =
|
||||
SubscriptionConfig(
|
||||
subId = generateSubId("notif-${pubKeyHex.take(8)}"),
|
||||
filters = listOf(FilterBuilders.notificationsForUser(pubKeyHex, limit = limit)),
|
||||
relays = relays,
|
||||
onEvent = onEvent,
|
||||
onEose = onEose,
|
||||
onCaughtUp = onCaughtUp,
|
||||
)
|
||||
|
||||
+7
-7
@@ -25,7 +25,7 @@ import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import com.vitorpamplona.amethyst.desktop.network.RelayConnectionManager
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.IRequestListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.SubscriptionListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
|
||||
@@ -45,7 +45,7 @@ data class SubscriptionConfig(
|
||||
val filters: List<Filter>,
|
||||
val relays: Set<NormalizedRelayUrl>,
|
||||
val onEvent: (Event, Boolean, NormalizedRelayUrl, List<Filter>?) -> Unit,
|
||||
val onEose: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
val onCaughtUp: (NormalizedRelayUrl, List<Filter>?) -> Unit = { _, _ -> },
|
||||
val onClosed: (NormalizedRelayUrl, String, List<Filter>?) -> Unit = { _, _, _ -> },
|
||||
)
|
||||
|
||||
@@ -80,21 +80,21 @@ fun rememberSubscription(
|
||||
filters = cfg.filters,
|
||||
relays = cfg.relays,
|
||||
listener =
|
||||
object : IRequestListener {
|
||||
object : SubscriptionListener {
|
||||
override fun onEvent(
|
||||
event: Event,
|
||||
isLive: Boolean,
|
||||
isRealTime: Boolean,
|
||||
relay: NormalizedRelayUrl,
|
||||
forFilters: List<Filter>?,
|
||||
) {
|
||||
cfg.onEvent(event, isLive, relay, forFilters)
|
||||
cfg.onEvent(event, isRealTime, relay, forFilters)
|
||||
}
|
||||
|
||||
override fun onEose(
|
||||
override fun onCaughtUp(
|
||||
relay: NormalizedRelayUrl,
|
||||
forFilters: List<Filter>?,
|
||||
) {
|
||||
cfg.onEose(relay, forFilters)
|
||||
cfg.onCaughtUp(relay, forFilters)
|
||||
}
|
||||
|
||||
override fun onClosed(
|
||||
|
||||
+1
-1
@@ -175,7 +175,7 @@ fun ArticleEditorScreen(
|
||||
)
|
||||
// TODO: send() is fire-and-forget; markPublished runs before relay ack.
|
||||
// Consider waiting for relay OK response before marking as published.
|
||||
relayManager.send(event)
|
||||
relayManager.publish(event)
|
||||
draftStore.markPublished(slug)
|
||||
onPublished()
|
||||
} catch (e: Exception) {
|
||||
|
||||
+2
-2
@@ -222,7 +222,7 @@ fun ArticleReaderScreen(
|
||||
}
|
||||
}
|
||||
},
|
||||
onEose = { _, _ ->
|
||||
onCaughtUp = { _, _ ->
|
||||
eoseReceived = true
|
||||
},
|
||||
)
|
||||
@@ -335,7 +335,7 @@ fun ArticleReaderScreen(
|
||||
.toSet()
|
||||
}
|
||||
},
|
||||
onEose = { _, _ -> },
|
||||
onCaughtUp = { _, _ -> },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
||||
+3
-3
@@ -168,7 +168,7 @@ fun BookmarksScreen(
|
||||
publicBookmarkIds = pubIds
|
||||
}
|
||||
},
|
||||
onEose = { _, _ ->
|
||||
onCaughtUp = { _, _ ->
|
||||
hasReceivedEose = true
|
||||
isLoading = false
|
||||
},
|
||||
@@ -214,7 +214,7 @@ fun BookmarksScreen(
|
||||
subscriptionsCoordinator?.consumeEvent(event, relay)
|
||||
publicEventState.addItem(event)
|
||||
},
|
||||
onEose = { _, _ -> },
|
||||
onCaughtUp = { _, _ -> },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
@@ -236,7 +236,7 @@ fun BookmarksScreen(
|
||||
subscriptionsCoordinator?.consumeEvent(event, relay)
|
||||
privateEventState.addItem(event)
|
||||
},
|
||||
onEose = { _, _ -> },
|
||||
onCaughtUp = { _, _ -> },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
||||
@@ -170,7 +170,7 @@ fun FeedScreen(
|
||||
val connectedRelays by relayManager.connectedRelays.collectAsState()
|
||||
val followedUsers by localCache.followedUsers.collectAsState()
|
||||
|
||||
// Available relay URLs — openReqSubscription triggers connection on-demand
|
||||
// Available relay URLs — subscribe triggers connection on-demand
|
||||
val allRelayUrls = remember(relayStatuses) { relayStatuses.keys }
|
||||
|
||||
var replyToEvent by remember { mutableStateOf<Event?>(null) }
|
||||
|
||||
@@ -72,7 +72,7 @@ import com.vitorpamplona.amethyst.desktop.nwc.NwcPaymentHandler
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.IRequestListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.SubscriptionListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent
|
||||
@@ -436,10 +436,10 @@ private suspend fun fetchMetadataForUsers(
|
||||
filters = filters,
|
||||
relays = relays,
|
||||
listener =
|
||||
object : IRequestListener {
|
||||
object : SubscriptionListener {
|
||||
override fun onEvent(
|
||||
event: Event,
|
||||
isLive: Boolean,
|
||||
isRealTime: Boolean,
|
||||
relay: NormalizedRelayUrl,
|
||||
forFilters: List<Filter>?,
|
||||
) {
|
||||
@@ -457,7 +457,7 @@ private suspend fun fetchMetadataForUsers(
|
||||
}
|
||||
}
|
||||
|
||||
override fun onEose(
|
||||
override fun onCaughtUp(
|
||||
relay: NormalizedRelayUrl,
|
||||
forFilters: List<Filter>?,
|
||||
) {
|
||||
@@ -1058,10 +1058,10 @@ private suspend fun fetchUserLightningAddress(
|
||||
filters = filters,
|
||||
relays = relays,
|
||||
listener =
|
||||
object : IRequestListener {
|
||||
object : SubscriptionListener {
|
||||
override fun onEvent(
|
||||
event: Event,
|
||||
isLive: Boolean,
|
||||
isRealTime: Boolean,
|
||||
relay: NormalizedRelayUrl,
|
||||
forFilters: List<Filter>?,
|
||||
) {
|
||||
@@ -1078,7 +1078,7 @@ private suspend fun fetchUserLightningAddress(
|
||||
}
|
||||
}
|
||||
|
||||
override fun onEose(
|
||||
override fun onCaughtUp(
|
||||
relay: NormalizedRelayUrl,
|
||||
forFilters: List<Filter>?,
|
||||
) {
|
||||
|
||||
+1
-1
@@ -228,7 +228,7 @@ fun NotificationsScreen(
|
||||
|
||||
notificationState.addItem(notification)
|
||||
},
|
||||
onEose = { _, _ ->
|
||||
onCaughtUp = { _, _ ->
|
||||
eoseReceivedCount++
|
||||
},
|
||||
)
|
||||
|
||||
@@ -261,7 +261,7 @@ fun ReadsScreen(
|
||||
eventState.addItem(event)
|
||||
}
|
||||
},
|
||||
onEose = { _, _ ->
|
||||
onCaughtUp = { _, _ ->
|
||||
eoseReceivedCount++
|
||||
},
|
||||
)
|
||||
@@ -277,7 +277,7 @@ fun ReadsScreen(
|
||||
eventState.addItem(event)
|
||||
}
|
||||
},
|
||||
onEose = { _, _ ->
|
||||
onCaughtUp = { _, _ ->
|
||||
eoseReceivedCount++
|
||||
},
|
||||
)
|
||||
|
||||
@@ -172,7 +172,7 @@ fun SearchScreen(
|
||||
}
|
||||
}
|
||||
|
||||
// NIP-50 people search subscription (use allRelayUrls — openReqSubscription will connect)
|
||||
// NIP-50 people search subscription (use allRelayUrls — subscribe will connect)
|
||||
rememberSubscription(connectedRelays, debouncedQuery, relayManager = relayManager) {
|
||||
if (allRelayUrls.isEmpty() || debouncedQuery.isEmpty) {
|
||||
return@rememberSubscription null
|
||||
@@ -202,7 +202,7 @@ fun SearchScreen(
|
||||
}
|
||||
}
|
||||
},
|
||||
onEose = { relay, _ ->
|
||||
onCaughtUp = { relay, _ ->
|
||||
state.updateRelayState(relay.url, RelaySyncStatus.EOSE_RECEIVED)
|
||||
state.stopSearching("people-search")
|
||||
},
|
||||
@@ -236,7 +236,7 @@ fun SearchScreen(
|
||||
}
|
||||
}
|
||||
},
|
||||
onEose = { relay, _ ->
|
||||
onCaughtUp = { relay, _ ->
|
||||
state.updateRelayState(relay.url, RelaySyncStatus.EOSE_RECEIVED)
|
||||
state.stopSearching("adv-search")
|
||||
},
|
||||
|
||||
@@ -131,7 +131,7 @@ fun ThreadScreen(
|
||||
subscriptionsCoordinator?.consumeEvent(event, relay)
|
||||
levelCache[event.id] = 0
|
||||
},
|
||||
onEose = { _, _ ->
|
||||
onCaughtUp = { _, _ ->
|
||||
rootNoteEoseReceived = true
|
||||
},
|
||||
)
|
||||
@@ -149,7 +149,7 @@ fun ThreadScreen(
|
||||
onEvent = { event, _, relay, _ ->
|
||||
subscriptionsCoordinator?.consumeEvent(event, relay)
|
||||
},
|
||||
onEose = { _, _ -> },
|
||||
onCaughtUp = { _, _ -> },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
||||
+7
-7
@@ -190,7 +190,7 @@ fun UserProfileScreen(
|
||||
onEvent = { event, _, relay, _ ->
|
||||
subscriptionsCoordinator?.consumeEvent(event, relay)
|
||||
},
|
||||
onEose = { _, _ -> },
|
||||
onCaughtUp = { _, _ -> },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
@@ -232,7 +232,7 @@ fun UserProfileScreen(
|
||||
contactListLoaded = true
|
||||
}
|
||||
},
|
||||
onEose = { _, _ ->
|
||||
onCaughtUp = { _, _ ->
|
||||
eoseReceivedCount++
|
||||
|
||||
// Wait for EOSE from at least 2 relays or all relays before enabling button
|
||||
@@ -294,7 +294,7 @@ fun UserProfileScreen(
|
||||
localCache.cacheFollowingCount(pubKeyHex, count)
|
||||
}
|
||||
},
|
||||
onEose = { _, _ -> },
|
||||
onCaughtUp = { _, _ -> },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
@@ -329,7 +329,7 @@ fun UserProfileScreen(
|
||||
localCache.cacheFollowerCount(pubKeyHex, count)
|
||||
}
|
||||
},
|
||||
onEose = { _, _ -> },
|
||||
onCaughtUp = { _, _ -> },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
@@ -356,7 +356,7 @@ fun UserProfileScreen(
|
||||
pictureEvents.add(event)
|
||||
}
|
||||
},
|
||||
onEose = { _, _ -> },
|
||||
onCaughtUp = { _, _ -> },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
@@ -383,7 +383,7 @@ fun UserProfileScreen(
|
||||
articleEvents.add(event)
|
||||
}
|
||||
},
|
||||
onEose = { _, _ -> },
|
||||
onCaughtUp = { _, _ -> },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
@@ -410,7 +410,7 @@ fun UserProfileScreen(
|
||||
highlightEvents.add(event)
|
||||
}
|
||||
},
|
||||
onEose = { _, _ -> },
|
||||
onCaughtUp = { _, _ -> },
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
||||
+3
-3
@@ -29,7 +29,7 @@ import com.vitorpamplona.amethyst.desktop.cache.DesktopLocalCache
|
||||
import com.vitorpamplona.amethyst.desktop.network.RelayConnectionManager
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.IRequestListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.SubscriptionListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip04Dm.messages.PrivateDmEvent
|
||||
@@ -161,10 +161,10 @@ class ChatroomListState(
|
||||
)
|
||||
|
||||
val listener =
|
||||
object : IRequestListener {
|
||||
object : SubscriptionListener {
|
||||
override fun onEvent(
|
||||
event: Event,
|
||||
isLive: Boolean,
|
||||
isRealTime: Boolean,
|
||||
relay: NormalizedRelayUrl,
|
||||
forFilters: List<Filter>?,
|
||||
) {
|
||||
|
||||
+4
-4
@@ -22,8 +22,8 @@ package com.vitorpamplona.amethyst.desktop.ui.chats
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.ui.chat.DmBroadcastStatus
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.sendAndWaitForResponseDetailed
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.publishAndConfirmDetailed
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -31,7 +31,7 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
class DmSendTracker(
|
||||
private val client: INostrClient,
|
||||
private val client: NostrClient,
|
||||
) {
|
||||
private val _status = MutableStateFlow<DmBroadcastStatus>(DmBroadcastStatus.Idle)
|
||||
val status: StateFlow<DmBroadcastStatus> = _status.asStateFlow()
|
||||
@@ -56,7 +56,7 @@ class DmSendTracker(
|
||||
val allSuccessful = mutableSetOf<NormalizedRelayUrl>()
|
||||
|
||||
for ((event, relays) in events) {
|
||||
val results = client.sendAndWaitForResponseDetailed(event, relays, 10)
|
||||
val results = client.publishAndConfirmDetailed(event, relays, 10)
|
||||
allSuccessful.addAll(results.filter { it.value }.keys)
|
||||
_status.value = DmBroadcastStatus.Sending(allSuccessful.size, totalRelays)
|
||||
}
|
||||
|
||||
+1
-1
@@ -103,7 +103,7 @@ fun NewDmDialog(
|
||||
}
|
||||
}
|
||||
},
|
||||
onEose = { _, _ ->
|
||||
onCaughtUp = { _, _ ->
|
||||
searchState.endRelaySearch()
|
||||
},
|
||||
)
|
||||
|
||||
Vendored
+14
-14
@@ -27,9 +27,9 @@ import com.vitorpamplona.amethyst.desktop.subscriptions.DesktopRelaySubscription
|
||||
import com.vitorpamplona.amethyst.desktop.viewmodels.DesktopFeedViewModel
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.IRequestListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.RelayConnectionListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.SubscriptionListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
@@ -50,7 +50,7 @@ import kotlin.test.assertTrue
|
||||
/**
|
||||
* Integration tests for the Coordinator → Cache → ViewModel pipeline.
|
||||
*
|
||||
* These tests use a stub INostrClient (no real relay connections) and exercise
|
||||
* These tests use a stub NostrClient (no real relay connections) and exercise
|
||||
* the full event consumption path through DesktopRelaySubscriptionsCoordinator.
|
||||
*
|
||||
* Key invariant being tested: when coordinator.consumeEvent() is called,
|
||||
@@ -65,11 +65,11 @@ class CoordinatorPipelineTest {
|
||||
private suspend fun waitForBundler() = delay(600)
|
||||
|
||||
/**
|
||||
* Stub INostrClient — records subscription calls but doesn't connect to any relay.
|
||||
* Stub NostrClient — records subscription calls but doesn't connect to any relay.
|
||||
* This lets us test the coordinator's event routing without network dependencies.
|
||||
*/
|
||||
private class StubNostrClient : INostrClient {
|
||||
val openedSubs = mutableMapOf<String, Pair<Map<NormalizedRelayUrl, List<Filter>>, IRequestListener?>>()
|
||||
private class StubNostrClient : NostrClient {
|
||||
val openedSubs = mutableMapOf<String, Pair<Map<NormalizedRelayUrl, List<Filter>>, SubscriptionListener?>>()
|
||||
|
||||
override fun connectedRelaysFlow(): StateFlow<Set<NormalizedRelayUrl>> = MutableStateFlow(emptySet())
|
||||
|
||||
@@ -88,17 +88,17 @@ class CoordinatorPipelineTest {
|
||||
|
||||
override fun isActive() = false
|
||||
|
||||
override fun renewFilters(relay: IRelayClient) {}
|
||||
override fun syncFilters(relay: IRelayClient) {}
|
||||
|
||||
override fun openReqSubscription(
|
||||
override fun subscribe(
|
||||
subId: String,
|
||||
filters: Map<NormalizedRelayUrl, List<Filter>>,
|
||||
listener: IRequestListener?,
|
||||
listener: SubscriptionListener?,
|
||||
) {
|
||||
openedSubs[subId] = filters to listener
|
||||
}
|
||||
|
||||
override fun queryCount(
|
||||
override fun count(
|
||||
subId: String,
|
||||
filters: Map<NormalizedRelayUrl, List<Filter>>,
|
||||
) {}
|
||||
@@ -112,9 +112,9 @@ class CoordinatorPipelineTest {
|
||||
relayList: Set<NormalizedRelayUrl>,
|
||||
) {}
|
||||
|
||||
override fun subscribe(listener: IRelayClientListener) {}
|
||||
override fun addConnectionListener(listener: RelayConnectionListener) {}
|
||||
|
||||
override fun unsubscribe(listener: IRelayClientListener) {}
|
||||
override fun removeConnectionListener(listener: RelayConnectionListener) {}
|
||||
|
||||
override fun getReqFiltersOrNull(subId: String): Map<NormalizedRelayUrl, List<Filter>>? = null
|
||||
|
||||
@@ -376,7 +376,7 @@ class CoordinatorPipelineTest {
|
||||
val noteIds = listOf("n1".padEnd(64, '0'))
|
||||
val subId = coordinator.requestInteractions(noteIds, setOf(relayUrl))
|
||||
|
||||
// openReqSubscription is launched in scope — wait for it
|
||||
// subscribe is launched in scope — wait for it
|
||||
delay(200)
|
||||
|
||||
assertTrue(client.openedSubs.containsKey(subId), "Interaction subscription should be opened")
|
||||
|
||||
Reference in New Issue
Block a user