Merge pull request #1986 from vitorpamplona/claude/simplify-nostrclient-api-ZpOTB

Refactor Nostr client API with clearer naming conventions
This commit is contained in:
Vitor Pamplona
2026-03-28 18:09:12 -04:00
committed by GitHub
84 changed files with 481 additions and 494 deletions
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.commons.chess
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.IRequestListener
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.SubscriptionListener
import com.vitorpamplona.quartz.nip01Core.relay.client.single.newSubId
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -49,7 +49,7 @@ enum class RelayFetchStatus {
/**
* One-shot relay fetch helper for chess events.
*
* Follows the existing INostrClient + IRequestListener + Channel pattern
* Follows the existing INostrClient + SubscriptionListener + Channel pattern
* from quartz (see NostrClientSingleDownloadExt.kt).
*
* Each fetch opens a subscription, collects events until EOSE from all relays,
@@ -62,7 +62,7 @@ class ChessRelayFetchHelper(
/**
* Fetch events matching filters from relays, waiting for EOSE.
*
* @param filters Map of relay → filter list (same format as INostrClient.openReqSubscription)
* @param filters Map of relay → filter list (same format as INostrClient.subscribe)
* @param timeoutMs Max time to wait for relays to respond (default from ChessConfig)
* @param onProgress Optional callback for progress updates per relay
* @return Deduplicated list of events received before timeout/EOSE
@@ -88,7 +88,7 @@ class ChessRelayFetchHelper(
}
val listener =
object : IRequestListener {
object : SubscriptionListener {
override fun onEvent(
event: Event,
isLive: Boolean,
@@ -114,7 +114,7 @@ class ChessRelayFetchHelper(
}
}
client.openReqSubscription(subId, filters, listener)
client.subscribe(subId, filters, listener)
val eoseResult = withTimeoutOrNull(timeoutMs) { allEose.await() }
// Mark timed-out relays
@@ -127,7 +127,7 @@ class ChessRelayFetchHelper(
}
}
client.close(subId)
client.unsubscribe(subId)
return events.values.toList()
}
@@ -25,7 +25,7 @@ import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.req
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.StaticSubscription
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal
@@ -122,14 +122,17 @@ object NostrConnectLoginUseCase {
val deferred = CompletableDeferred<NostrConnectEvent>()
val subscription =
client.req(
relays = relays.toList(),
filter =
Filter(
kinds = listOf(NostrConnectEvent.KIND),
tags = mapOf("p" to listOf(ephemeralPubKey)),
since = TimeUtils.now() - 60,
),
StaticSubscription(
client,
relays.associateWith {
listOf(
Filter(
kinds = listOf(NostrConnectEvent.KIND),
tags = mapOf("p" to listOf(ephemeralPubKey)),
since = TimeUtils.now() - 60,
),
)
},
) { event ->
if (event is NostrConnectEvent && !deferred.isCompleted) {
deferred.complete(event)
@@ -207,7 +210,7 @@ object NostrConnectLoginUseCase {
remoteKey = connectData.signerPubkey,
signer = ephemeralSigner,
)
client.send(ackEvent, relays)
client.publish(ackEvent, relays)
}
private fun generateSecret(): String {
@@ -28,7 +28,7 @@ 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.reqs.SubscriptionListener
import com.vitorpamplona.quartz.nip01Core.relay.client.single.newSubId
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -79,7 +79,7 @@ class FeedMetadataCoordinator(
// Create listener to pass events to the callback
val listener =
if (onEvent != null) {
object : IRequestListener {
object : SubscriptionListener {
override fun onEvent(
event: Event,
isLive: Boolean,
@@ -93,7 +93,7 @@ class FeedMetadataCoordinator(
null
}
client.openReqSubscription(
client.subscribe(
subId = newSubId(),
filters = filterMap,
listener = listener,
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.commons.relayClient.eoseManagers
import com.vitorpamplona.amethyst.commons.service.BundledUpdate
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.IRequestListener
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.SubscriptionListener
import com.vitorpamplona.quartz.nip01Core.relay.client.single.newSubId
import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.SubscriptionController
import kotlinx.coroutines.Dispatchers
@@ -38,7 +38,7 @@ abstract class BaseEoseManager<T>(
fun getSubscription(subId: String) = orchestrator.getSub(subId)
fun requestNewSubscription(listener: IRequestListener) = orchestrator.requestNewSubscription(newSubId(), listener)
fun requestNewSubscription(listener: SubscriptionListener) = orchestrator.requestNewSubscription(newSubId(), listener)
fun dismissSubscription(subId: String) = orchestrator.dismissSubscription(subId)
@@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter
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.client.subscriptions.Subscription
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -82,7 +82,7 @@ abstract class PerKeyEoseManager<T, K : Any>(
*/
open fun newSub(queryState: T): Subscription =
requestNewSubscription(
object : IRequestListener {
object : SubscriptionListener {
override fun onEose(
relay: NormalizedRelayUrl,
forFilters: List<Filter>?,
@@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter
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.utils.TimeUtils
@@ -66,7 +66,7 @@ abstract class SingleSubEoseManager<T>(
val sub =
requestNewSubscription(
object : IRequestListener {
object : SubscriptionListener {
override fun onEose(
relay: NormalizedRelayUrl,
forFilters: List<Filter>?,
@@ -22,8 +22,8 @@ package com.vitorpamplona.amethyst.commons.chess
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.sendAndWaitForResponse
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.IRequestListener
import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.publishAndConfirm
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.SubscriptionListener
import com.vitorpamplona.quartz.nip01Core.relay.client.single.newSubId
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -42,7 +42,7 @@ data class BroadcastResult(
/**
* Helper for broadcasting chess events to relays with reliable delivery.
*
* Uses sendAndWaitForResponse to get actual OK confirmations from relays,
* Uses publishAndConfirm to get actual OK confirmations from relays,
* ensuring the event was actually received and accepted.
*/
class ChessEventBroadcaster(
@@ -84,7 +84,7 @@ class ChessEventBroadcaster(
)
val listener =
object : IRequestListener {
object : SubscriptionListener {
override fun onEvent(
event: Event,
isLive: Boolean,
@@ -100,19 +100,19 @@ class ChessEventBroadcaster(
// Open subscription to all target relays (triggers connection)
val filterMap = targetRelays.associateWith { listOf(dummyFilter) }
client.openReqSubscription(subId, filterMap, listener)
client.subscribe(subId, filterMap, listener)
// Wait for relays to connect (poll with timeout)
waitForRelays(targetRelays, 5000L)
// Close the dummy subscription
client.close(subId)
client.unsubscribe(subId)
}
// Step 3: Send the event and wait for OK responses
val success = client.sendAndWaitForResponse(event, targetRelays, timeoutSeconds)
val success = client.publishAndConfirm(event, targetRelays, timeoutSeconds)
// Note: sendAndWaitForResponse only returns aggregate success (any relay accepted)
// Note: publishAndConfirm only returns aggregate success (any relay accepted)
// We don't have per-relay results, so relayResults is empty
return BroadcastResult(
success = success,