feat: add NIP-77 negentropy sync support
Add support for NIP-77 (Negentropy Syncing) protocol messages using the negentropy-kmp library for efficient set reconciliation between client and relay. New files: - NegOpenCmd, NegMsgCmd, NegCloseCmd: Client-to-relay commands - NegMsgMessage, NegErrMessage: Relay-to-client messages - NegentropySession: Client-side reconciliation orchestrator - NegentropyServerSession: Server-side reconciliation handler - NegentropyManager: High-level sync manager with listener callbacks Updated serializers: - Jackson MessageSerializer/Deserializer for NEG-MSG, NEG-ERR - Jackson CommandSerializer/Deserializer for NEG-OPEN, NEG-MSG, NEG-CLOSE - Kotlin MessageKSerializer/CommandKSerializer for all NIP-77 types Compatible with strfry relay's negentropy implementation via the negentropy-kmp library which implements the same Protocol V1 spec. https://claude.ai/code/session_01Dc6W1G1jURAAR9kzyVvk6g
This commit is contained in:
+16
@@ -26,6 +26,8 @@ import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
|
||||
import com.vitorpamplona.quartz.nip01Core.jackson.EventDeserializer
|
||||
import com.vitorpamplona.quartz.nip77Negentropy.NegErrMessage
|
||||
import com.vitorpamplona.quartz.nip77Negentropy.NegMsgMessage
|
||||
|
||||
class MessageDeserializer : StdDeserializer<Message>(Message::class.java) {
|
||||
val eventDeserializer = EventDeserializer()
|
||||
@@ -101,6 +103,20 @@ class MessageDeserializer : StdDeserializer<Message>(Message::class.java) {
|
||||
)
|
||||
}
|
||||
|
||||
NegMsgMessage.LABEL -> {
|
||||
NegMsgMessage(
|
||||
subId = jp.nextTextValue(),
|
||||
message = jp.nextTextValue(),
|
||||
)
|
||||
}
|
||||
|
||||
NegErrMessage.LABEL -> {
|
||||
NegErrMessage(
|
||||
subId = jp.nextTextValue(),
|
||||
reason = jp.nextTextValue() ?: "",
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
throw IllegalArgumentException("Message $type is not supported")
|
||||
}
|
||||
|
||||
+12
@@ -24,6 +24,8 @@ import com.fasterxml.jackson.core.JsonGenerator
|
||||
import com.fasterxml.jackson.databind.SerializerProvider
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer
|
||||
import com.vitorpamplona.quartz.nip01Core.jackson.EventSerializer
|
||||
import com.vitorpamplona.quartz.nip77Negentropy.NegErrMessage
|
||||
import com.vitorpamplona.quartz.nip77Negentropy.NegMsgMessage
|
||||
|
||||
class MessageSerializer : StdSerializer<Message>(Message::class.java) {
|
||||
val eventSerializer = EventSerializer()
|
||||
@@ -75,6 +77,16 @@ class MessageSerializer : StdSerializer<Message>(Message::class.java) {
|
||||
is EoseMessage -> {
|
||||
gen.writeString(msg.subId)
|
||||
}
|
||||
|
||||
is NegMsgMessage -> {
|
||||
gen.writeString(msg.subId)
|
||||
gen.writeString(msg.message)
|
||||
}
|
||||
|
||||
is NegErrMessage -> {
|
||||
gen.writeString(msg.subId)
|
||||
gen.writeString(msg.reason)
|
||||
}
|
||||
}
|
||||
|
||||
gen.writeEndArray()
|
||||
|
||||
+30
@@ -29,6 +29,9 @@ import com.vitorpamplona.quartz.nip01Core.jackson.EventDeserializer
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.ManualFilterDeserializer
|
||||
import com.vitorpamplona.quartz.nip42RelayAuth.RelayAuthEvent
|
||||
import com.vitorpamplona.quartz.nip77Negentropy.NegCloseCmd
|
||||
import com.vitorpamplona.quartz.nip77Negentropy.NegMsgCmd
|
||||
import com.vitorpamplona.quartz.nip77Negentropy.NegOpenCmd
|
||||
|
||||
class CommandDeserializer : StdDeserializer<Command>(Command::class.java) {
|
||||
val eventDeserializer = EventDeserializer()
|
||||
@@ -97,6 +100,33 @@ class CommandDeserializer : StdDeserializer<Command>(Command::class.java) {
|
||||
)
|
||||
}
|
||||
|
||||
NegOpenCmd.LABEL -> {
|
||||
val subId = jp.nextTextValue()
|
||||
jp.nextToken()
|
||||
val filterObj: ObjectNode = jp.codec.readTree(jp)
|
||||
val filter = ManualFilterDeserializer.fromJson(filterObj)
|
||||
val initialMessage = jp.nextTextValue()
|
||||
|
||||
NegOpenCmd(
|
||||
subId = subId,
|
||||
filter = filter,
|
||||
initialMessage = initialMessage,
|
||||
)
|
||||
}
|
||||
|
||||
NegMsgCmd.LABEL -> {
|
||||
NegMsgCmd(
|
||||
subId = jp.nextTextValue(),
|
||||
message = jp.nextTextValue(),
|
||||
)
|
||||
}
|
||||
|
||||
NegCloseCmd.LABEL -> {
|
||||
NegCloseCmd(
|
||||
subId = jp.nextTextValue(),
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
throw IllegalArgumentException("Message $type is not supported")
|
||||
}
|
||||
|
||||
+18
@@ -25,6 +25,9 @@ import com.fasterxml.jackson.databind.SerializerProvider
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer
|
||||
import com.vitorpamplona.quartz.nip01Core.jackson.EventSerializer
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.FilterSerializer
|
||||
import com.vitorpamplona.quartz.nip77Negentropy.NegCloseCmd
|
||||
import com.vitorpamplona.quartz.nip77Negentropy.NegMsgCmd
|
||||
import com.vitorpamplona.quartz.nip77Negentropy.NegOpenCmd
|
||||
|
||||
class CommandSerializer : StdSerializer<Command>(Command::class.java) {
|
||||
val eventSerializer = EventSerializer()
|
||||
@@ -65,6 +68,21 @@ class CommandSerializer : StdSerializer<Command>(Command::class.java) {
|
||||
}
|
||||
}
|
||||
|
||||
is NegOpenCmd -> {
|
||||
gen.writeString(cmd.subId)
|
||||
filterSerializer.serialize(cmd.filter, gen, provider)
|
||||
gen.writeString(cmd.initialMessage)
|
||||
}
|
||||
|
||||
is NegMsgCmd -> {
|
||||
gen.writeString(cmd.subId)
|
||||
gen.writeString(cmd.message)
|
||||
}
|
||||
|
||||
is NegCloseCmd -> {
|
||||
gen.writeString(cmd.subId)
|
||||
}
|
||||
|
||||
else -> {
|
||||
null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user