Merge branch 'main' into claude/nip42-relay-auth-P878m
This commit is contained in:
+97
-3
@@ -23,13 +23,26 @@ package com.vitorpamplona.quartz.experimental.attestations.attestation
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.experimental.attestations.attestation.tags.AttestationStatus
|
||||
import com.vitorpamplona.quartz.experimental.attestations.attestation.tags.Validity
|
||||
import com.vitorpamplona.quartz.experimental.attestations.request.AttestationRequestEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
|
||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlinx.serialization.json.JsonNull.content
|
||||
|
||||
@Immutable
|
||||
class AttestationEvent(
|
||||
@@ -39,7 +52,22 @@ class AttestationEvent(
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig),
|
||||
EventHintProvider,
|
||||
AddressHintProvider,
|
||||
PubKeyHintProvider {
|
||||
override fun eventHints(): List<EventIdHint> = tags.mapNotNull(ETag::parseAsHint)
|
||||
|
||||
override fun linkedEventIds(): List<HexKey> = tags.mapNotNull(ETag::parseId)
|
||||
|
||||
override fun addressHints(): List<AddressHint> = tags.mapNotNull(ATag::parseAsHint)
|
||||
|
||||
override fun linkedAddressIds(): List<String> = tags.mapNotNull(ATag::parseAddressId)
|
||||
|
||||
override fun pubKeyHints() = tags.mapNotNull(PTag::parseAsHint)
|
||||
|
||||
override fun linkedPubKeys() = tags.mapNotNull(PTag::parseKey)
|
||||
|
||||
fun validity() = tags.validity()
|
||||
|
||||
fun status() = tags.status()
|
||||
@@ -50,25 +78,91 @@ class AttestationEvent(
|
||||
|
||||
fun request() = tags.request()
|
||||
|
||||
fun requestId() = tags.requestId()
|
||||
|
||||
fun requestAddress() = tags.requestAddress()
|
||||
|
||||
fun isRevoked() = status() == AttestationStatus.REVOKED
|
||||
|
||||
fun assertionAddrId() = tags.firstNotNullOfOrNull(ATag::parseAddressId)
|
||||
|
||||
fun assertionAddress() = tags.firstNotNullOfOrNull(ATag::parseAddress)
|
||||
|
||||
fun assertionATag() = tags.firstNotNullOfOrNull(ATag::parse)
|
||||
|
||||
fun assertionEventId() = tags.firstNotNullOfOrNull(ETag::parseId)
|
||||
|
||||
fun assertionETag() = tags.firstNotNullOfOrNull(ETag::parse)
|
||||
|
||||
fun assertionPubkey() = tags.firstNotNullOfOrNull(PTag::parseKey)
|
||||
|
||||
fun assertionPTag() = tags.firstNotNullOfOrNull(PTag::parse)
|
||||
|
||||
companion object {
|
||||
const val KIND = 31871
|
||||
const val ALT_DESCRIPTION = "Attestation"
|
||||
|
||||
fun build(
|
||||
fun buildEvent(
|
||||
dTagId: String,
|
||||
about: EventHintBundle<Event>,
|
||||
content: String = "",
|
||||
validity: Validity? = null,
|
||||
status: AttestationStatus? = null,
|
||||
validFrom: Long? = null,
|
||||
validTo: Long? = null,
|
||||
requestAddress: String? = null,
|
||||
requestAddress: EventHintBundle<AttestationRequestEvent>? = null,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<AttestationEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, content, createdAt) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
dTag(dTagId)
|
||||
about(about)
|
||||
validity?.let { validity(it) }
|
||||
status?.let { status(it) }
|
||||
validFrom?.let { validFrom(it) }
|
||||
validTo?.let { validTo(it) }
|
||||
requestAddress?.let { request(it) }
|
||||
initializer()
|
||||
}
|
||||
|
||||
fun buildReplaceable(
|
||||
dTagId: String,
|
||||
about: EventHintBundle<BaseReplaceableEvent>,
|
||||
content: String = "",
|
||||
validity: Validity? = null,
|
||||
status: AttestationStatus? = null,
|
||||
validFrom: Long? = null,
|
||||
validTo: Long? = null,
|
||||
requestAddress: EventHintBundle<AttestationRequestEvent>? = null,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<AttestationEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, content, createdAt) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
dTag(dTagId)
|
||||
aboutReplaceable(about)
|
||||
validity?.let { validity(it) }
|
||||
status?.let { status(it) }
|
||||
validFrom?.let { validFrom(it) }
|
||||
validTo?.let { validTo(it) }
|
||||
requestAddress?.let { request(it) }
|
||||
initializer()
|
||||
}
|
||||
|
||||
fun buildAddress(
|
||||
dTagId: String,
|
||||
about: EventHintBundle<BaseAddressableEvent>,
|
||||
content: String = "",
|
||||
validity: Validity? = null,
|
||||
status: AttestationStatus? = null,
|
||||
validFrom: Long? = null,
|
||||
validTo: Long? = null,
|
||||
requestAddress: EventHintBundle<AttestationRequestEvent>? = null,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<AttestationEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, content, createdAt) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
dTag(dTagId)
|
||||
aboutAddressable(about)
|
||||
validity?.let { validity(it) }
|
||||
status?.let { status(it) }
|
||||
validFrom?.let { validFrom(it) }
|
||||
|
||||
+14
-1
@@ -27,7 +27,14 @@ import com.vitorpamplona.quartz.experimental.attestations.attestation.tags.Valid
|
||||
import com.vitorpamplona.quartz.experimental.attestations.attestation.tags.ValidToTag
|
||||
import com.vitorpamplona.quartz.experimental.attestations.attestation.tags.Validity
|
||||
import com.vitorpamplona.quartz.experimental.attestations.attestation.tags.ValidityTag
|
||||
import com.vitorpamplona.quartz.experimental.attestations.request.AttestationRequestEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||
|
||||
fun TagArrayBuilder<AttestationEvent>.validity(validity: Validity) = addUnique(ValidityTag.assemble(validity))
|
||||
|
||||
@@ -37,4 +44,10 @@ fun TagArrayBuilder<AttestationEvent>.validFrom(timestamp: Long) = addUnique(Val
|
||||
|
||||
fun TagArrayBuilder<AttestationEvent>.validTo(timestamp: Long) = addUnique(ValidToTag.assemble(timestamp))
|
||||
|
||||
fun TagArrayBuilder<AttestationEvent>.request(requestAddress: String) = addUnique(RequestTag.assemble(requestAddress))
|
||||
fun TagArrayBuilder<AttestationEvent>.request(request: EventHintBundle<AttestationRequestEvent>) = addUnique(RequestTag.assemble(request.event.address(), request.relay))
|
||||
|
||||
fun TagArrayBuilder<AttestationEvent>.aboutAddressable(request: EventHintBundle<BaseAddressableEvent>) = addUnique(ATag.assemble(request.event.address(), request.relay))
|
||||
|
||||
fun TagArrayBuilder<AttestationEvent>.aboutReplaceable(request: EventHintBundle<BaseReplaceableEvent>) = addUnique(ATag.assemble(request.event.address(), request.relay))
|
||||
|
||||
fun TagArrayBuilder<AttestationEvent>.about(request: EventHintBundle<Event>) = addUnique(ETag.assemble(request.event.id, request.relay, request.event.pubKey))
|
||||
|
||||
+4
@@ -36,3 +36,7 @@ fun TagArray.validFrom() = firstNotNullOfOrNull(ValidFromTag::parse)
|
||||
fun TagArray.validTo() = firstNotNullOfOrNull(ValidToTag::parse)
|
||||
|
||||
fun TagArray.request() = firstNotNullOfOrNull(RequestTag::parse)
|
||||
|
||||
fun TagArray.requestId() = firstNotNullOfOrNull(RequestTag::parseAddressId)
|
||||
|
||||
fun TagArray.requestAddress() = firstNotNullOfOrNull(RequestTag::parseAddress)
|
||||
|
||||
+90
-4
@@ -20,22 +20,108 @@
|
||||
*/
|
||||
package com.vitorpamplona.quartz.experimental.attestations.attestation.tags
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Address
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||
import com.vitorpamplona.quartz.nip72ModCommunities.approval.tags.ApprovedAddressTag
|
||||
import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent
|
||||
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
||||
import com.vitorpamplona.quartz.utils.ensure
|
||||
|
||||
class RequestTag {
|
||||
class RequestTag(
|
||||
val address: Address,
|
||||
val relayHint: NormalizedRelayUrl? = null,
|
||||
) {
|
||||
fun toTag() = Address.assemble(address.kind, address.pubKeyHex, address.dTag)
|
||||
|
||||
fun toTagArray() = assemble(address, relayHint)
|
||||
|
||||
fun toTagIdOnly() = assemble(address, null)
|
||||
|
||||
companion object {
|
||||
const val TAG_NAME = "request"
|
||||
|
||||
fun isTag(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
||||
fun isTagged(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && !Address.isOfKind(tag[1], CommunityDefinitionEvent.KIND_STR)
|
||||
|
||||
fun parse(tag: Array<String>): String? {
|
||||
fun isTagged(
|
||||
tag: Array<String>,
|
||||
addressId: String,
|
||||
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == addressId
|
||||
|
||||
fun isTagged(
|
||||
tag: Array<String>,
|
||||
address: ApprovedAddressTag,
|
||||
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == address.toTag()
|
||||
|
||||
fun isIn(
|
||||
tag: Array<String>,
|
||||
addressIds: Set<String>,
|
||||
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in addressIds
|
||||
|
||||
fun parse(tag: Array<String>): ApprovedAddressTag? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(!Address.isOfKind(tag[1], CommunityDefinitionEvent.KIND_STR)) { return null }
|
||||
|
||||
val address = Address.parse(tag[1]) ?: return null
|
||||
val relayHint = tag.getOrNull(2)?.let { RelayUrlNormalizer.normalizeOrNull(it) }
|
||||
return ApprovedAddressTag(address, relayHint)
|
||||
}
|
||||
|
||||
fun parseValidAddress(tag: Array<String>): String? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(!Address.isOfKind(tag[1], CommunityDefinitionEvent.KIND_STR)) { return null }
|
||||
return Address.parse(tag[1])?.toValue()
|
||||
}
|
||||
|
||||
fun parseAddress(tag: Array<String>): Address? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].isNotEmpty()) { return null }
|
||||
val address = Address.parse(tag[1]) ?: return null
|
||||
ensure(address.kind != CommunityDefinitionEvent.KIND) { return null }
|
||||
return address
|
||||
}
|
||||
|
||||
fun parseAddressId(tag: Array<String>): String? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(!Address.isOfKind(tag[1], CommunityDefinitionEvent.KIND_STR)) { return null }
|
||||
return tag[1]
|
||||
}
|
||||
|
||||
fun assemble(requestAddress: String) = arrayOf(TAG_NAME, requestAddress)
|
||||
fun parseAsHint(tag: Array<String>): AddressHint? {
|
||||
ensure(tag.has(2)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(!Address.isOfKind(tag[1], CommunityDefinitionEvent.KIND_STR)) { return null }
|
||||
ensure(tag[1].contains(':')) { return null }
|
||||
ensure(tag[2].isNotEmpty()) { return null }
|
||||
|
||||
val relayHint = RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||
ensure(relayHint != null) { return null }
|
||||
|
||||
return AddressHint(tag[1], relayHint)
|
||||
}
|
||||
|
||||
fun assemble(
|
||||
aTagId: HexKey,
|
||||
relay: NormalizedRelayUrl?,
|
||||
) = arrayOfNotNull(TAG_NAME, aTagId, relay?.url)
|
||||
|
||||
fun assemble(
|
||||
address: Address,
|
||||
relay: NormalizedRelayUrl?,
|
||||
) = arrayOfNotNull(TAG_NAME, address.toValue(), relay?.url)
|
||||
|
||||
fun assemble(
|
||||
kind: Int,
|
||||
pubKey: String,
|
||||
dTag: String,
|
||||
relay: NormalizedRelayUrl?,
|
||||
) = assemble(Address.assemble(kind, pubKey, dTag), relay)
|
||||
}
|
||||
}
|
||||
|
||||
+81
-2
@@ -21,13 +21,27 @@
|
||||
package com.vitorpamplona.quartz.experimental.attestations.request
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.experimental.attestations.request.attestorPubKeys
|
||||
import com.vitorpamplona.quartz.experimental.attestations.request.cashuToken
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
|
||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlin.let
|
||||
|
||||
@Immutable
|
||||
class AttestationRequestEvent(
|
||||
@@ -37,15 +51,45 @@ class AttestationRequestEvent(
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig),
|
||||
EventHintProvider,
|
||||
AddressHintProvider,
|
||||
PubKeyHintProvider {
|
||||
override fun eventHints(): List<EventIdHint> = tags.mapNotNull(ETag::parseAsHint)
|
||||
|
||||
override fun linkedEventIds(): List<HexKey> = tags.mapNotNull(ETag::parseId)
|
||||
|
||||
override fun addressHints(): List<AddressHint> = tags.mapNotNull(ATag::parseAsHint)
|
||||
|
||||
override fun linkedAddressIds(): List<String> = tags.mapNotNull(ATag::parseAddressId)
|
||||
|
||||
override fun pubKeyHints() = tags.mapNotNull(PTag::parseAsHint)
|
||||
|
||||
override fun linkedPubKeys() = tags.mapNotNull(PTag::parseKey)
|
||||
|
||||
fun cashuToken() = tags.cashuToken()
|
||||
|
||||
fun assertionAddrId() = tags.firstNotNullOfOrNull(ATag::parseAddressId)
|
||||
|
||||
fun assertionAddress() = tags.firstNotNullOfOrNull(ATag::parseAddress)
|
||||
|
||||
fun assertionATag() = tags.firstNotNullOfOrNull(ATag::parse)
|
||||
|
||||
fun assertionEventId() = tags.firstNotNullOfOrNull(ETag::parseId)
|
||||
|
||||
fun assertionETag() = tags.firstNotNullOfOrNull(ETag::parse)
|
||||
|
||||
fun assertionPubkey() = tags.firstNotNullOfOrNull(PTag::parseKey)
|
||||
|
||||
fun assertionPTag() = tags.firstNotNullOfOrNull(PTag::parse)
|
||||
|
||||
companion object {
|
||||
const val KIND = 31872
|
||||
const val ALT_DESCRIPTION = "Attestation Request"
|
||||
|
||||
fun build(
|
||||
fun buildEvent(
|
||||
dTagId: String,
|
||||
about: EventHintBundle<Event>,
|
||||
content: String = "",
|
||||
attestorPubKeys: List<HexKey> = emptyList(),
|
||||
cashuToken: String? = null,
|
||||
@@ -54,6 +98,41 @@ class AttestationRequestEvent(
|
||||
) = eventTemplate(KIND, content, createdAt) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
dTag(dTagId)
|
||||
about(about)
|
||||
attestorPubKeys(attestorPubKeys)
|
||||
cashuToken?.let { cashuToken(it) }
|
||||
initializer()
|
||||
}
|
||||
|
||||
fun buildReplaceable(
|
||||
dTagId: String,
|
||||
about: EventHintBundle<BaseReplaceableEvent>,
|
||||
content: String = "",
|
||||
attestorPubKeys: List<HexKey> = emptyList(),
|
||||
cashuToken: String? = null,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<AttestationRequestEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, content, createdAt) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
dTag(dTagId)
|
||||
aboutReplaceable(about)
|
||||
attestorPubKeys(attestorPubKeys)
|
||||
cashuToken?.let { cashuToken(it) }
|
||||
initializer()
|
||||
}
|
||||
|
||||
fun buildAddress(
|
||||
dTagId: String,
|
||||
about: EventHintBundle<BaseAddressableEvent>,
|
||||
content: String = "",
|
||||
attestorPubKeys: List<HexKey> = emptyList(),
|
||||
cashuToken: String? = null,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<AttestationRequestEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, content, createdAt) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
dTag(dTagId)
|
||||
aboutAddressable(about)
|
||||
attestorPubKeys(attestorPubKeys)
|
||||
cashuToken?.let { cashuToken(it) }
|
||||
initializer()
|
||||
|
||||
+12
@@ -21,10 +21,22 @@
|
||||
package com.vitorpamplona.quartz.experimental.attestations.request
|
||||
|
||||
import com.vitorpamplona.quartz.experimental.attestations.request.tags.CashuTokenTag
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
|
||||
|
||||
fun TagArrayBuilder<AttestationRequestEvent>.attestorPubKeys(pubKeys: List<HexKey>) = addAll(pubKeys.map { PTag.assemble(it, null) })
|
||||
|
||||
fun TagArrayBuilder<AttestationRequestEvent>.cashuToken(token: String) = addUnique(CashuTokenTag.assemble(token))
|
||||
|
||||
fun TagArrayBuilder<AttestationRequestEvent>.aboutAddressable(request: EventHintBundle<BaseAddressableEvent>) = addUnique(ATag.assemble(request.event.address(), request.relay))
|
||||
|
||||
fun TagArrayBuilder<AttestationRequestEvent>.aboutReplaceable(request: EventHintBundle<BaseReplaceableEvent>) = addUnique(ATag.assemble(request.event.address(), request.relay))
|
||||
|
||||
fun TagArrayBuilder<AttestationRequestEvent>.about(request: EventHintBundle<Event>) = addUnique(ETag.assemble(request.event.id, request.relay, request.event.pubKey))
|
||||
|
||||
+10
@@ -26,6 +26,16 @@ import com.vitorpamplona.quartz.nip01Core.store.IEventStore
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
||||
/**
|
||||
* A reactive event store that combines historical data retrieval with live event streaming.
|
||||
*
|
||||
* This class wraps an [IEventStore] to provide real-time updates. When a [query] is executed,
|
||||
* it first replays all matching historical events from the underlying store, signals the
|
||||
* End of Stored Events (EOSE), and then continues to stream matching new events as they
|
||||
* are inserted.
|
||||
*
|
||||
* @property store The underlying persistent storage for events.
|
||||
*/
|
||||
class LiveEventStore(
|
||||
private val store: IEventStore,
|
||||
) {
|
||||
|
||||
+3
-7
@@ -29,14 +29,10 @@ import kotlinx.coroutines.cancel
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
* This class manages per-connection subscriptions as coroutines. Each
|
||||
* subscription (REQ) launches a child coroutine that first replays stored
|
||||
* events matching the filters, sends EOSE, and then streams live events.
|
||||
* Closing a subscription (CLOSE) immediately cancels its coroutine.
|
||||
* Represents a Nostr relay server that manages client connections, event storage, and verification.
|
||||
*
|
||||
* The server is transport-agnostic: callers feed incoming JSON via
|
||||
* [RelaySession.receive] and receive outgoing JSON via the [RelaySession.send] callback
|
||||
* provided to [connect]. This allows use with any WebSocket library.
|
||||
* This class acts as the central coordinator for a relay server, handling the lifecycle of [RelaySession]s
|
||||
* and providing access to the underlying event store.
|
||||
*
|
||||
* @param store The [IEventStore] backing this relay.
|
||||
* @param policyBuilder Controls requirements for relay commands.
|
||||
|
||||
+2
-1
@@ -41,7 +41,8 @@ import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* Represents a single connected client with its active subscriptions.
|
||||
* Represents an active session between a Nostr client and the relay.
|
||||
* Each one of these is a connection that can hold many subscriptions
|
||||
*/
|
||||
class RelaySession(
|
||||
private val store: LiveEventStore,
|
||||
|
||||
+7
-1
@@ -24,6 +24,7 @@ import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.aTag.aTag
|
||||
@@ -47,7 +48,12 @@ class CalendarRSVPEvent(
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig),
|
||||
PubKeyHintProvider {
|
||||
override fun pubKeyHints() = tags.mapNotNull(PTag::parseAsHint)
|
||||
|
||||
override fun linkedPubKeys() = tags.mapNotNull(PTag::parseKey)
|
||||
|
||||
fun status() = tags.firstNotNullOfOrNull(RSVPStatusTag.Companion::parse)
|
||||
|
||||
fun statusValue() = tags.firstNotNullOfOrNull(RSVPStatusTag.Companion::parseValue)
|
||||
|
||||
Reference in New Issue
Block a user