Adds simplified methods to create Requests from NostrClient

This commit is contained in:
Vitor Pamplona
2025-10-29 16:51:49 -04:00
parent 40ce627de0
commit b8511b5ac3
5 changed files with 180 additions and 46 deletions

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip01Core.relay.client.reqs
interface IOpenNostrRequest {
fun updateFilter()
fun close()
}

View File

@@ -18,19 +18,20 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip01Core.relay.client
package com.vitorpamplona.quartz.nip01Core.relay.client.reqs
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.IRequestListener
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.utils.RandomInstance
class NostrClientSubscription(
class NostrClientDynamicFilterRequest(
val client: INostrClient,
val filter: () -> Map<NormalizedRelayUrl, List<Filter>> = { emptyMap() },
val filter: () -> Map<NormalizedRelayUrl, List<Filter>>,
val onEvent: (event: Event) -> Unit = {},
) : IRequestListener {
) : IRequestListener,
IOpenNostrRequest {
private val subId = RandomInstance.randomChars(10)
override fun onEvent(
@@ -46,15 +47,16 @@ class NostrClientSubscription(
* Creates or Updates the filter with relays. This method should be called
* everytime the filter changes.
*/
fun updateFilter() = client.openReqSubscription(subId, filter(), this)
override fun updateFilter() = client.openReqSubscription(subId, filter(), this)
fun closeSubscription() = client.close(subId)
fun destroy() {
closeSubscription()
}
override fun close() = client.close(subId)
init {
updateFilter()
}
}
fun INostrClient.req(
filters: () -> Map<NormalizedRelayUrl, List<Filter>>,
onEvent: (event: Event) -> Unit = {},
): IOpenNostrRequest = NostrClientDynamicFilterRequest(this, filters, onEvent)

View File

@@ -0,0 +1,97 @@
/**
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip01Core.relay.client.reqs
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
import com.vitorpamplona.quartz.utils.RandomInstance
class NostrClientStaticFilterRequest(
val client: INostrClient,
val filter: Map<NormalizedRelayUrl, List<Filter>>,
val onEvent: (event: Event) -> Unit = {},
) : IRequestListener,
IOpenNostrRequest {
private val subId = RandomInstance.randomChars(10)
override fun onEvent(
event: Event,
isLive: Boolean,
relay: NormalizedRelayUrl,
forFilters: List<Filter>?,
) {
onEvent(event)
}
/**
* Creates or Updates the filter with relays. This method should be called
* everytime the filter changes.
*/
override fun updateFilter() = client.openReqSubscription(subId, filter, this)
override fun close() = client.close(subId)
init {
updateFilter()
}
}
fun INostrClient.req(
relay: NormalizedRelayUrl,
filters: List<Filter>,
onEvent: (event: Event) -> Unit = {},
): IOpenNostrRequest = NostrClientStaticFilterRequest(this, mapOf(relay to filters), onEvent)
fun INostrClient.req(
relay: NormalizedRelayUrl,
filter: Filter,
onEvent: (event: Event) -> Unit = {},
): IOpenNostrRequest = NostrClientStaticFilterRequest(this, mapOf(relay to listOf(filter)), onEvent)
fun INostrClient.req(
relays: List<NormalizedRelayUrl>,
filters: List<Filter>,
onEvent: (event: Event) -> Unit = {},
): IOpenNostrRequest = NostrClientStaticFilterRequest(this, relays.associateWith { filters }, onEvent)
fun INostrClient.req(
relays: List<NormalizedRelayUrl>,
filter: Filter,
onEvent: (event: Event) -> Unit = {},
): IOpenNostrRequest = NostrClientStaticFilterRequest(this, relays.associateWith { listOf(filter) }, onEvent)
// -----------------------------------
// Helper methods with relay as string
// -----------------------------------
fun INostrClient.req(
relay: String,
filters: List<Filter>,
onEvent: (event: Event) -> Unit = {},
): IOpenNostrRequest = NostrClientStaticFilterRequest(this, mapOf(RelayUrlNormalizer.normalize(relay) to filters), onEvent)
fun INostrClient.req(
relay: String,
filter: Filter,
onEvent: (event: Event) -> Unit = {},
): IOpenNostrRequest = NostrClientStaticFilterRequest(this, mapOf(RelayUrlNormalizer.normalize(relay) to listOf(filter)), onEvent)

View File

@@ -23,9 +23,8 @@ package com.vitorpamplona.quartz.nip01Core.relay
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClientSubscription
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.req
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@@ -48,19 +47,13 @@ class NostrClientSubscriptionTest : BaseNostrClientTest() {
val events = mutableSetOf<Event>()
val sub =
NostrClientSubscription(
client = client,
filter = {
mapOf(
RelayUrlNormalizer.normalize("wss://relay.damus.io") to
listOf(
Filter(
kinds = listOf(MetadataEvent.KIND),
limit = 100,
),
),
)
},
client.req(
relay = "wss://relay.damus.io",
filter =
Filter(
kinds = listOf(MetadataEvent.KIND),
limit = 100,
),
) { event ->
assertEquals(MetadataEvent.KIND, event.kind)
resultChannel.trySend(event)
@@ -75,7 +68,7 @@ class NostrClientSubscriptionTest : BaseNostrClientTest() {
resultChannel.close()
sub.closeSubscription()
sub.close()
client.disconnect()
appScope.cancel()