From b229343c73b81d8359aec2cf5e494a66d5625f6a Mon Sep 17 00:00:00 2001 From: nick avlo Date: Sat, 1 Jun 2024 22:05:09 -0700 Subject: [PATCH 01/12] existing\/procedural encoding mechanism refactored to leverage polymorphism --- .../src/main/java/nostr/api/NIP01.java | 8 +- .../src/main/java/nostr/api/Nostr.java | 9 +- .../nostr/api/factory/impl/NIP01Impl.java | 34 +------- .../src/main/java/nostr/client/Client.java | 5 +- .../src/main/java/module-info.java | 3 +- .../command/provider/AuthCommandHandler.java | 13 ++- .../provider/ClosedCommandHandler.java | 13 ++- .../main/java/nostr/event/BaseMessage.java | 6 +- .../java/nostr/event/impl/GenericMessage.java | 27 ++++-- .../event/json/codec/BaseMessageEncoder.java | 85 ------------------- .../CanonicalAuthenticationMessage.java | 37 ++++---- .../nostr/event/message/CloseMessage.java | 25 +++--- .../nostr/event/message/ClosedMessage.java | 20 +++-- .../java/nostr/event/message/EoseMessage.java | 22 +++-- .../nostr/event/message/EventMessage.java | 30 ++++--- .../nostr/event/message/NoticeMessage.java | 21 +++-- .../java/nostr/event/message/OkMessage.java | 29 ++++--- .../message/RelayAuthenticationMessage.java | 19 +++-- .../java/nostr/event/message/ReqMessage.java | 28 ++++-- .../java/nostr/test/json/JsonParseTest.java | 12 +-- 20 files changed, 201 insertions(+), 245 deletions(-) delete mode 100644 nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageEncoder.java diff --git a/nostr-java-api/src/main/java/nostr/api/NIP01.java b/nostr-java-api/src/main/java/nostr/api/NIP01.java index b43365a91..b8c6a26ff 100644 --- a/nostr-java-api/src/main/java/nostr/api/NIP01.java +++ b/nostr-java-api/src/main/java/nostr/api/NIP01.java @@ -9,11 +9,9 @@ import nostr.api.factory.impl.NIP01Impl.CloseMessageFactory; import nostr.api.factory.impl.NIP01Impl.EoseMessageFactory; import nostr.api.factory.impl.NIP01Impl.EphemeralEventFactory; -import nostr.api.factory.impl.NIP01Impl.EventMessageFactory; import nostr.api.factory.impl.NIP01Impl.EventTagFactory; import nostr.api.factory.impl.NIP01Impl.IdentifierTagFactory; import nostr.api.factory.impl.NIP01Impl.MetadataEventFactory; -import nostr.api.factory.impl.NIP01Impl.NoticeMessageFactory; import nostr.api.factory.impl.NIP01Impl.ParameterizedReplaceableEventFactory; import nostr.api.factory.impl.NIP01Impl.PubKeyTagFactory; import nostr.api.factory.impl.NIP01Impl.ReplaceableEventFactory; @@ -226,9 +224,7 @@ public static Filters createFilters(List events, List a * @return an event message */ public static EventMessage createEventMessage(@NonNull IEvent event, @NonNull String subscriptionId) { - var result = new EventMessageFactory(event).create(); - result.setSubscriptionId(subscriptionId); - return result; + return new EventMessage(event, subscriptionId); } /** @@ -271,7 +267,7 @@ public static EoseMessage createEoseMessage(@NonNull String subscriptionId) { * @return a NOTICE message */ public static NoticeMessage createNoticeMessage(@NonNull String message) { - return new NoticeMessageFactory(message).create(); + return new NoticeMessage(message); } /** diff --git a/nostr-java-api/src/main/java/nostr/api/Nostr.java b/nostr-java-api/src/main/java/nostr/api/Nostr.java index 2a5cb26d2..f26db6d14 100644 --- a/nostr-java-api/src/main/java/nostr/api/Nostr.java +++ b/nostr-java-api/src/main/java/nostr/api/Nostr.java @@ -4,6 +4,7 @@ */ package nostr.api; +import com.fasterxml.jackson.core.JsonProcessingException; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.NonNull; @@ -23,7 +24,6 @@ import nostr.event.impl.GenericEvent; import nostr.event.json.codec.BaseEventEncoder; import nostr.event.json.codec.BaseMessageDecoder; -import nostr.event.json.codec.BaseMessageEncoder; import nostr.event.json.codec.BaseTagDecoder; import nostr.event.json.codec.BaseTagEncoder; import nostr.event.json.codec.FiltersDecoder; @@ -204,15 +204,14 @@ public static GenericEvent decodeEvent(@NonNull String json) { * @param message * @param relay */ - public static String encode(@NonNull BaseMessage message, Relay relay) { - final var enc = new BaseMessageEncoder(message, relay); - return enc.encode(); + public static String encode(@NonNull BaseMessage message, Relay relay) throws JsonProcessingException { + return message.encode(); } /** * @param message */ - public static String encode(@NonNull BaseMessage message) { + public static String encode(@NonNull BaseMessage message) throws JsonProcessingException { return Nostr.Json.encode(message, null); } diff --git a/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java b/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java index 9bfec1fcf..8067e3e70 100644 --- a/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java +++ b/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java @@ -15,7 +15,8 @@ import nostr.base.PublicKey; import nostr.base.Relay; import nostr.base.UserProfile; -import nostr.event.BaseTag; +import nostr.event + .BaseTag; import nostr.event.Marker; import nostr.event.impl.EphemeralEvent; import nostr.event.impl.Filters; @@ -120,24 +121,6 @@ public PubKeyTag create() { } } - @Data - @EqualsAndHashCode(callSuper = false) - public static class EventMessageFactory extends MessageFactory { - - private final IEvent event; - private String subscriptionId; - - public EventMessageFactory(@NonNull IEvent event) { - this.event = event; - } - - @Override - public EventMessage create() { - return new EventMessage(event, subscriptionId); - } - - } - @Data @EqualsAndHashCode(callSuper = false) @AllArgsConstructor @@ -276,19 +259,6 @@ public EoseMessage create() { } } - @Data - @EqualsAndHashCode(callSuper = false) - @AllArgsConstructor - public static class NoticeMessageFactory extends MessageFactory { - - private final String message; - - @Override - public NoticeMessage create() { - return new NoticeMessage(message); - } - } - public static class Kinds { public static final Integer KIND_SET_METADATA = 0; diff --git a/nostr-java-client/src/main/java/nostr/client/Client.java b/nostr-java-client/src/main/java/nostr/client/Client.java index c39e7feff..d4704bd01 100644 --- a/nostr-java-client/src/main/java/nostr/client/Client.java +++ b/nostr-java-client/src/main/java/nostr/client/Client.java @@ -11,7 +11,6 @@ import nostr.context.impl.DefaultRequestContext; import nostr.event.BaseMessage; import nostr.event.impl.GenericTag; -import nostr.event.json.codec.BaseMessageEncoder; import nostr.event.message.CanonicalAuthenticationMessage; import nostr.util.thread.Task; import nostr.util.thread.ThreadUtil; @@ -102,13 +101,13 @@ public Void execute(@NonNull Context context) { var relayTagValue = ((GenericTag) relayTag.get()).getAttributes().get(0).getValue().toString(); log.log(Level.FINEST, "**** Relay found in CanonicalAuthenticationMessage: {0}", relayTagValue); var r = new Relay(relayTagValue); - connectionPool.send(new BaseMessageEncoder(canonicalAuthenticationMessage).encode(), r); + connectionPool.send(canonicalAuthenticationMessage.encode(), r); } else { log.log(Level.SEVERE, "Relay tag not found in CanonicalAuthenticationMessage. Ignoring..."); } } else { log.log(Level.FINER, "+++ message {0}...", message); - connectionPool.send(new BaseMessageEncoder(message).encode()); + connectionPool.send(message.encode()); } return null; } diff --git a/nostr-java-command-provider/src/main/java/module-info.java b/nostr-java-command-provider/src/main/java/module-info.java index 0bb8c75ea..34f9f62c2 100644 --- a/nostr-java-command-provider/src/main/java/module-info.java +++ b/nostr-java-command-provider/src/main/java/module-info.java @@ -17,8 +17,9 @@ requires nostr.context; requires nostr.context.impl; requires nostr.command.handler; + requires com.fasterxml.jackson.core; - exports nostr.command.provider; + exports nostr.command.provider; provides CommandHandler with OkCommandHandler, diff --git a/nostr-java-command-provider/src/main/java/nostr/command/provider/AuthCommandHandler.java b/nostr-java-command-provider/src/main/java/nostr/command/provider/AuthCommandHandler.java index 8180448c4..71994cc8c 100644 --- a/nostr-java-command-provider/src/main/java/nostr/command/provider/AuthCommandHandler.java +++ b/nostr-java-command-provider/src/main/java/nostr/command/provider/AuthCommandHandler.java @@ -1,5 +1,6 @@ package nostr.command.provider; +import com.fasterxml.jackson.core.JsonProcessingException; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.extern.java.Log; @@ -11,7 +12,6 @@ import nostr.context.CommandContext; import nostr.context.impl.DefaultCommandContext; import nostr.event.impl.CanonicalAuthenticationEvent; -import nostr.event.json.codec.BaseMessageEncoder; import nostr.event.message.CanonicalAuthenticationMessage; import nostr.event.message.RelayAuthenticationMessage; import nostr.id.Identity; @@ -49,14 +49,13 @@ public void handle(@NonNull CommandContext context) { var client = Client.getInstance(); var canonicalAuthenticationMessage = new CanonicalAuthenticationMessage(canonicalAuthenticationEvent); - var encoder = new BaseMessageEncoder(canonicalAuthenticationMessage); - var encodedMessage = encoder.encode(); - log.log(Level.INFO, "Sending authentication event {0} to the relay {1}", new Object[]{encodedMessage, relay}); - - // Publish the event to the relay try { + var encodedMessage = canonicalAuthenticationMessage.encode(); + log.log(Level.INFO, "Sending authentication event {0} to the relay {1}", new Object[]{encodedMessage, relay}); + + // Publish the event to the relay client.send(canonicalAuthenticationMessage); - } catch (TimeoutException e) { + } catch (TimeoutException | JsonProcessingException e) { throw new RuntimeException(e); } } diff --git a/nostr-java-command-provider/src/main/java/nostr/command/provider/ClosedCommandHandler.java b/nostr-java-command-provider/src/main/java/nostr/command/provider/ClosedCommandHandler.java index dcfd75704..54288619c 100644 --- a/nostr-java-command-provider/src/main/java/nostr/command/provider/ClosedCommandHandler.java +++ b/nostr-java-command-provider/src/main/java/nostr/command/provider/ClosedCommandHandler.java @@ -1,5 +1,6 @@ package nostr.command.provider; +import com.fasterxml.jackson.core.JsonProcessingException; import lombok.NoArgsConstructor; import lombok.extern.java.Log; import nostr.base.Command; @@ -10,7 +11,6 @@ import nostr.context.CommandContext; import nostr.context.impl.DefaultCommandContext; import nostr.event.impl.CanonicalAuthenticationEvent; -import nostr.event.json.codec.BaseMessageEncoder; import nostr.event.message.CanonicalAuthenticationMessage; import nostr.event.message.ClosedMessage; import nostr.id.Identity; @@ -49,14 +49,13 @@ public void handle(CommandContext context) { var client = Client.getInstance(); // No need to pass the request context here. The client will use the default one var canonicalAuthenticationMessage = new CanonicalAuthenticationMessage(canonicalAuthenticationEvent); - var encoder = new BaseMessageEncoder(canonicalAuthenticationMessage); - var encodedMessage = encoder.encode(); - log.log(Level.INFO, "Sending authentication event {0} to the relay {1}", new Object[]{encodedMessage, relay}); - - // Publish the event to the relay try { + var encodedMessage = canonicalAuthenticationMessage.encode(); + log.log(Level.INFO, "Sending authentication event {0} to the relay {1}", new Object[]{encodedMessage, relay}); + + // Publish the event to the relay client.send(canonicalAuthenticationMessage); - } catch (TimeoutException e) { + } catch (TimeoutException | JsonProcessingException e) { throw new RuntimeException(e); } } diff --git a/nostr-java-event/src/main/java/nostr/event/BaseMessage.java b/nostr-java-event/src/main/java/nostr/event/BaseMessage.java index 8571e6226..a78aafcec 100644 --- a/nostr-java-event/src/main/java/nostr/event/BaseMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/BaseMessage.java @@ -1,5 +1,8 @@ package nostr.event; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; import lombok.Getter; import nostr.base.IElement; @@ -9,7 +12,7 @@ */ @Getter public abstract class BaseMessage implements IElement { - + private final ArrayNode arrayNode = JsonNodeFactory.instance.arrayNode(); private final String command; protected BaseMessage(String command) { @@ -21,4 +24,5 @@ public Integer getNip() { return 1; } + public abstract String encode() throws JsonProcessingException; } diff --git a/nostr-java-event/src/main/java/nostr/event/impl/GenericMessage.java b/nostr-java-event/src/main/java/nostr/event/impl/GenericMessage.java index 6e09caf77..6a31cd561 100644 --- a/nostr-java-event/src/main/java/nostr/event/impl/GenericMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/impl/GenericMessage.java @@ -1,30 +1,33 @@ package nostr.event.impl; import com.fasterxml.jackson.annotation.JsonIgnore; - -import java.util.ArrayList; -import java.util.List; -import lombok.Data; -import lombok.EqualsAndHashCode; +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.Getter; +import lombok.Setter; import nostr.base.ElementAttribute; import nostr.base.IElement; +import nostr.base.IEncoder; import nostr.base.IGenericElement; import nostr.event.BaseMessage; +import java.util.ArrayList; +import java.util.List; + /** * * @author squirrel */ -@Data -@EqualsAndHashCode(callSuper = false) + +@Setter +@Getter public class GenericMessage extends BaseMessage implements IGenericElement, IElement { @JsonIgnore private final List attributes; - + @JsonIgnore private final Integer nip; - + public GenericMessage(String command) { this(command, new ArrayList<>(), 1); } @@ -44,4 +47,10 @@ public void addAttribute(ElementAttribute attribute) { this.attributes.add(attribute); } + @Override + public String encode() throws JsonProcessingException { + getArrayNode().add(getCommand()); + getAttributes().stream().map(ElementAttribute::getValue).forEach(v -> getArrayNode().add(v.toString())); + return IEncoder.MAPPER.writeValueAsString(getArrayNode()); + } } diff --git a/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageEncoder.java b/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageEncoder.java deleted file mode 100644 index 42638d95a..000000000 --- a/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageEncoder.java +++ /dev/null @@ -1,85 +0,0 @@ -package nostr.event.json.codec; - - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NonNull; -import nostr.base.IEncoder; -import nostr.base.Relay; -import nostr.event.BaseEvent; -import nostr.event.BaseMessage; -import nostr.event.impl.Filters; -import nostr.event.impl.GenericMessage; -import nostr.event.message.CanonicalAuthenticationMessage; -import nostr.event.message.CloseMessage; -import nostr.event.message.EventMessage; -import nostr.event.message.NoticeMessage; -import nostr.event.message.OkMessage; -import nostr.event.message.RelayAuthenticationMessage; -import nostr.event.message.ReqMessage; - -import java.util.List; - -/** - * @author squirrel - */ -@Data -@AllArgsConstructor -public class BaseMessageEncoder implements IEncoder { - - private final BaseMessage message; - private final Relay relay; - - public BaseMessageEncoder(@NonNull BaseMessage message) { - this(message, null); - } - - @Override - public String encode() { - var arrayNode = JsonNodeFactory.instance.arrayNode(); - try { - arrayNode.add(message.getCommand()); - if (message instanceof EventMessage msg) { - JsonNode tree = IEncoder.MAPPER.readTree(new BaseEventEncoder<>((BaseEvent) msg.getEvent()).encode()); - arrayNode.add(tree); - } else if (message instanceof ReqMessage msg) { - arrayNode.add(msg.getSubscriptionId()); - // Encode each filter individually and join them with a comma - List filtersList = msg.getFiltersList(); - for (Filters f : filtersList) { - try { - FiltersEncoder filtersEncoder = new FiltersEncoder(f); - var filterNode = MAPPER.readTree(filtersEncoder.encode()); - arrayNode.add(filterNode); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } else if (message instanceof NoticeMessage msg) { - arrayNode.add(msg.getMessage()); - } else if (message instanceof OkMessage msg) { - arrayNode.add(msg.getEventId()); - arrayNode.add(msg.getFlag()); - arrayNode.add(msg.getMessage()); - } else if (message instanceof CloseMessage msg) { - arrayNode.add(msg.getSubscriptionId()); - } else if (message instanceof CanonicalAuthenticationMessage msg) { - JsonNode tree = IEncoder.MAPPER.readTree(new BaseEventEncoder<>(msg.getEvent()).encode()); - arrayNode.add(tree); - } else if (message instanceof RelayAuthenticationMessage msg) { - arrayNode.add(msg.getChallenge()); - } else if (message instanceof GenericMessage msg) { - msg.getAttributes().stream().map(a -> a.getValue()).forEach(v -> arrayNode.add(v.toString())); - } else { - throw new RuntimeException(String.format("Invalid message type %s", message)); - } - - return IEncoder.MAPPER.writeValueAsString(arrayNode); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } -} diff --git a/nostr-java-event/src/main/java/nostr/event/message/CanonicalAuthenticationMessage.java b/nostr-java-event/src/main/java/nostr/event/message/CanonicalAuthenticationMessage.java index e1f9d836a..e3b4003f0 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/CanonicalAuthenticationMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/CanonicalAuthenticationMessage.java @@ -2,27 +2,34 @@ package nostr.event.message; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.Getter; +import lombok.Setter; import nostr.base.Command; +import nostr.base.IEncoder; import nostr.event.impl.CanonicalAuthenticationEvent; +import nostr.event.json.codec.BaseEventEncoder; /** - * * @author eric */ -@Data -@EqualsAndHashCode(callSuper = false) -@ToString(callSuper = true) +@Setter +@Getter public class CanonicalAuthenticationMessage extends BaseAuthMessage { - @JsonProperty - private final CanonicalAuthenticationEvent event; - - public CanonicalAuthenticationMessage(CanonicalAuthenticationEvent event) { - super(Command.AUTH.name()); - this.event = event; - } - + @JsonProperty + private final CanonicalAuthenticationEvent event; + + public CanonicalAuthenticationMessage(CanonicalAuthenticationEvent event) { + super(Command.AUTH.name()); + this.event = event; + } + @Override + public String encode() throws JsonProcessingException { + return IEncoder.MAPPER.writeValueAsString( + getArrayNode() + .add(getCommand()) + .add(IEncoder.MAPPER.readTree( + new BaseEventEncoder<>(getEvent()).encode()))); + } } \ No newline at end of file diff --git a/nostr-java-event/src/main/java/nostr/event/message/CloseMessage.java b/nostr-java-event/src/main/java/nostr/event/message/CloseMessage.java index 376a5052b..224430654 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/CloseMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/CloseMessage.java @@ -1,24 +1,19 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package nostr.event.message; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.Getter; +import lombok.Setter; import nostr.base.Command; +import nostr.base.IEncoder; import nostr.event.BaseMessage; /** * * @author squirrel */ -@Data -@EqualsAndHashCode(callSuper = false) -@ToString(callSuper = true) +@Setter +@Getter public class CloseMessage extends BaseMessage { @JsonProperty @@ -32,4 +27,12 @@ public CloseMessage(String subscriptionId) { super(Command.CLOSE.name()); this.subscriptionId = subscriptionId; } + + @Override + public String encode() throws JsonProcessingException { + return IEncoder.MAPPER.writeValueAsString( + getArrayNode() + .add(getCommand()) + .add(getSubscriptionId())); + } } diff --git a/nostr-java-event/src/main/java/nostr/event/message/ClosedMessage.java b/nostr-java-event/src/main/java/nostr/event/message/ClosedMessage.java index e7d693f7b..628c7adbf 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/ClosedMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/ClosedMessage.java @@ -1,16 +1,16 @@ package nostr.event.message; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.Getter; import lombok.NonNull; -import lombok.ToString; +import lombok.Setter; import nostr.base.Command; +import nostr.base.IEncoder; import nostr.event.BaseMessage; -@Data -@EqualsAndHashCode(callSuper = false) -@ToString(callSuper = true) +@Setter +@Getter public class ClosedMessage extends BaseMessage { @JsonProperty @@ -24,4 +24,12 @@ public ClosedMessage(@NonNull String subId, @NonNull String message) { this.subscriptionId = subId; this.message = message; } + + @Override + public String encode() throws JsonProcessingException { + return IEncoder.MAPPER.writeValueAsString( + getArrayNode() + .add(getCommand()) + .add(getSubscriptionId())); + } } diff --git a/nostr-java-event/src/main/java/nostr/event/message/EoseMessage.java b/nostr-java-event/src/main/java/nostr/event/message/EoseMessage.java index 1b3c1cb7e..2da444ba6 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/EoseMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/EoseMessage.java @@ -2,24 +2,23 @@ package nostr.event.message; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.Getter; +import lombok.Setter; import nostr.base.Command; +import nostr.base.IEncoder; import nostr.event.BaseMessage; /** * * @author squirrel */ -@Data -@EqualsAndHashCode(callSuper = false) -@ToString(callSuper = true) +@Setter +@Getter public class EoseMessage extends BaseMessage { @JsonProperty private final String subscriptionId; - private EoseMessage() { this(null); } @@ -28,5 +27,12 @@ public EoseMessage(String subId) { super(Command.EOSE.name()); this.subscriptionId = subId; } - + + @Override + public String encode() throws JsonProcessingException { + return IEncoder.MAPPER.writeValueAsString( + getArrayNode() + .add(getCommand()) + .add(getSubscriptionId())); + } } diff --git a/nostr-java-event/src/main/java/nostr/event/message/EventMessage.java b/nostr-java-event/src/main/java/nostr/event/message/EventMessage.java index 0ef85c540..61aa4610f 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/EventMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/EventMessage.java @@ -1,27 +1,24 @@ - package nostr.event.message; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.Getter; import lombok.NonNull; -import lombok.ToString; +import lombok.Setter; import nostr.base.Command; +import nostr.base.IEncoder; import nostr.base.IEvent; +import nostr.event.BaseEvent; import nostr.event.BaseMessage; +import nostr.event.json.codec.BaseEventEncoder; -/** - * - * @author squirrel - */ -@Data -@EqualsAndHashCode(callSuper = false) -@ToString(callSuper = true) +@Setter +@Getter public class EventMessage extends BaseMessage { @JsonProperty private final IEvent event; - + @JsonProperty private String subscriptionId; @@ -34,4 +31,13 @@ public EventMessage(@NonNull IEvent event, String subscriptionId) { this.event = event; this.subscriptionId = subscriptionId; } + + @Override + public String encode() throws JsonProcessingException { + return IEncoder.MAPPER.writeValueAsString( + getArrayNode() + .add(getCommand()) + .add(IEncoder.MAPPER.readTree( + new BaseEventEncoder<>((BaseEvent)getEvent()).encode()))); + } } diff --git a/nostr-java-event/src/main/java/nostr/event/message/NoticeMessage.java b/nostr-java-event/src/main/java/nostr/event/message/NoticeMessage.java index bcb8b7ac1..261e5fbc7 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/NoticeMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/NoticeMessage.java @@ -1,21 +1,20 @@ - package nostr.event.message; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.Getter; import lombok.NonNull; -import lombok.ToString; +import lombok.Setter; import nostr.base.Command; +import nostr.base.IEncoder; import nostr.event.BaseMessage; /** * * @author squirrel */ -@Data -@EqualsAndHashCode(callSuper = false) -@ToString(callSuper = true) +@Setter +@Getter public class NoticeMessage extends BaseMessage { @JsonProperty @@ -25,4 +24,12 @@ public NoticeMessage(@NonNull String message) { super(Command.NOTICE.name()); this.message = message; } + + @Override + public String encode() throws JsonProcessingException { + return IEncoder.MAPPER.writeValueAsString( + getArrayNode() + .add(getCommand()) + .add(getMessage())); + } } diff --git a/nostr-java-event/src/main/java/nostr/event/message/OkMessage.java b/nostr-java-event/src/main/java/nostr/event/message/OkMessage.java index c9770a3cd..6fe9bf6d6 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/OkMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/OkMessage.java @@ -1,28 +1,27 @@ - package nostr.event.message; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.Getter; +import lombok.Setter; import nostr.base.Command; +import nostr.base.IEncoder; import nostr.event.BaseMessage; /** * * @author squirrel */ -@Data -@EqualsAndHashCode(callSuper = false) -@ToString +@Setter +@Getter public class OkMessage extends BaseMessage { @JsonProperty private final String eventId; - + @JsonProperty private final Boolean flag; - + @JsonProperty private final String message; @@ -32,6 +31,14 @@ public OkMessage(String eventId, Boolean flag, String message) { this.flag = flag; this.message = message; } - - + + @Override + public String encode() throws JsonProcessingException { + return IEncoder.MAPPER.writeValueAsString( + getArrayNode() + .add(getCommand()) + .add(getEventId()) + .add(getFlag()) + .add(getMessage())); + } } diff --git a/nostr-java-event/src/main/java/nostr/event/message/RelayAuthenticationMessage.java b/nostr-java-event/src/main/java/nostr/event/message/RelayAuthenticationMessage.java index 8ffb0fca9..4a3e83539 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/RelayAuthenticationMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/RelayAuthenticationMessage.java @@ -1,18 +1,18 @@ package nostr.event.message; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.Getter; +import lombok.Setter; import nostr.base.Command; +import nostr.base.IEncoder; /** * * @author eric */ -@Data -@EqualsAndHashCode(callSuper = false) -@ToString(callSuper = true) +@Setter +@Getter public class RelayAuthenticationMessage extends BaseAuthMessage { @JsonProperty @@ -23,4 +23,11 @@ public RelayAuthenticationMessage(String challenge) { this.challenge = challenge; } + @Override + public String encode() throws JsonProcessingException { + return IEncoder.MAPPER.writeValueAsString( + getArrayNode() + .add(getCommand()) + .add(getChallenge())); + } } diff --git a/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java b/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java index 28f70cc57..86ce41f92 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java @@ -1,13 +1,15 @@ - package nostr.event.message; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; import nostr.base.Command; +import nostr.base.IEncoder; import nostr.event.BaseMessage; import nostr.event.impl.Filters; +import nostr.event.json.codec.FiltersEncoder; import java.util.ArrayList; import java.util.List; @@ -28,10 +30,7 @@ public class ReqMessage extends BaseMessage { private final List filtersList; public ReqMessage(String subscriptionId, Filters filters) { - super(Command.REQ.name()); - this.subscriptionId = subscriptionId; - this.filtersList = new ArrayList<>(); - this.filtersList.add(filters); + this(subscriptionId, List.of(filters)); } public ReqMessage(String subscriptionId, List incomingFiltersList) { @@ -40,4 +39,23 @@ public ReqMessage(String subscriptionId, List incomingFiltersList) { this.filtersList = new ArrayList<>(); this.filtersList.addAll(incomingFiltersList); } + + @Override + public String encode() throws JsonProcessingException { + getArrayNode() + .add(getCommand()) + .add(getSubscriptionId()); + // Encode each filter individually and join them with a comma + List localFiltersList = getFiltersList(); + for (Filters f : localFiltersList) { + try { + FiltersEncoder filtersEncoder = new FiltersEncoder(f); + var filterNode = IEncoder.MAPPER.readTree(filtersEncoder.encode()); + getArrayNode().add(filterNode); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return IEncoder.MAPPER.writeValueAsString(getArrayNode()); + } } diff --git a/nostr-java-test/src/test/java/nostr/test/json/JsonParseTest.java b/nostr-java-test/src/test/java/nostr/test/json/JsonParseTest.java index 90d9a9103..b10875cb8 100644 --- a/nostr-java-test/src/test/java/nostr/test/json/JsonParseTest.java +++ b/nostr-java-test/src/test/java/nostr/test/json/JsonParseTest.java @@ -18,7 +18,6 @@ import nostr.event.impl.GenericTag; import nostr.event.json.codec.BaseEventEncoder; import nostr.event.json.codec.BaseMessageDecoder; -import nostr.event.json.codec.BaseMessageEncoder; import nostr.event.json.codec.BaseTagDecoder; import nostr.event.json.codec.FiltersEncoder; import nostr.event.json.codec.GenericEventDecoder; @@ -72,7 +71,7 @@ public void testBaseReqMessageDecoder() { } @Test - public void testBaseReqMessageEncoder() { + public void testBaseReqMessageEncoder() throws JsonProcessingException { System.out.println("testBaseReqMessageEncoder"); final var filtersList = new ArrayList(); @@ -84,9 +83,7 @@ public void testBaseReqMessageEncoder() { final var reqMessage = new ReqMessage(publicKey.toString(), filtersList); - BaseMessageEncoder encoder = new BaseMessageEncoder(reqMessage); - - var jsonMessage = encoder.encode(); + var jsonMessage = reqMessage.encode(); var jsonMsg = jsonMessage.substring(1, jsonMessage.length() - 1); var parts = jsonMsg.split(","); @@ -276,7 +273,7 @@ public void testFiltersEncoder() { } @Test - public void testReqMessageSerializer() { + public void testReqMessageSerializer() throws JsonProcessingException { System.out.println("testFiltersEncoder"); String new_geohash = "2vghde"; @@ -288,8 +285,7 @@ public void testReqMessageSerializer() { Filters filters = Filters.builder().genericTagQuery(genericTagQuery).build(); ReqMessage reqMessage = new ReqMessage("npub1clk6vc9xhjp8q5cws262wuf2eh4zuvwupft03hy4ttqqnm7e0jrq3upup9", new ArrayList(List.of(filters))); - BaseMessageEncoder encoder = new BaseMessageEncoder(reqMessage); - String jsonMessage = encoder.encode(); + String jsonMessage = reqMessage.encode(); assertEquals("[\"REQ\",\"npub1clk6vc9xhjp8q5cws262wuf2eh4zuvwupft03hy4ttqqnm7e0jrq3upup9\",{\"#g\":[\"2vghde\"]}]", jsonMessage); } From 0c95e0bfdc134529b847e8181e54cdd3aab41278 Mon Sep 17 00:00:00 2001 From: nick avlo Date: Sat, 1 Jun 2024 22:47:14 -0700 Subject: [PATCH 02/12] cleanup & formatting --- .../src/main/java/nostr/api/NIP01.java | 544 +++++++++--------- .../nostr/api/factory/impl/NIP01Impl.java | 16 +- .../src/main/java/nostr/client/Client.java | 228 ++++---- .../serializer/CustomBaseListSerializer.java | 14 +- .../CustomIdEventListSerializer.java | 1 - .../CanonicalAuthenticationMessage.java | 2 +- .../java/nostr/event/message/ReqMessage.java | 1 - 7 files changed, 400 insertions(+), 406 deletions(-) diff --git a/nostr-java-api/src/main/java/nostr/api/NIP01.java b/nostr-java-api/src/main/java/nostr/api/NIP01.java index b8c6a26ff..8e0a41380 100644 --- a/nostr-java-api/src/main/java/nostr/api/NIP01.java +++ b/nostr-java-api/src/main/java/nostr/api/NIP01.java @@ -47,276 +47,276 @@ */ public class NIP01 extends EventNostr { - public NIP01(@NonNull Identity sender) { - setSender(sender); - } - - /** - * Create a NIP01 text note event without tags - * - * @param content the content of the note - * @return the text note without tags - */ - public NIP01 createTextNoteEvent(@NonNull String content) { - var event = new TextNoteEventFactory(getSender(), content).create(); - this.setEvent((T) event); - - return this; - } - - public NIP01 createTextNoteEvent(@NonNull Identity sender, @NonNull String content) { - var event = new TextNoteEventFactory(sender, content).create(); - this.setEvent((T) event); - - return this; - } - - /** - * Create a NIP01 text note event with tags - * - * @param tags the note tags - * @param content the content of the note - * @return a text note event - */ - public NIP01 createTextNoteEvent(@NonNull List tags, @NonNull String content) { - setEvent((T) new TextNoteEventFactory(getSender(), tags, content).create()); - return this; - } - - public NIP01 createMetadataEvent(@NonNull UserProfile profile) { - var sender = getSender(); - var event = (sender!=null) ? new MetadataEventFactory(sender, profile).create() : new MetadataEventFactory(profile).create(); - - this.setEvent((T) event); - return this; - } - - /** - * Create a replaceable event - * @param kind the kind (10000 <= kind < 20000 || kind == 0 || kind == 3) - * @param content the content - */ - public NIP01 createReplaceableEvent(@NonNull Integer kind, String content) { - var event = new ReplaceableEventFactory(getSender(), kind, content).create(); - - this.setEvent((T) event); - return this; - } - - /** - * Create a replaceable event - * @param tags the note's tags - * @param kind the kind (10000 <= kind < 20000 || kind == 0 || kind == 3) - * @param content the note's content - */ - public NIP01 createReplaceableEvent(@NonNull List tags, @NonNull Integer kind, String content) { - var event = new ReplaceableEventFactory(getSender(), tags, kind, content).create(); - - this.setEvent((T) event); - return this; - } - - /** - * Create an ephemeral event - * @param kind the kind (20000 <= n < 30000) - * @param content the note's content - */ - public NIP01 createEphemeralEvent(@NonNull Integer kind, String content) { - var event = new EphemeralEventFactory(getSender(), kind, content).create(); - - this.setEvent((T) event); - return this; - } - - /** - * Create a NIP01 event tag - * - * @param relateEventId the related event id - * @return an event tag with the id of the related event - */ - public static EventTag createEventTag(@NonNull String relateEventId) { - return new EventTagFactory(relateEventId).create(); - } - - /** - * Create a NIP01 event tag with additional recommended relay and marker - * - * @param relateEventId the related event id - * @param recommendedRelayUrl the recommended relay - * @param marker the marker - * @return an event tag with the id of the related event and optional - * recommended relay and marker - */ - public static EventTag createEventTag(@NonNull String relateEventId, String recommendedRelayUrl, Marker marker) { - var result = new EventTagFactory(relateEventId).create(); - result.setMarker(marker); - result.setRecommendedRelayUrl(recommendedRelayUrl); - return result; - } - - /** - * Create a NIP01 pubkey tag - * - * @param publicKey the associated public key - * @return a pubkey tag with the hex representation of the associated public - * key - */ - public static PubKeyTag createPubKeyTag(@NonNull PublicKey publicKey) { - return new PubKeyTagFactory(publicKey).create(); - } - - /** - * Create a NIP01 pubkey tag with additional recommended relay and petname - * (as defined in NIP02) - * - * @param publicKey the associated public key - * @param mainRelayUrl the recommended relay - * @param petName the petname - * @return a pubkey tag with the hex representation of the associated public - * key and the optional recommended relay and petname - */ - public static PubKeyTag createPubKeyTag(@NonNull PublicKey publicKey, String mainRelayUrl, String petName) { - var result = new PubKeyTagFactory(publicKey).create(); - result.setMainRelayUrl(mainRelayUrl); - result.setPetName(petName); - return result; - } - - /** - * Create a NIP01 filters object (all parameters are optional) - * - * @param events a list of event - * @param authors a list of pubkeys or prefixes, the pubkey of an event must - * be one of these - * @param kinds a list of a kind numbers - * @param referencedEvents a list of event ids that are referenced in an "e" - * tag - * @param referencePubKeys a list of pubkeys that are referenced in a "p" - * tag - * @param since an integer unix timestamp in seconds, events must be newer - * than this to pass - * @param until an integer unix timestamp in seconds, events must be older - * than this to pass - * @param limit maximum number of events to be returned in the initial query - * @param genericTagQuery a generic tag query - * @return a filters object - */ - @Deprecated(forRemoval = true) - public static Filters createFilters(List events, List authors, List kinds, List referencedEvents, List referencePubKeys, Long since, Long until, Integer limit, GenericTagQuery genericTagQuery) { - return Filters.builder() - .authors(authors) - .events(events) - .genericTagQuery(genericTagQuery) - .kinds(kinds).limit(limit) - .referencePubKeys(referencePubKeys) - .referencedEvents(referencedEvents) - .since(since) - .until(until) - .build(); - } - - - /** - * Create an event message to send events requested by clients - * - * @param event the related event - * @param subscriptionId the related subscription id - * @return an event message - */ - public static EventMessage createEventMessage(@NonNull IEvent event, @NonNull String subscriptionId) { - return new EventMessage(event, subscriptionId); - } - - /** - * Create a REQ message to request events and subscribe to new updates - * - * @param subscriptionId the subscription id - * @param filtersList the filters list - * @return a REQ message - */ - public static ReqMessage createReqMessage(@NonNull String subscriptionId, @NonNull List filtersList) { - return new ReqMessageFactory(subscriptionId, filtersList).create(); - } - - /** - * Create a CLOSE message to stop previous subscriptions - * - * @param subscriptionId the subscription id - * @return a CLOSE message - */ - public static CloseMessage createCloseMessage(@NonNull String subscriptionId) { - return new CloseMessageFactory(subscriptionId).create(); - } - - /** - * Create an EOSE message to indicate the end of stored events and the - * beginning of events newly received in real-time - * - * @param subscriptionId the subscription id - * @return an EOSE message - */ - public static EoseMessage createEoseMessage(@NonNull String subscriptionId) { - return new EoseMessageFactory(subscriptionId).create(); - } - - /** - * Create a NOTICE message to send human-readable error messages or other - * things to clients. - * - * @param message the human-readable message to send to the client - * @return a NOTICE message - */ - public static NoticeMessage createNoticeMessage(@NonNull String message) { - return new NoticeMessage(message); - } - - /** - * - * @param comment the event's comment - */ - public NIP01 createParameterizedReplaceableEvent(@NonNull Integer kind, String comment) { - var event = new ParameterizedReplaceableEventFactory(getSender(), kind, comment).create(); - - this.setEvent((T) event); - return this; - } - - /** - * - * @param tags - * @param kind - * @param comment - * @return - */ - public NIP01 createParameterizedReplaceableEvent(@NonNull List tags, @NonNull Integer kind, String comment) { - var event = new ParameterizedReplaceableEventFactory(getSender(), tags, kind, comment).create(); - - this.setEvent((T) event); - return this; - } - - /** - * - * @param id - * @return - */ - public static IdentifierTag createIdentifierTag(@NonNull String id) { - return new IdentifierTagFactory(id).create(); - } - - /** - * - * @param kind - * @param publicKey - * @param idTag - * @param relay - * @return - */ - public static AddressTag createAddressTag(@NonNull Integer kind, @NonNull PublicKey publicKey, @NonNull IdentifierTag idTag, Relay relay) { - var result = new AddressTagFactory(publicKey).create(); - result.setIdentifierTag(idTag); - result.setKind(kind); - result.setRelay(relay); - return result; - } + public NIP01(@NonNull Identity sender) { + setSender(sender); + } + + /** + * Create a NIP01 text note event without tags + * + * @param content the content of the note + * @return the text note without tags + */ + public NIP01 createTextNoteEvent(@NonNull String content) { + var event = new TextNoteEventFactory(getSender(), content).create(); + this.setEvent((T) event); + + return this; + } + + public NIP01 createTextNoteEvent(@NonNull Identity sender, @NonNull String content) { + var event = new TextNoteEventFactory(sender, content).create(); + this.setEvent((T) event); + + return this; + } + + /** + * Create a NIP01 text note event with tags + * + * @param tags the note tags + * @param content the content of the note + * @return a text note event + */ + public NIP01 createTextNoteEvent(@NonNull List tags, @NonNull String content) { + setEvent((T) new TextNoteEventFactory(getSender(), tags, content).create()); + return this; + } + + public NIP01 createMetadataEvent(@NonNull UserProfile profile) { + var sender = getSender(); + var event = (sender != null) ? new MetadataEventFactory(sender, profile).create() : new MetadataEventFactory(profile).create(); + + this.setEvent((T) event); + return this; + } + + /** + * Create a replaceable event + * @param kind the kind (10000 <= kind < 20000 || kind == 0 || kind == 3) + * @param content the content + */ + public NIP01 createReplaceableEvent(@NonNull Integer kind, String content) { + var event = new ReplaceableEventFactory(getSender(), kind, content).create(); + + this.setEvent((T) event); + return this; + } + + /** + * Create a replaceable event + * @param tags the note's tags + * @param kind the kind (10000 <= kind < 20000 || kind == 0 || kind == 3) + * @param content the note's content + */ + public NIP01 createReplaceableEvent(@NonNull List tags, @NonNull Integer kind, String content) { + var event = new ReplaceableEventFactory(getSender(), tags, kind, content).create(); + + this.setEvent((T) event); + return this; + } + + /** + * Create an ephemeral event + * @param kind the kind (20000 <= n < 30000) + * @param content the note's content + */ + public NIP01 createEphemeralEvent(@NonNull Integer kind, String content) { + var event = new EphemeralEventFactory(getSender(), kind, content).create(); + + this.setEvent((T) event); + return this; + } + + /** + * Create a NIP01 event tag + * + * @param relateEventId the related event id + * @return an event tag with the id of the related event + */ + public static EventTag createEventTag(@NonNull String relateEventId) { + return new EventTagFactory(relateEventId).create(); + } + + /** + * Create a NIP01 event tag with additional recommended relay and marker + * + * @param relateEventId the related event id + * @param recommendedRelayUrl the recommended relay + * @param marker the marker + * @return an event tag with the id of the related event and optional + * recommended relay and marker + */ + public static EventTag createEventTag(@NonNull String relateEventId, String recommendedRelayUrl, Marker marker) { + var result = new EventTagFactory(relateEventId).create(); + result.setMarker(marker); + result.setRecommendedRelayUrl(recommendedRelayUrl); + return result; + } + + /** + * Create a NIP01 pubkey tag + * + * @param publicKey the associated public key + * @return a pubkey tag with the hex representation of the associated public + * key + */ + public static PubKeyTag createPubKeyTag(@NonNull PublicKey publicKey) { + return new PubKeyTagFactory(publicKey).create(); + } + + /** + * Create a NIP01 pubkey tag with additional recommended relay and petname + * (as defined in NIP02) + * + * @param publicKey the associated public key + * @param mainRelayUrl the recommended relay + * @param petName the petname + * @return a pubkey tag with the hex representation of the associated public + * key and the optional recommended relay and petname + */ + public static PubKeyTag createPubKeyTag(@NonNull PublicKey publicKey, String mainRelayUrl, String petName) { + var result = new PubKeyTagFactory(publicKey).create(); + result.setMainRelayUrl(mainRelayUrl); + result.setPetName(petName); + return result; + } + + /** + * Create a NIP01 filters object (all parameters are optional) + * + * @param events a list of event + * @param authors a list of pubkeys or prefixes, the pubkey of an event must + * be one of these + * @param kinds a list of a kind numbers + * @param referencedEvents a list of event ids that are referenced in an "e" + * tag + * @param referencePubKeys a list of pubkeys that are referenced in a "p" + * tag + * @param since an integer unix timestamp in seconds, events must be newer + * than this to pass + * @param until an integer unix timestamp in seconds, events must be older + * than this to pass + * @param limit maximum number of events to be returned in the initial query + * @param genericTagQuery a generic tag query + * @return a filters object + */ + @Deprecated(forRemoval = true) + public static Filters createFilters(List events, List authors, List kinds, List referencedEvents, List referencePubKeys, Long since, Long until, Integer limit, GenericTagQuery genericTagQuery) { + return Filters.builder() + .authors(authors) + .events(events) + .genericTagQuery(genericTagQuery) + .kinds(kinds).limit(limit) + .referencePubKeys(referencePubKeys) + .referencedEvents(referencedEvents) + .since(since) + .until(until) + .build(); + } + + + /** + * Create an event message to send events requested by clients + * + * @param event the related event + * @param subscriptionId the related subscription id + * @return an event message + */ + public static EventMessage createEventMessage(@NonNull IEvent event, @NonNull String subscriptionId) { + return new EventMessage(event, subscriptionId); + } + + /** + * Create a REQ message to request events and subscribe to new updates + * + * @param subscriptionId the subscription id + * @param filtersList the filters list + * @return a REQ message + */ + public static ReqMessage createReqMessage(@NonNull String subscriptionId, @NonNull List filtersList) { + return new ReqMessageFactory(subscriptionId, filtersList).create(); + } + + /** + * Create a CLOSE message to stop previous subscriptions + * + * @param subscriptionId the subscription id + * @return a CLOSE message + */ + public static CloseMessage createCloseMessage(@NonNull String subscriptionId) { + return new CloseMessageFactory(subscriptionId).create(); + } + + /** + * Create an EOSE message to indicate the end of stored events and the + * beginning of events newly received in real-time + * + * @param subscriptionId the subscription id + * @return an EOSE message + */ + public static EoseMessage createEoseMessage(@NonNull String subscriptionId) { + return new EoseMessageFactory(subscriptionId).create(); + } + + /** + * Create a NOTICE message to send human-readable error messages or other + * things to clients. + * + * @param message the human-readable message to send to the client + * @return a NOTICE message + */ + public static NoticeMessage createNoticeMessage(@NonNull String message) { + return new NoticeMessage(message); + } + + /** + * + * @param comment the event's comment + */ + public NIP01 createParameterizedReplaceableEvent(@NonNull Integer kind, String comment) { + var event = new ParameterizedReplaceableEventFactory(getSender(), kind, comment).create(); + + this.setEvent((T) event); + return this; + } + + /** + * + * @param tags + * @param kind + * @param comment + * @return + */ + public NIP01 createParameterizedReplaceableEvent(@NonNull List tags, @NonNull Integer kind, String comment) { + var event = new ParameterizedReplaceableEventFactory(getSender(), tags, kind, comment).create(); + + this.setEvent((T) event); + return this; + } + + /** + * + * @param id + * @return + */ + public static IdentifierTag createIdentifierTag(@NonNull String id) { + return new IdentifierTagFactory(id).create(); + } + + /** + * + * @param kind + * @param publicKey + * @param idTag + * @param relay + * @return + */ + public static AddressTag createAddressTag(@NonNull Integer kind, @NonNull PublicKey publicKey, @NonNull IdentifierTag idTag, Relay relay) { + var result = new AddressTagFactory(publicKey).create(); + result.setIdentifierTag(idTag); + result.setKind(kind); + result.setRelay(relay); + return result; + } } diff --git a/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java b/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java index 8067e3e70..8ce12827b 100644 --- a/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java +++ b/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java @@ -11,12 +11,10 @@ import nostr.api.factory.AbstractTagFactory; import nostr.api.factory.EventFactory; import nostr.api.factory.MessageFactory; -import nostr.base.IEvent; import nostr.base.PublicKey; import nostr.base.Relay; import nostr.base.UserProfile; -import nostr.event - .BaseTag; +import nostr.event.BaseTag; import nostr.event.Marker; import nostr.event.impl.EphemeralEvent; import nostr.event.impl.Filters; @@ -26,8 +24,6 @@ import nostr.event.impl.TextNoteEvent; import nostr.event.message.CloseMessage; import nostr.event.message.EoseMessage; -import nostr.event.message.EventMessage; -import nostr.event.message.NoticeMessage; import nostr.event.message.ReqMessage; import nostr.event.tag.AddressTag; import nostr.event.tag.EventTag; @@ -62,7 +58,7 @@ public TextNoteEvent create() { return event; } } - + @Data @EqualsAndHashCode(callSuper = false) public static class MetadataEventFactory extends EventFactory { @@ -81,7 +77,7 @@ public MetadataEventFactory(@NonNull Identity sender, @NonNull UserProfile profi @Override public MetadataEvent create() { return new MetadataEvent(getSender(), profile); - } + } } @Data @@ -91,7 +87,7 @@ public static class EventTagFactory extends AbstractTagFactory { private final String relateEventId; private String recommendedRelayUrl; private Marker marker; - + public EventTagFactory(@NonNull String relateEventId) { this.relateEventId = relateEventId; } @@ -194,9 +190,9 @@ public ParameterizedReplaceableEventFactory(@NonNull Identity sender, @NonNull L @Override public ParameterizedReplaceableEvent create() { return new ParameterizedReplaceableEvent(getSender(), kind, getTags(), getContent()); - } + } } - + @Data @EqualsAndHashCode(callSuper = false) public static class IdentifierTagFactory extends AbstractTagFactory { diff --git a/nostr-java-client/src/main/java/nostr/client/Client.java b/nostr-java-client/src/main/java/nostr/client/Client.java index d4704bd01..0af27871d 100644 --- a/nostr-java-client/src/main/java/nostr/client/Client.java +++ b/nostr-java-client/src/main/java/nostr/client/Client.java @@ -1,115 +1,115 @@ -package nostr.client; - -import lombok.AllArgsConstructor; -import lombok.NoArgsConstructor; -import lombok.NonNull; -import lombok.extern.java.Log; -import nostr.base.Relay; -import nostr.connection.impl.ConnectionPool; -import nostr.context.Context; -import nostr.context.RequestContext; -import nostr.context.impl.DefaultRequestContext; -import nostr.event.BaseMessage; -import nostr.event.impl.GenericTag; -import nostr.event.message.CanonicalAuthenticationMessage; -import nostr.util.thread.Task; -import nostr.util.thread.ThreadUtil; - -import java.util.concurrent.TimeoutException; -import java.util.logging.Level; - -@Log -@NoArgsConstructor -public class Client { - - private static class Holder { - private static final Client INSTANCE = new Client(); - } - - private RequestContext context; - - private ConnectionPool connectionPool; - - public static Client getInstance() { - return Holder.INSTANCE; - } - - public Client connect(@NonNull RequestContext context) throws TimeoutException { - if (context instanceof DefaultRequestContext defaultRequestContext) { - Holder.INSTANCE.context = context; - connectionPool = ConnectionPool.getInstance(defaultRequestContext); - ThreadUtil.builder().blocking(true).lock(true).task(new RelayConnectionTask(this.connectionPool)).build().run(context); - } - return this; - } - - public void disconnect() throws TimeoutException { - ThreadUtil.builder().blocking(true).task(new RelayDisconnectionTask(this.connectionPool)).build().run(this.context); - } - - public int getOpenConnectionsCount() { - return connectionPool.connectionCount(); - } - - public void send(@NonNull BaseMessage message) throws TimeoutException { - log.log(Level.FINE, "Requesting to send the message {0}...", message); - ThreadUtil.builder().blocking(false).lock(true).task(new SendMessageTask(message, this.connectionPool)).build().run(this.context); - } - - boolean isConnected(@NonNull Relay relay) { - return this.connectionPool.isConnectedTo(relay); - } - - @AllArgsConstructor - private static class RelayConnectionTask implements Task { - - private final ConnectionPool connectionManager; - - @Override - public Void execute(@NonNull Context context) { - connectionManager.connect(); - return null; - } - } - - @AllArgsConstructor - private static class RelayDisconnectionTask implements Task { - - private final ConnectionPool connectionPool; - - @Override - public Void execute(@NonNull Context context) { - connectionPool.disconnect(); - return null; - } - } - - @AllArgsConstructor - private static class SendMessageTask implements Task { - - private final BaseMessage message; - private final ConnectionPool connectionPool; - - @Override - public Void execute(@NonNull Context context) { - // Only send AUTH messages to the relay mentioned in the tag https://github.com/tcheeric/nostr-java/issues/129 - if (message instanceof CanonicalAuthenticationMessage canonicalAuthenticationMessage) { - log.log(Level.FINE, ">>> Authentication message {0}...", canonicalAuthenticationMessage); - var event = canonicalAuthenticationMessage.getEvent(); - var relayTag = event.getTags().stream().filter(t -> t.getCode().equalsIgnoreCase("relay")).findFirst(); - if (relayTag.isPresent()) { - var relayTagValue = ((GenericTag) relayTag.get()).getAttributes().get(0).getValue().toString(); - log.log(Level.FINEST, "**** Relay found in CanonicalAuthenticationMessage: {0}", relayTagValue); - var r = new Relay(relayTagValue); - connectionPool.send(canonicalAuthenticationMessage.encode(), r); - } else { - log.log(Level.SEVERE, "Relay tag not found in CanonicalAuthenticationMessage. Ignoring..."); - } - } else { - log.log(Level.FINER, "+++ message {0}...", message); - connectionPool.send(message.encode()); - } - return null; - } - } +package nostr.client; + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.extern.java.Log; +import nostr.base.Relay; +import nostr.connection.impl.ConnectionPool; +import nostr.context.Context; +import nostr.context.RequestContext; +import nostr.context.impl.DefaultRequestContext; +import nostr.event.BaseMessage; +import nostr.event.impl.GenericTag; +import nostr.event.message.CanonicalAuthenticationMessage; +import nostr.util.thread.Task; +import nostr.util.thread.ThreadUtil; + +import java.util.concurrent.TimeoutException; +import java.util.logging.Level; + +@Log +@NoArgsConstructor +public class Client { + + private static class Holder { + private static final Client INSTANCE = new Client(); + } + + private RequestContext context; + + private ConnectionPool connectionPool; + + public static Client getInstance() { + return Holder.INSTANCE; + } + + public Client connect(@NonNull RequestContext context) throws TimeoutException { + if (context instanceof DefaultRequestContext defaultRequestContext) { + Holder.INSTANCE.context = context; + connectionPool = ConnectionPool.getInstance(defaultRequestContext); + ThreadUtil.builder().blocking(true).lock(true).task(new RelayConnectionTask(this.connectionPool)).build().run(context); + } + return this; + } + + public void disconnect() throws TimeoutException { + ThreadUtil.builder().blocking(true).task(new RelayDisconnectionTask(this.connectionPool)).build().run(this.context); + } + + public int getOpenConnectionsCount() { + return connectionPool.connectionCount(); + } + + public void send(@NonNull BaseMessage message) throws TimeoutException { + log.log(Level.FINE, "Requesting to send the message {0}...", message); + ThreadUtil.builder().blocking(false).lock(true).task(new SendMessageTask(message, this.connectionPool)).build().run(this.context); + } + + boolean isConnected(@NonNull Relay relay) { + return this.connectionPool.isConnectedTo(relay); + } + + @AllArgsConstructor + private static class RelayConnectionTask implements Task { + + private final ConnectionPool connectionManager; + + @Override + public Void execute(@NonNull Context context) { + connectionManager.connect(); + return null; + } + } + + @AllArgsConstructor + private static class RelayDisconnectionTask implements Task { + + private final ConnectionPool connectionPool; + + @Override + public Void execute(@NonNull Context context) { + connectionPool.disconnect(); + return null; + } + } + + @AllArgsConstructor + private static class SendMessageTask implements Task { + + private final BaseMessage message; + private final ConnectionPool connectionPool; + + @Override + public Void execute(@NonNull Context context) { + // Only send AUTH messages to the relay mentioned in the tag https://github.com/tcheeric/nostr-java/issues/129 + if (message instanceof CanonicalAuthenticationMessage canonicalAuthenticationMessage) { + log.log(Level.FINE, ">>> Authentication message {0}...", canonicalAuthenticationMessage); + var event = canonicalAuthenticationMessage.getEvent(); + var relayTag = event.getTags().stream().filter(t -> t.getCode().equalsIgnoreCase("relay")).findFirst(); + if (relayTag.isPresent()) { + var relayTagValue = ((GenericTag) relayTag.get()).getAttributes().get(0).getValue().toString(); + log.log(Level.FINEST, "**** Relay found in CanonicalAuthenticationMessage: {0}", relayTagValue); + var r = new Relay(relayTagValue); + connectionPool.send(canonicalAuthenticationMessage.encode(), r); + } else { + log.log(Level.SEVERE, "Relay tag not found in CanonicalAuthenticationMessage. Ignoring..."); + } + } else { + log.log(Level.FINER, "+++ message {0}...", message); + connectionPool.send(message.encode()); + } + return null; + } + } } \ No newline at end of file diff --git a/nostr-java-event/src/main/java/nostr/event/json/serializer/CustomBaseListSerializer.java b/nostr-java-event/src/main/java/nostr/event/json/serializer/CustomBaseListSerializer.java index 74df7c381..2d3ba9b02 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/serializer/CustomBaseListSerializer.java +++ b/nostr-java-event/src/main/java/nostr/event/json/serializer/CustomBaseListSerializer.java @@ -1,12 +1,5 @@ package nostr.event.json.serializer; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import nostr.base.IEncoder; -import nostr.event.BaseEvent; - import java.io.IOException; import java.util.Iterator; import java.util.List; @@ -15,6 +8,13 @@ import java.util.Spliterators; import java.util.stream.StreamSupport; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import nostr.base.IEncoder; +import nostr.event.BaseEvent; + /** * @author guilhermegps * diff --git a/nostr-java-event/src/main/java/nostr/event/json/serializer/CustomIdEventListSerializer.java b/nostr-java-event/src/main/java/nostr/event/json/serializer/CustomIdEventListSerializer.java index 6f9ce64aa..63f507ef5 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/serializer/CustomIdEventListSerializer.java +++ b/nostr-java-event/src/main/java/nostr/event/json/serializer/CustomIdEventListSerializer.java @@ -9,7 +9,6 @@ import java.util.List; import java.util.Objects; - /** * @author guilhermegps */ diff --git a/nostr-java-event/src/main/java/nostr/event/message/CanonicalAuthenticationMessage.java b/nostr-java-event/src/main/java/nostr/event/message/CanonicalAuthenticationMessage.java index e3b4003f0..eb24c0432 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/CanonicalAuthenticationMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/CanonicalAuthenticationMessage.java @@ -1,4 +1,3 @@ - package nostr.event.message; import com.fasterxml.jackson.annotation.JsonProperty; @@ -11,6 +10,7 @@ import nostr.event.json.codec.BaseEventEncoder; /** + * * @author eric */ @Setter diff --git a/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java b/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java index 86ce41f92..79dabe367 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java @@ -45,7 +45,6 @@ public String encode() throws JsonProcessingException { getArrayNode() .add(getCommand()) .add(getSubscriptionId()); - // Encode each filter individually and join them with a comma List localFiltersList = getFiltersList(); for (Filters f : localFiltersList) { try { From 9341691091dff3141418538b83b488208b662428 Mon Sep 17 00:00:00 2001 From: nick avlo Date: Sat, 1 Jun 2024 23:26:18 -0700 Subject: [PATCH 03/12] exception handling --- .../src/main/java/nostr/client/Client.java | 4 +++- .../command/provider/AuthCommandHandler.java | 16 ++++++---------- .../command/provider/ClosedCommandHandler.java | 16 ++++++---------- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/nostr-java-client/src/main/java/nostr/client/Client.java b/nostr-java-client/src/main/java/nostr/client/Client.java index 0af27871d..d1cc550f2 100644 --- a/nostr-java-client/src/main/java/nostr/client/Client.java +++ b/nostr-java-client/src/main/java/nostr/client/Client.java @@ -3,6 +3,7 @@ import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.NonNull; +import lombok.SneakyThrows; import lombok.extern.java.Log; import nostr.base.Relay; import nostr.connection.impl.ConnectionPool; @@ -90,6 +91,7 @@ private static class SendMessageTask implements Task { private final BaseMessage message; private final ConnectionPool connectionPool; + @SneakyThrows @Override public Void execute(@NonNull Context context) { // Only send AUTH messages to the relay mentioned in the tag https://github.com/tcheeric/nostr-java/issues/129 @@ -112,4 +114,4 @@ public Void execute(@NonNull Context context) { return null; } } -} \ No newline at end of file +} diff --git a/nostr-java-command-provider/src/main/java/nostr/command/provider/AuthCommandHandler.java b/nostr-java-command-provider/src/main/java/nostr/command/provider/AuthCommandHandler.java index 71994cc8c..001c29f54 100644 --- a/nostr-java-command-provider/src/main/java/nostr/command/provider/AuthCommandHandler.java +++ b/nostr-java-command-provider/src/main/java/nostr/command/provider/AuthCommandHandler.java @@ -1,8 +1,8 @@ package nostr.command.provider; -import com.fasterxml.jackson.core.JsonProcessingException; import lombok.NoArgsConstructor; import lombok.NonNull; +import lombok.SneakyThrows; import lombok.extern.java.Log; import nostr.base.Command; import nostr.base.PrivateKey; @@ -16,7 +16,6 @@ import nostr.event.message.RelayAuthenticationMessage; import nostr.id.Identity; -import java.util.concurrent.TimeoutException; import java.util.logging.Level; @DefaultHandler(command = Command.AUTH) @@ -24,6 +23,7 @@ @Log public class AuthCommandHandler implements CommandHandler { + @SneakyThrows @Override public void handle(@NonNull CommandContext context) { @@ -49,15 +49,11 @@ public void handle(@NonNull CommandContext context) { var client = Client.getInstance(); var canonicalAuthenticationMessage = new CanonicalAuthenticationMessage(canonicalAuthenticationEvent); - try { - var encodedMessage = canonicalAuthenticationMessage.encode(); - log.log(Level.INFO, "Sending authentication event {0} to the relay {1}", new Object[]{encodedMessage, relay}); + var encodedMessage = canonicalAuthenticationMessage.encode(); + log.log(Level.INFO, "Sending authentication event {0} to the relay {1}", new Object[]{encodedMessage, relay}); - // Publish the event to the relay - client.send(canonicalAuthenticationMessage); - } catch (TimeoutException | JsonProcessingException e) { - throw new RuntimeException(e); - } + // Publish the event to the relay + client.send(canonicalAuthenticationMessage); } } else { throw new IllegalArgumentException("Invalid context type"); diff --git a/nostr-java-command-provider/src/main/java/nostr/command/provider/ClosedCommandHandler.java b/nostr-java-command-provider/src/main/java/nostr/command/provider/ClosedCommandHandler.java index 54288619c..20400e981 100644 --- a/nostr-java-command-provider/src/main/java/nostr/command/provider/ClosedCommandHandler.java +++ b/nostr-java-command-provider/src/main/java/nostr/command/provider/ClosedCommandHandler.java @@ -1,7 +1,7 @@ package nostr.command.provider; -import com.fasterxml.jackson.core.JsonProcessingException; import lombok.NoArgsConstructor; +import lombok.SneakyThrows; import lombok.extern.java.Log; import nostr.base.Command; import nostr.base.PrivateKey; @@ -15,7 +15,6 @@ import nostr.event.message.ClosedMessage; import nostr.id.Identity; -import java.util.concurrent.TimeoutException; import java.util.logging.Level; @DefaultHandler(command = Command.CLOSED) @@ -23,6 +22,7 @@ @Log public class ClosedCommandHandler implements CommandHandler { + @SneakyThrows @Override public void handle(CommandContext context) { @@ -49,15 +49,11 @@ public void handle(CommandContext context) { var client = Client.getInstance(); // No need to pass the request context here. The client will use the default one var canonicalAuthenticationMessage = new CanonicalAuthenticationMessage(canonicalAuthenticationEvent); - try { - var encodedMessage = canonicalAuthenticationMessage.encode(); - log.log(Level.INFO, "Sending authentication event {0} to the relay {1}", new Object[]{encodedMessage, relay}); + var encodedMessage = canonicalAuthenticationMessage.encode(); + log.log(Level.INFO, "Sending authentication event {0} to the relay {1}", new Object[]{encodedMessage, relay}); - // Publish the event to the relay - client.send(canonicalAuthenticationMessage); - } catch (TimeoutException | JsonProcessingException e) { - throw new RuntimeException(e); - } + // Publish the event to the relay + client.send(canonicalAuthenticationMessage); } } } else { From 53962e3e408792eea2fef4bcaecf47d61a1258dd Mon Sep 17 00:00:00 2001 From: nick avlo Date: Sat, 1 Jun 2024 23:31:28 -0700 Subject: [PATCH 04/12] maintain formatting --- .../src/main/java/nostr/api/NIP01.java | 144 +++++++++--------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/nostr-java-api/src/main/java/nostr/api/NIP01.java b/nostr-java-api/src/main/java/nostr/api/NIP01.java index 8e0a41380..f8158c018 100644 --- a/nostr-java-api/src/main/java/nostr/api/NIP01.java +++ b/nostr-java-api/src/main/java/nostr/api/NIP01.java @@ -46,10 +46,10 @@ * @author eric */ public class NIP01 extends EventNostr { - - public NIP01(@NonNull Identity sender) { - setSender(sender); - } + + public NIP01(@NonNull Identity sender) { + setSender(sender); + } /** * Create a NIP01 text note event without tags @@ -57,76 +57,76 @@ public NIP01(@NonNull Identity sender) { * @param content the content of the note * @return the text note without tags */ - public NIP01 createTextNoteEvent(@NonNull String content) { - var event = new TextNoteEventFactory(getSender(), content).create(); - this.setEvent((T) event); + public NIP01 createTextNoteEvent(@NonNull String content) { + var event = new TextNoteEventFactory(getSender(), content).create(); + this.setEvent((T) event); - return this; + return this; } - public NIP01 createTextNoteEvent(@NonNull Identity sender, @NonNull String content) { - var event = new TextNoteEventFactory(sender, content).create(); - this.setEvent((T) event); + public NIP01 createTextNoteEvent(@NonNull Identity sender, @NonNull String content) { + var event = new TextNoteEventFactory(sender, content).create(); + this.setEvent((T) event); - return this; + return this; } /** * Create a NIP01 text note event with tags * - * @param tags the note tags + * @param tags the note tags * @param content the content of the note * @return a text note event */ public NIP01 createTextNoteEvent(@NonNull List tags, @NonNull String content) { - setEvent((T) new TextNoteEventFactory(getSender(), tags, content).create()); - return this; + setEvent((T) new TextNoteEventFactory(getSender(), tags, content).create()); + return this; } public NIP01 createMetadataEvent(@NonNull UserProfile profile) { - var sender = getSender(); - var event = (sender != null) ? new MetadataEventFactory(sender, profile).create() : new MetadataEventFactory(profile).create(); - + var sender = getSender(); + var event = (sender!=null) ? new MetadataEventFactory(sender, profile).create() : new MetadataEventFactory(profile).create(); + this.setEvent((T) event); return this; } /** * Create a replaceable event - * @param kind the kind (10000 <= kind < 20000 || kind == 0 || kind == 3) + * @param kind the kind (10000 <= kind < 20000 || kind == 0 || kind == 3) * @param content the content */ public NIP01 createReplaceableEvent(@NonNull Integer kind, String content) { - var event = new ReplaceableEventFactory(getSender(), kind, content).create(); - + var event = new ReplaceableEventFactory(getSender(), kind, content).create(); + this.setEvent((T) event); return this; } - + /** * Create a replaceable event - * @param tags the note's tags - * @param kind the kind (10000 <= kind < 20000 || kind == 0 || kind == 3) + * @param tags the note's tags + * @param kind the kind (10000 <= kind < 20000 || kind == 0 || kind == 3) * @param content the note's content */ public NIP01 createReplaceableEvent(@NonNull List tags, @NonNull Integer kind, String content) { - var event = new ReplaceableEventFactory(getSender(), tags, kind, content).create(); - + var event = new ReplaceableEventFactory(getSender(), tags, kind, content).create(); + this.setEvent((T) event); return this; } /** * Create an ephemeral event - * @param kind the kind (20000 <= n < 30000) + * @param kind the kind (20000 <= n < 30000) * @param content the note's content */ public NIP01 createEphemeralEvent(@NonNull Integer kind, String content) { - var event = new EphemeralEventFactory(getSender(), kind, content).create(); - + var event = new EphemeralEventFactory(getSender(), kind, content).create(); + this.setEvent((T) event); - return this; - } + return this; + } /** * Create a NIP01 event tag @@ -141,9 +141,9 @@ public static EventTag createEventTag(@NonNull String relateEventId) { /** * Create a NIP01 event tag with additional recommended relay and marker * - * @param relateEventId the related event id + * @param relateEventId the related event id * @param recommendedRelayUrl the recommended relay - * @param marker the marker + * @param marker the marker * @return an event tag with the id of the related event and optional * recommended relay and marker */ @@ -169,9 +169,9 @@ public static PubKeyTag createPubKeyTag(@NonNull PublicKey publicKey) { * Create a NIP01 pubkey tag with additional recommended relay and petname * (as defined in NIP02) * - * @param publicKey the associated public key + * @param publicKey the associated public key * @param mainRelayUrl the recommended relay - * @param petName the petname + * @param petName the petname * @return a pubkey tag with the hex representation of the associated public * key and the optional recommended relay and petname */ @@ -185,41 +185,41 @@ public static PubKeyTag createPubKeyTag(@NonNull PublicKey publicKey, String mai /** * Create a NIP01 filters object (all parameters are optional) * - * @param events a list of event - * @param authors a list of pubkeys or prefixes, the pubkey of an event must - * be one of these - * @param kinds a list of a kind numbers + * @param events a list of event + * @param authors a list of pubkeys or prefixes, the pubkey of an event must + * be one of these + * @param kinds a list of a kind numbers * @param referencedEvents a list of event ids that are referenced in an "e" - * tag + * tag * @param referencePubKeys a list of pubkeys that are referenced in a "p" - * tag - * @param since an integer unix timestamp in seconds, events must be newer - * than this to pass - * @param until an integer unix timestamp in seconds, events must be older - * than this to pass - * @param limit maximum number of events to be returned in the initial query - * @param genericTagQuery a generic tag query + * tag + * @param since an integer unix timestamp in seconds, events must be newer + * than this to pass + * @param until an integer unix timestamp in seconds, events must be older + * than this to pass + * @param limit maximum number of events to be returned in the initial query + * @param genericTagQuery a generic tag query * @return a filters object */ @Deprecated(forRemoval = true) public static Filters createFilters(List events, List authors, List kinds, List referencedEvents, List referencePubKeys, Long since, Long until, Integer limit, GenericTagQuery genericTagQuery) { return Filters.builder() - .authors(authors) - .events(events) - .genericTagQuery(genericTagQuery) - .kinds(kinds).limit(limit) - .referencePubKeys(referencePubKeys) - .referencedEvents(referencedEvents) - .since(since) - .until(until) - .build(); + .authors(authors) + .events(events) + .genericTagQuery(genericTagQuery) + .kinds(kinds).limit(limit) + .referencePubKeys(referencePubKeys) + .referencedEvents(referencedEvents) + .since(since) + .until(until) + .build(); } /** * Create an event message to send events requested by clients * - * @param event the related event + * @param event the related event * @param subscriptionId the related subscription id * @return an event message */ @@ -231,7 +231,7 @@ public static EventMessage createEventMessage(@NonNull IEvent event, @NonNull St * Create a REQ message to request events and subscribe to new updates * * @param subscriptionId the subscription id - * @param filtersList the filters list + * @param filtersList the filters list * @return a REQ message */ public static ReqMessage createReqMessage(@NonNull String subscriptionId, @NonNull List filtersList) { @@ -271,46 +271,46 @@ public static NoticeMessage createNoticeMessage(@NonNull String message) { } /** - * + * * @param comment the event's comment */ public NIP01 createParameterizedReplaceableEvent(@NonNull Integer kind, String comment) { - var event = new ParameterizedReplaceableEventFactory(getSender(), kind, comment).create(); - + var event = new ParameterizedReplaceableEventFactory(getSender(), kind, comment).create(); + this.setEvent((T) event); return this; } - + /** - * + * * @param tags * @param kind * @param comment - * @return + * @return */ public NIP01 createParameterizedReplaceableEvent(@NonNull List tags, @NonNull Integer kind, String comment) { - var event = new ParameterizedReplaceableEventFactory(getSender(), tags, kind, comment).create(); - + var event = new ParameterizedReplaceableEventFactory(getSender(), tags, kind, comment).create(); + this.setEvent((T) event); return this; } - + /** - * + * * @param id - * @return + * @return */ public static IdentifierTag createIdentifierTag(@NonNull String id) { return new IdentifierTagFactory(id).create(); } /** - * + * * @param kind * @param publicKey * @param idTag * @param relay - * @return + * @return */ public static AddressTag createAddressTag(@NonNull Integer kind, @NonNull PublicKey publicKey, @NonNull IdentifierTag idTag, Relay relay) { var result = new AddressTagFactory(publicKey).create(); @@ -318,5 +318,5 @@ public static AddressTag createAddressTag(@NonNull Integer kind, @NonNull Public result.setKind(kind); result.setRelay(relay); return result; - } + } } From 785795ea034b811db8e67a6738c45f4f0425207e Mon Sep 17 00:00:00 2001 From: nick avlo Date: Sat, 1 Jun 2024 23:45:48 -0700 Subject: [PATCH 05/12] preserve formatting --- .../src/main/java/nostr/api/NIP01.java | 8 +++-- .../nostr/api/factory/impl/NIP01Impl.java | 34 +++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/nostr-java-api/src/main/java/nostr/api/NIP01.java b/nostr-java-api/src/main/java/nostr/api/NIP01.java index f8158c018..bbf2c4951 100644 --- a/nostr-java-api/src/main/java/nostr/api/NIP01.java +++ b/nostr-java-api/src/main/java/nostr/api/NIP01.java @@ -9,9 +9,11 @@ import nostr.api.factory.impl.NIP01Impl.CloseMessageFactory; import nostr.api.factory.impl.NIP01Impl.EoseMessageFactory; import nostr.api.factory.impl.NIP01Impl.EphemeralEventFactory; +import nostr.api.factory.impl.NIP01Impl.EventMessageFactory; import nostr.api.factory.impl.NIP01Impl.EventTagFactory; import nostr.api.factory.impl.NIP01Impl.IdentifierTagFactory; import nostr.api.factory.impl.NIP01Impl.MetadataEventFactory; +import nostr.api.factory.impl.NIP01Impl.NoticeMessageFactory; import nostr.api.factory.impl.NIP01Impl.ParameterizedReplaceableEventFactory; import nostr.api.factory.impl.NIP01Impl.PubKeyTagFactory; import nostr.api.factory.impl.NIP01Impl.ReplaceableEventFactory; @@ -224,7 +226,9 @@ public static Filters createFilters(List events, List a * @return an event message */ public static EventMessage createEventMessage(@NonNull IEvent event, @NonNull String subscriptionId) { - return new EventMessage(event, subscriptionId); + var result = new EventMessageFactory(event).create(); + result.setSubscriptionId(subscriptionId); + return result; } /** @@ -267,7 +271,7 @@ public static EoseMessage createEoseMessage(@NonNull String subscriptionId) { * @return a NOTICE message */ public static NoticeMessage createNoticeMessage(@NonNull String message) { - return new NoticeMessage(message); + return new NoticeMessageFactory(message).create(); } /** diff --git a/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java b/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java index 8ce12827b..d1eee0eee 100644 --- a/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java +++ b/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java @@ -11,6 +11,7 @@ import nostr.api.factory.AbstractTagFactory; import nostr.api.factory.EventFactory; import nostr.api.factory.MessageFactory; +import nostr.base.IEvent; import nostr.base.PublicKey; import nostr.base.Relay; import nostr.base.UserProfile; @@ -24,6 +25,8 @@ import nostr.event.impl.TextNoteEvent; import nostr.event.message.CloseMessage; import nostr.event.message.EoseMessage; +import nostr.event.message.EventMessage; +import nostr.event.message.NoticeMessage; import nostr.event.message.ReqMessage; import nostr.event.tag.AddressTag; import nostr.event.tag.EventTag; @@ -117,6 +120,24 @@ public PubKeyTag create() { } } + @Data + @EqualsAndHashCode(callSuper = false) + public static class EventMessageFactory extends MessageFactory { + + private final IEvent event; + private String subscriptionId; + + public EventMessageFactory(@NonNull IEvent event) { + this.event = event; + } + + @Override + public EventMessage create() { + return new EventMessage(event, subscriptionId); + } + + } + @Data @EqualsAndHashCode(callSuper = false) @AllArgsConstructor @@ -255,6 +276,19 @@ public EoseMessage create() { } } + @Data + @EqualsAndHashCode(callSuper = false) + @AllArgsConstructor + public static class NoticeMessageFactory extends MessageFactory { + + private final String message; + + @Override + public NoticeMessage create() { + return new NoticeMessage(message); + } + } + public static class Kinds { public static final Integer KIND_SET_METADATA = 0; From 0244604cb570f7189521c5bb341cc4632895c067 Mon Sep 17 00:00:00 2001 From: nick avlo Date: Sat, 1 Jun 2024 23:55:18 -0700 Subject: [PATCH 06/12] sneaky throws --- .../src/main/java/nostr/client/Client.java | 234 +++++++++--------- 1 file changed, 117 insertions(+), 117 deletions(-) diff --git a/nostr-java-client/src/main/java/nostr/client/Client.java b/nostr-java-client/src/main/java/nostr/client/Client.java index d1cc550f2..c70486213 100644 --- a/nostr-java-client/src/main/java/nostr/client/Client.java +++ b/nostr-java-client/src/main/java/nostr/client/Client.java @@ -1,117 +1,117 @@ -package nostr.client; - -import lombok.AllArgsConstructor; -import lombok.NoArgsConstructor; -import lombok.NonNull; -import lombok.SneakyThrows; -import lombok.extern.java.Log; -import nostr.base.Relay; -import nostr.connection.impl.ConnectionPool; -import nostr.context.Context; -import nostr.context.RequestContext; -import nostr.context.impl.DefaultRequestContext; -import nostr.event.BaseMessage; -import nostr.event.impl.GenericTag; -import nostr.event.message.CanonicalAuthenticationMessage; -import nostr.util.thread.Task; -import nostr.util.thread.ThreadUtil; - -import java.util.concurrent.TimeoutException; -import java.util.logging.Level; - -@Log -@NoArgsConstructor -public class Client { - - private static class Holder { - private static final Client INSTANCE = new Client(); - } - - private RequestContext context; - - private ConnectionPool connectionPool; - - public static Client getInstance() { - return Holder.INSTANCE; - } - - public Client connect(@NonNull RequestContext context) throws TimeoutException { - if (context instanceof DefaultRequestContext defaultRequestContext) { - Holder.INSTANCE.context = context; - connectionPool = ConnectionPool.getInstance(defaultRequestContext); - ThreadUtil.builder().blocking(true).lock(true).task(new RelayConnectionTask(this.connectionPool)).build().run(context); - } - return this; - } - - public void disconnect() throws TimeoutException { - ThreadUtil.builder().blocking(true).task(new RelayDisconnectionTask(this.connectionPool)).build().run(this.context); - } - - public int getOpenConnectionsCount() { - return connectionPool.connectionCount(); - } - - public void send(@NonNull BaseMessage message) throws TimeoutException { - log.log(Level.FINE, "Requesting to send the message {0}...", message); - ThreadUtil.builder().blocking(false).lock(true).task(new SendMessageTask(message, this.connectionPool)).build().run(this.context); - } - - boolean isConnected(@NonNull Relay relay) { - return this.connectionPool.isConnectedTo(relay); - } - - @AllArgsConstructor - private static class RelayConnectionTask implements Task { - - private final ConnectionPool connectionManager; - - @Override - public Void execute(@NonNull Context context) { - connectionManager.connect(); - return null; - } - } - - @AllArgsConstructor - private static class RelayDisconnectionTask implements Task { - - private final ConnectionPool connectionPool; - - @Override - public Void execute(@NonNull Context context) { - connectionPool.disconnect(); - return null; - } - } - - @AllArgsConstructor - private static class SendMessageTask implements Task { - - private final BaseMessage message; - private final ConnectionPool connectionPool; - - @SneakyThrows - @Override - public Void execute(@NonNull Context context) { - // Only send AUTH messages to the relay mentioned in the tag https://github.com/tcheeric/nostr-java/issues/129 - if (message instanceof CanonicalAuthenticationMessage canonicalAuthenticationMessage) { - log.log(Level.FINE, ">>> Authentication message {0}...", canonicalAuthenticationMessage); - var event = canonicalAuthenticationMessage.getEvent(); - var relayTag = event.getTags().stream().filter(t -> t.getCode().equalsIgnoreCase("relay")).findFirst(); - if (relayTag.isPresent()) { - var relayTagValue = ((GenericTag) relayTag.get()).getAttributes().get(0).getValue().toString(); - log.log(Level.FINEST, "**** Relay found in CanonicalAuthenticationMessage: {0}", relayTagValue); - var r = new Relay(relayTagValue); - connectionPool.send(canonicalAuthenticationMessage.encode(), r); - } else { - log.log(Level.SEVERE, "Relay tag not found in CanonicalAuthenticationMessage. Ignoring..."); - } - } else { - log.log(Level.FINER, "+++ message {0}...", message); - connectionPool.send(message.encode()); - } - return null; - } - } -} +package nostr.client; + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.SneakyThrows; +import lombok.extern.java.Log; +import nostr.base.Relay; +import nostr.connection.impl.ConnectionPool; +import nostr.context.Context; +import nostr.context.RequestContext; +import nostr.context.impl.DefaultRequestContext; +import nostr.event.BaseMessage; +import nostr.event.impl.GenericTag; +import nostr.event.message.CanonicalAuthenticationMessage; +import nostr.util.thread.Task; +import nostr.util.thread.ThreadUtil; + +import java.util.concurrent.TimeoutException; +import java.util.logging.Level; + +@Log +@NoArgsConstructor +public class Client { + + private static class Holder { + private static final Client INSTANCE = new Client(); + } + + private RequestContext context; + + private ConnectionPool connectionPool; + + public static Client getInstance() { + return Holder.INSTANCE; + } + + public Client connect(@NonNull RequestContext context) throws TimeoutException { + if (context instanceof DefaultRequestContext defaultRequestContext) { + Holder.INSTANCE.context = context; + connectionPool = ConnectionPool.getInstance(defaultRequestContext); + ThreadUtil.builder().blocking(true).lock(true).task(new RelayConnectionTask(this.connectionPool)).build().run(context); + } + return this; + } + + public void disconnect() throws TimeoutException { + ThreadUtil.builder().blocking(true).task(new RelayDisconnectionTask(this.connectionPool)).build().run(this.context); + } + + public int getOpenConnectionsCount() { + return connectionPool.connectionCount(); + } + + public void send(@NonNull BaseMessage message) throws TimeoutException { + log.log(Level.FINE, "Requesting to send the message {0}...", message); + ThreadUtil.builder().blocking(false).lock(true).task(new SendMessageTask(message, this.connectionPool)).build().run(this.context); + } + + boolean isConnected(@NonNull Relay relay) { + return this.connectionPool.isConnectedTo(relay); + } + + @AllArgsConstructor + private static class RelayConnectionTask implements Task { + + private final ConnectionPool connectionManager; + + @Override + public Void execute(@NonNull Context context) { + connectionManager.connect(); + return null; + } + } + + @AllArgsConstructor + private static class RelayDisconnectionTask implements Task { + + private final ConnectionPool connectionPool; + + @Override + public Void execute(@NonNull Context context) { + connectionPool.disconnect(); + return null; + } + } + + @AllArgsConstructor + private static class SendMessageTask implements Task { + + private final BaseMessage message; + private final ConnectionPool connectionPool; + + @SneakyThrows + @Override + public Void execute(@NonNull Context context) { + // Only send AUTH messages to the relay mentioned in the tag https://github.com/tcheeric/nostr-java/issues/129 + if (message instanceof CanonicalAuthenticationMessage canonicalAuthenticationMessage) { + log.log(Level.FINE, ">>> Authentication message {0}...", canonicalAuthenticationMessage); + var event = canonicalAuthenticationMessage.getEvent(); + var relayTag = event.getTags().stream().filter(t -> t.getCode().equalsIgnoreCase("relay")).findFirst(); + if (relayTag.isPresent()) { + var relayTagValue = ((GenericTag) relayTag.get()).getAttributes().get(0).getValue().toString(); + log.log(Level.FINEST, "**** Relay found in CanonicalAuthenticationMessage: {0}", relayTagValue); + var r = new Relay(relayTagValue); + connectionPool.send(canonicalAuthenticationMessage.encode(), r); + } else { + log.log(Level.SEVERE, "Relay tag not found in CanonicalAuthenticationMessage. Ignoring..."); + } + } else { + log.log(Level.FINER, "+++ message {0}...", message); + connectionPool.send(message.encode()); + } + return null; + } + } +} \ No newline at end of file From 23a0e97a0688b543a65bb24566e32254ffff8429 Mon Sep 17 00:00:00 2001 From: nick avlo Date: Sat, 1 Jun 2024 23:59:17 -0700 Subject: [PATCH 07/12] preserve formatting --- .../src/main/java/nostr/client/Client.java | 232 +++++++++--------- .../src/main/java/module-info.java | 3 +- 2 files changed, 117 insertions(+), 118 deletions(-) diff --git a/nostr-java-client/src/main/java/nostr/client/Client.java b/nostr-java-client/src/main/java/nostr/client/Client.java index c70486213..1dd19f451 100644 --- a/nostr-java-client/src/main/java/nostr/client/Client.java +++ b/nostr-java-client/src/main/java/nostr/client/Client.java @@ -1,117 +1,117 @@ -package nostr.client; - -import lombok.AllArgsConstructor; -import lombok.NoArgsConstructor; -import lombok.NonNull; -import lombok.SneakyThrows; -import lombok.extern.java.Log; -import nostr.base.Relay; -import nostr.connection.impl.ConnectionPool; -import nostr.context.Context; -import nostr.context.RequestContext; -import nostr.context.impl.DefaultRequestContext; -import nostr.event.BaseMessage; -import nostr.event.impl.GenericTag; -import nostr.event.message.CanonicalAuthenticationMessage; -import nostr.util.thread.Task; -import nostr.util.thread.ThreadUtil; - -import java.util.concurrent.TimeoutException; -import java.util.logging.Level; - -@Log -@NoArgsConstructor -public class Client { - - private static class Holder { - private static final Client INSTANCE = new Client(); - } - - private RequestContext context; - - private ConnectionPool connectionPool; - - public static Client getInstance() { - return Holder.INSTANCE; - } - - public Client connect(@NonNull RequestContext context) throws TimeoutException { - if (context instanceof DefaultRequestContext defaultRequestContext) { - Holder.INSTANCE.context = context; - connectionPool = ConnectionPool.getInstance(defaultRequestContext); - ThreadUtil.builder().blocking(true).lock(true).task(new RelayConnectionTask(this.connectionPool)).build().run(context); - } - return this; - } - - public void disconnect() throws TimeoutException { - ThreadUtil.builder().blocking(true).task(new RelayDisconnectionTask(this.connectionPool)).build().run(this.context); - } - - public int getOpenConnectionsCount() { - return connectionPool.connectionCount(); - } - - public void send(@NonNull BaseMessage message) throws TimeoutException { - log.log(Level.FINE, "Requesting to send the message {0}...", message); - ThreadUtil.builder().blocking(false).lock(true).task(new SendMessageTask(message, this.connectionPool)).build().run(this.context); - } - - boolean isConnected(@NonNull Relay relay) { - return this.connectionPool.isConnectedTo(relay); - } - - @AllArgsConstructor - private static class RelayConnectionTask implements Task { - - private final ConnectionPool connectionManager; - - @Override - public Void execute(@NonNull Context context) { - connectionManager.connect(); - return null; - } - } - - @AllArgsConstructor - private static class RelayDisconnectionTask implements Task { - - private final ConnectionPool connectionPool; - - @Override - public Void execute(@NonNull Context context) { - connectionPool.disconnect(); - return null; - } - } - - @AllArgsConstructor - private static class SendMessageTask implements Task { - - private final BaseMessage message; - private final ConnectionPool connectionPool; - - @SneakyThrows - @Override - public Void execute(@NonNull Context context) { - // Only send AUTH messages to the relay mentioned in the tag https://github.com/tcheeric/nostr-java/issues/129 - if (message instanceof CanonicalAuthenticationMessage canonicalAuthenticationMessage) { - log.log(Level.FINE, ">>> Authentication message {0}...", canonicalAuthenticationMessage); - var event = canonicalAuthenticationMessage.getEvent(); - var relayTag = event.getTags().stream().filter(t -> t.getCode().equalsIgnoreCase("relay")).findFirst(); - if (relayTag.isPresent()) { - var relayTagValue = ((GenericTag) relayTag.get()).getAttributes().get(0).getValue().toString(); - log.log(Level.FINEST, "**** Relay found in CanonicalAuthenticationMessage: {0}", relayTagValue); - var r = new Relay(relayTagValue); - connectionPool.send(canonicalAuthenticationMessage.encode(), r); - } else { - log.log(Level.SEVERE, "Relay tag not found in CanonicalAuthenticationMessage. Ignoring..."); - } - } else { - log.log(Level.FINER, "+++ message {0}...", message); - connectionPool.send(message.encode()); - } - return null; - } - } +package nostr.client; + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.SneakyThrows; +import lombok.extern.java.Log; +import nostr.base.Relay; +import nostr.connection.impl.ConnectionPool; +import nostr.context.Context; +import nostr.context.RequestContext; +import nostr.context.impl.DefaultRequestContext; +import nostr.event.BaseMessage; +import nostr.event.impl.GenericTag; +import nostr.event.message.CanonicalAuthenticationMessage; +import nostr.util.thread.Task; +import nostr.util.thread.ThreadUtil; + +import java.util.concurrent.TimeoutException; +import java.util.logging.Level; + +@Log +@NoArgsConstructor +public class Client { + + private static class Holder { + private static final Client INSTANCE = new Client(); + } + + private RequestContext context; + + private ConnectionPool connectionPool; + + public static Client getInstance() { + return Holder.INSTANCE; + } + + public Client connect(@NonNull RequestContext context) throws TimeoutException { + if (context instanceof DefaultRequestContext defaultRequestContext) { + Holder.INSTANCE.context = context; + connectionPool = ConnectionPool.getInstance(defaultRequestContext); + ThreadUtil.builder().blocking(true).lock(true).task(new RelayConnectionTask(this.connectionPool)).build().run(context); + } + return this; + } + + public void disconnect() throws TimeoutException { + ThreadUtil.builder().blocking(true).task(new RelayDisconnectionTask(this.connectionPool)).build().run(this.context); + } + + public int getOpenConnectionsCount() { + return connectionPool.connectionCount(); + } + + public void send(@NonNull BaseMessage message) throws TimeoutException { + log.log(Level.FINE, "Requesting to send the message {0}...", message); + ThreadUtil.builder().blocking(false).lock(true).task(new SendMessageTask(message, this.connectionPool)).build().run(this.context); + } + + boolean isConnected(@NonNull Relay relay) { + return this.connectionPool.isConnectedTo(relay); + } + + @AllArgsConstructor + private static class RelayConnectionTask implements Task { + + private final ConnectionPool connectionManager; + + @Override + public Void execute(@NonNull Context context) { + connectionManager.connect(); + return null; + } + } + + @AllArgsConstructor + private static class RelayDisconnectionTask implements Task { + + private final ConnectionPool connectionPool; + + @Override + public Void execute(@NonNull Context context) { + connectionPool.disconnect(); + return null; + } + } + + @AllArgsConstructor + private static class SendMessageTask implements Task { + + private final BaseMessage message; + private final ConnectionPool connectionPool; + + @SneakyThrows + @Override + public Void execute(@NonNull Context context) { + // Only send AUTH messages to the relay mentioned in the tag https://github.com/tcheeric/nostr-java/issues/129 + if (message instanceof CanonicalAuthenticationMessage canonicalAuthenticationMessage) { + log.log(Level.FINE, ">>> Authentication message {0}...", canonicalAuthenticationMessage); + var event = canonicalAuthenticationMessage.getEvent(); + var relayTag = event.getTags().stream().filter(t -> t.getCode().equalsIgnoreCase("relay")).findFirst(); + if (relayTag.isPresent()) { + var relayTagValue = ((GenericTag) relayTag.get()).getAttributes().get(0).getValue().toString(); + log.log(Level.FINEST, "**** Relay found in CanonicalAuthenticationMessage: {0}", relayTagValue); + var r = new Relay(relayTagValue); + connectionPool.send(canonicalAuthenticationMessage.encode(), r); + } else { + log.log(Level.SEVERE, "Relay tag not found in CanonicalAuthenticationMessage. Ignoring..."); + } + } else { + log.log(Level.FINER, "+++ message {0}...", message); + connectionPool.send(message.encode()); + } + return null; + } + } } \ No newline at end of file diff --git a/nostr-java-command-provider/src/main/java/module-info.java b/nostr-java-command-provider/src/main/java/module-info.java index 34f9f62c2..0bb8c75ea 100644 --- a/nostr-java-command-provider/src/main/java/module-info.java +++ b/nostr-java-command-provider/src/main/java/module-info.java @@ -17,9 +17,8 @@ requires nostr.context; requires nostr.context.impl; requires nostr.command.handler; - requires com.fasterxml.jackson.core; - exports nostr.command.provider; + exports nostr.command.provider; provides CommandHandler with OkCommandHandler, From a18ebc191e2c7ba207dce7c1704452921bc2db26 Mon Sep 17 00:00:00 2001 From: nick avlo Date: Sun, 2 Jun 2024 00:00:53 -0700 Subject: [PATCH 08/12] preserve formatting --- .../src/main/java/nostr/client/Client.java | 232 +++++++++--------- 1 file changed, 116 insertions(+), 116 deletions(-) diff --git a/nostr-java-client/src/main/java/nostr/client/Client.java b/nostr-java-client/src/main/java/nostr/client/Client.java index 1dd19f451..c70486213 100644 --- a/nostr-java-client/src/main/java/nostr/client/Client.java +++ b/nostr-java-client/src/main/java/nostr/client/Client.java @@ -1,117 +1,117 @@ -package nostr.client; - -import lombok.AllArgsConstructor; -import lombok.NoArgsConstructor; -import lombok.NonNull; -import lombok.SneakyThrows; -import lombok.extern.java.Log; -import nostr.base.Relay; -import nostr.connection.impl.ConnectionPool; -import nostr.context.Context; -import nostr.context.RequestContext; -import nostr.context.impl.DefaultRequestContext; -import nostr.event.BaseMessage; -import nostr.event.impl.GenericTag; -import nostr.event.message.CanonicalAuthenticationMessage; -import nostr.util.thread.Task; -import nostr.util.thread.ThreadUtil; - -import java.util.concurrent.TimeoutException; -import java.util.logging.Level; - -@Log -@NoArgsConstructor -public class Client { - - private static class Holder { - private static final Client INSTANCE = new Client(); - } - - private RequestContext context; - - private ConnectionPool connectionPool; - - public static Client getInstance() { - return Holder.INSTANCE; - } - - public Client connect(@NonNull RequestContext context) throws TimeoutException { - if (context instanceof DefaultRequestContext defaultRequestContext) { - Holder.INSTANCE.context = context; - connectionPool = ConnectionPool.getInstance(defaultRequestContext); - ThreadUtil.builder().blocking(true).lock(true).task(new RelayConnectionTask(this.connectionPool)).build().run(context); - } - return this; - } - - public void disconnect() throws TimeoutException { - ThreadUtil.builder().blocking(true).task(new RelayDisconnectionTask(this.connectionPool)).build().run(this.context); - } - - public int getOpenConnectionsCount() { - return connectionPool.connectionCount(); - } - - public void send(@NonNull BaseMessage message) throws TimeoutException { - log.log(Level.FINE, "Requesting to send the message {0}...", message); - ThreadUtil.builder().blocking(false).lock(true).task(new SendMessageTask(message, this.connectionPool)).build().run(this.context); - } - - boolean isConnected(@NonNull Relay relay) { - return this.connectionPool.isConnectedTo(relay); - } - - @AllArgsConstructor - private static class RelayConnectionTask implements Task { - - private final ConnectionPool connectionManager; - - @Override - public Void execute(@NonNull Context context) { - connectionManager.connect(); - return null; - } - } - - @AllArgsConstructor - private static class RelayDisconnectionTask implements Task { - - private final ConnectionPool connectionPool; - - @Override - public Void execute(@NonNull Context context) { - connectionPool.disconnect(); - return null; - } - } - - @AllArgsConstructor - private static class SendMessageTask implements Task { - - private final BaseMessage message; - private final ConnectionPool connectionPool; - - @SneakyThrows - @Override - public Void execute(@NonNull Context context) { - // Only send AUTH messages to the relay mentioned in the tag https://github.com/tcheeric/nostr-java/issues/129 - if (message instanceof CanonicalAuthenticationMessage canonicalAuthenticationMessage) { - log.log(Level.FINE, ">>> Authentication message {0}...", canonicalAuthenticationMessage); - var event = canonicalAuthenticationMessage.getEvent(); - var relayTag = event.getTags().stream().filter(t -> t.getCode().equalsIgnoreCase("relay")).findFirst(); - if (relayTag.isPresent()) { - var relayTagValue = ((GenericTag) relayTag.get()).getAttributes().get(0).getValue().toString(); - log.log(Level.FINEST, "**** Relay found in CanonicalAuthenticationMessage: {0}", relayTagValue); - var r = new Relay(relayTagValue); - connectionPool.send(canonicalAuthenticationMessage.encode(), r); - } else { - log.log(Level.SEVERE, "Relay tag not found in CanonicalAuthenticationMessage. Ignoring..."); - } - } else { - log.log(Level.FINER, "+++ message {0}...", message); - connectionPool.send(message.encode()); - } - return null; - } - } +package nostr.client; + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.SneakyThrows; +import lombok.extern.java.Log; +import nostr.base.Relay; +import nostr.connection.impl.ConnectionPool; +import nostr.context.Context; +import nostr.context.RequestContext; +import nostr.context.impl.DefaultRequestContext; +import nostr.event.BaseMessage; +import nostr.event.impl.GenericTag; +import nostr.event.message.CanonicalAuthenticationMessage; +import nostr.util.thread.Task; +import nostr.util.thread.ThreadUtil; + +import java.util.concurrent.TimeoutException; +import java.util.logging.Level; + +@Log +@NoArgsConstructor +public class Client { + + private static class Holder { + private static final Client INSTANCE = new Client(); + } + + private RequestContext context; + + private ConnectionPool connectionPool; + + public static Client getInstance() { + return Holder.INSTANCE; + } + + public Client connect(@NonNull RequestContext context) throws TimeoutException { + if (context instanceof DefaultRequestContext defaultRequestContext) { + Holder.INSTANCE.context = context; + connectionPool = ConnectionPool.getInstance(defaultRequestContext); + ThreadUtil.builder().blocking(true).lock(true).task(new RelayConnectionTask(this.connectionPool)).build().run(context); + } + return this; + } + + public void disconnect() throws TimeoutException { + ThreadUtil.builder().blocking(true).task(new RelayDisconnectionTask(this.connectionPool)).build().run(this.context); + } + + public int getOpenConnectionsCount() { + return connectionPool.connectionCount(); + } + + public void send(@NonNull BaseMessage message) throws TimeoutException { + log.log(Level.FINE, "Requesting to send the message {0}...", message); + ThreadUtil.builder().blocking(false).lock(true).task(new SendMessageTask(message, this.connectionPool)).build().run(this.context); + } + + boolean isConnected(@NonNull Relay relay) { + return this.connectionPool.isConnectedTo(relay); + } + + @AllArgsConstructor + private static class RelayConnectionTask implements Task { + + private final ConnectionPool connectionManager; + + @Override + public Void execute(@NonNull Context context) { + connectionManager.connect(); + return null; + } + } + + @AllArgsConstructor + private static class RelayDisconnectionTask implements Task { + + private final ConnectionPool connectionPool; + + @Override + public Void execute(@NonNull Context context) { + connectionPool.disconnect(); + return null; + } + } + + @AllArgsConstructor + private static class SendMessageTask implements Task { + + private final BaseMessage message; + private final ConnectionPool connectionPool; + + @SneakyThrows + @Override + public Void execute(@NonNull Context context) { + // Only send AUTH messages to the relay mentioned in the tag https://github.com/tcheeric/nostr-java/issues/129 + if (message instanceof CanonicalAuthenticationMessage canonicalAuthenticationMessage) { + log.log(Level.FINE, ">>> Authentication message {0}...", canonicalAuthenticationMessage); + var event = canonicalAuthenticationMessage.getEvent(); + var relayTag = event.getTags().stream().filter(t -> t.getCode().equalsIgnoreCase("relay")).findFirst(); + if (relayTag.isPresent()) { + var relayTagValue = ((GenericTag) relayTag.get()).getAttributes().get(0).getValue().toString(); + log.log(Level.FINEST, "**** Relay found in CanonicalAuthenticationMessage: {0}", relayTagValue); + var r = new Relay(relayTagValue); + connectionPool.send(canonicalAuthenticationMessage.encode(), r); + } else { + log.log(Level.SEVERE, "Relay tag not found in CanonicalAuthenticationMessage. Ignoring..."); + } + } else { + log.log(Level.FINER, "+++ message {0}...", message); + connectionPool.send(message.encode()); + } + return null; + } + } } \ No newline at end of file From 10dc54bcb853518f82af212333fe8146a93e18d5 Mon Sep 17 00:00:00 2001 From: nick avlo Date: Sun, 2 Jun 2024 01:21:42 -0700 Subject: [PATCH 09/12] decoder refactor --- .../src/main/java/nostr/api/Nostr.java | 9 +- .../src/main/java/nostr/base/IDecoder.java | 6 +- .../src/main/java/module-info.java | 1 + .../impl/listeners/TextListener.java | 3 +- .../java/nostr/event/impl/GenericMessage.java | 11 ++ .../event/json/codec/BaseMessageDecoder.java | 113 ++++-------------- .../event/json/codec/BaseTagDecoder.java | 6 +- .../event/json/codec/GenericEventDecoder.java | 6 +- .../event/json/codec/GenericTagDecoder.java | 8 +- .../event/json/codec/Nip05ContentDecoder.java | 8 +- .../CustomEventListDeserializer.java | 3 +- .../json/deserializer/TagDeserializer.java | 3 +- .../CanonicalAuthenticationMessage.java | 11 ++ .../nostr/event/message/CloseMessage.java | 5 + .../java/nostr/event/message/EoseMessage.java | 5 + .../nostr/event/message/EventMessage.java | 20 ++++ .../nostr/event/message/NoticeMessage.java | 4 + .../java/nostr/event/message/OkMessage.java | 10 ++ .../message/RelayAuthenticationMessage.java | 6 + .../java/nostr/event/message/ReqMessage.java | 12 ++ .../java/nostr/event/util/Nip05Validator.java | 4 +- .../java/nostr/test/event/DecodeTest.java | 3 +- .../java/nostr/test/json/JsonParseTest.java | 25 ++-- 23 files changed, 142 insertions(+), 140 deletions(-) diff --git a/nostr-java-api/src/main/java/nostr/api/Nostr.java b/nostr-java-api/src/main/java/nostr/api/Nostr.java index f26db6d14..038f35ab5 100644 --- a/nostr-java-api/src/main/java/nostr/api/Nostr.java +++ b/nostr-java-api/src/main/java/nostr/api/Nostr.java @@ -194,8 +194,7 @@ public static String encode(@NonNull BaseEvent event, Relay relay) { * @param json */ public static GenericEvent decodeEvent(@NonNull String json) { - final var dec = new GenericEventDecoder(json); - return dec.decode(); + return new GenericEventDecoder<>().decode(json); } // Messages @@ -219,8 +218,7 @@ public static String encode(@NonNull BaseMessage message) throws JsonProcessingE * @param json */ public static BaseMessage decodeMessage(@NonNull String json) { - final var dec = new BaseMessageDecoder(json); - return dec.decode(); + return new BaseMessageDecoder().decode(json); } // Tags @@ -245,8 +243,7 @@ public static String encode(@NonNull BaseTag tag) { * @param json */ public static BaseTag decodeTag(@NonNull String json) { - final var dec = new BaseTagDecoder(json); - return dec.decode(); + return new BaseTagDecoder<>().decode(json); } // Filters diff --git a/nostr-java-base/src/main/java/nostr/base/IDecoder.java b/nostr-java-base/src/main/java/nostr/base/IDecoder.java index 4fb9fcd09..f94d95120 100644 --- a/nostr-java-base/src/main/java/nostr/base/IDecoder.java +++ b/nostr-java-base/src/main/java/nostr/base/IDecoder.java @@ -1,5 +1,7 @@ package nostr.base; +import com.fasterxml.jackson.core.JsonProcessingException; + /** * * @author eric @@ -7,6 +9,6 @@ */ public interface IDecoder { - T decode(); - + T decode(String str) throws JsonProcessingException; + } diff --git a/nostr-java-connection/src/main/java/module-info.java b/nostr-java-connection/src/main/java/module-info.java index f43974ed2..974504604 100644 --- a/nostr-java-connection/src/main/java/module-info.java +++ b/nostr-java-connection/src/main/java/module-info.java @@ -13,6 +13,7 @@ requires nostr.controller; requires nostr.context; requires nostr.context.impl; + requires org.bouncycastle.provider; exports nostr.connection; exports nostr.connection.impl; diff --git a/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/TextListener.java b/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/TextListener.java index 6678b617a..7695e8a7e 100644 --- a/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/TextListener.java +++ b/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/TextListener.java @@ -20,6 +20,7 @@ import okhttp3.WebSocketListener; import okhttp3.WebSocket; import okio.ByteString; + import java.util.logging.Level; @AllArgsConstructor @@ -50,7 +51,7 @@ public void onMessage(WebSocket webSocket, ByteString bytes) { private void handleReceivedText(@NonNull String message) { log.log(Level.INFO, "Received message {0} from {1}", new Object[]{message, relay}); - var msg = new BaseMessageDecoder(message).decode(); + var msg = new BaseMessageDecoder<>().decode(message); final String strCommand = msg.getCommand(); log.log(Level.FINE, "Creating the command context with message {0}", new Object[]{msg}); diff --git a/nostr-java-event/src/main/java/nostr/event/impl/GenericMessage.java b/nostr-java-event/src/main/java/nostr/event/impl/GenericMessage.java index 6a31cd561..ee06ffeaf 100644 --- a/nostr-java-event/src/main/java/nostr/event/impl/GenericMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/impl/GenericMessage.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.core.JsonProcessingException; import lombok.Getter; +import lombok.NonNull; import lombok.Setter; import nostr.base.ElementAttribute; import nostr.base.IElement; @@ -53,4 +54,14 @@ public String encode() throws JsonProcessingException { getAttributes().stream().map(ElementAttribute::getValue).forEach(v -> getArrayNode().add(v.toString())); return IEncoder.MAPPER.writeValueAsString(getArrayNode()); } + + public static T decode(@NonNull Object[] msgArr) { + GenericMessage gm = new GenericMessage(msgArr[0].toString()); + for (int i = 1; i < msgArr.length; i++) { + if (msgArr[i] instanceof String) { + gm.addAttribute(ElementAttribute.builder().value(msgArr[i]).build()); + } + } + return (T) gm; + } } diff --git a/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java b/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java index 3432c8987..3d99cdc9f 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java +++ b/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java @@ -1,27 +1,20 @@ package nostr.event.json.codec; import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data; -import nostr.base.ElementAttribute; +import lombok.SneakyThrows; import nostr.base.IDecoder; import nostr.event.BaseMessage; -import nostr.event.impl.CanonicalAuthenticationEvent; -import nostr.event.impl.Filters; -import nostr.event.impl.GenericEvent; import nostr.event.impl.GenericMessage; import nostr.event.message.CanonicalAuthenticationMessage; import nostr.event.message.CloseMessage; -import nostr.event.message.EoseMessage; import nostr.event.message.EventMessage; import nostr.event.message.NoticeMessage; import nostr.event.message.OkMessage; import nostr.event.message.RelayAuthenticationMessage; import nostr.event.message.ReqMessage; -import java.util.List; import java.util.Map; /** @@ -29,92 +22,30 @@ */ @Data public class BaseMessageDecoder implements IDecoder { - private final Class clazz; - private final String jsonString; + private final ObjectMapper mapper; - public BaseMessageDecoder(String jsonString) { - this.clazz = (Class) BaseMessage.class; - this.jsonString = jsonString; + public BaseMessageDecoder() { + mapper = new ObjectMapper(); + mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); } + @SneakyThrows @Override - public T decode() { - try { - ObjectMapper mapper = new ObjectMapper(); - mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); - var msgArr = mapper.readValue(jsonString, Object[].class); - final String strCmd = msgArr[0].toString(); - final Object arg = msgArr[1]; - T message = null; - - if (arg == null) { - throw new AssertionError("arg == null"); - } - - switch (strCmd) { - case "AUTH" -> { - final T authMsg; - // Client Auth - if (arg instanceof Map map) { - var event = mapper.convertValue(map, new TypeReference() { - }); - authMsg = (T) new CanonicalAuthenticationMessage(event); - } else { - // Relay Auth - final var challenge = arg.toString(); - authMsg = (T) new RelayAuthenticationMessage(challenge); - } - message = authMsg; - } - case "CLOSE" -> message = (T) new CloseMessage(arg.toString()); - case "EOSE" -> message = (T) new EoseMessage(arg.toString()); - case "EVENT" -> { - if (msgArr.length == 2 && arg instanceof Map map) { - var event = mapper.convertValue(map, new TypeReference() { - }); - message = (T) new EventMessage(event); - } else if (msgArr.length == 3 && arg instanceof String) { - var subId = arg.toString(); - if (msgArr[2] instanceof Map map) { - var event = mapper.convertValue(map, new TypeReference() { - }); - message = (T) new EventMessage(event, subId); - } - } else { - throw new AssertionError("Invalid argument: " + arg); - } - } - case "NOTICE" -> message = (T) new NoticeMessage(arg.toString()); - case "OK" -> { - if (msgArr.length == 4 && msgArr[2] instanceof Boolean duplicate) { - String msgArg = msgArr[3].toString(); - message = (T) new OkMessage(arg.toString(), duplicate, msgArg); - } else { - throw new AssertionError("Invalid argument: " + msgArr[2]); - } - } - case "REQ" -> { - var len = msgArr.length - 2; - var filtersArr = new Object[len]; - System.arraycopy(msgArr, 2, filtersArr, 0, len); - var filtersList = mapper.convertValue(filtersArr, new TypeReference>() { - }); - message = (T) new ReqMessage(arg.toString(), filtersList); - } - default -> { - // NOTE: Only String attribute supported. It would be impossible to guess the object's type - GenericMessage gm = new GenericMessage(strCmd); - for (int i = 1; i < msgArr.length; i++) { - if (msgArr[i] instanceof String) { - gm.addAttribute(ElementAttribute.builder().value(msgArr[i]).build()); - } - } - } - } - return message; - } catch (JsonProcessingException ex) { - throw new RuntimeException(ex); - } + public T decode(String jsonString) { + Object[] msgArr = mapper.readValue(jsonString, Object[].class); + final String strCmd = msgArr[0].toString(); + final Object arg = msgArr[1]; + + return switch (strCmd) { + case "NOTICE" -> NoticeMessage.decode(arg); + case "OK" -> OkMessage.decode(msgArr); + case "REQ" -> ReqMessage.decode(msgArr, mapper); + case "EVENT" -> EventMessage.decode(msgArr, mapper); + case "CLOSE" -> CloseMessage.decode(arg); + case "AUTH" -> arg instanceof Map map ? + CanonicalAuthenticationMessage.decode(map, mapper) : + RelayAuthenticationMessage.decode(arg); + default -> GenericMessage.decode(msgArr); + }; } - } diff --git a/nostr-java-event/src/main/java/nostr/event/json/codec/BaseTagDecoder.java b/nostr-java-event/src/main/java/nostr/event/json/codec/BaseTagDecoder.java index 5a9fb082f..46e6fe3d6 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/codec/BaseTagDecoder.java +++ b/nostr-java-event/src/main/java/nostr/event/json/codec/BaseTagDecoder.java @@ -14,15 +14,13 @@ public class BaseTagDecoder implements IDecoder { private final Class clazz; - private final String jsonString; - public BaseTagDecoder(String jsonString) { + public BaseTagDecoder() { this.clazz = (Class) BaseTag.class; - this.jsonString = jsonString; } @Override - public T decode() { + public T decode(String jsonString) { try { ObjectMapper mapper = new ObjectMapper(); return mapper.readValue(jsonString, clazz); diff --git a/nostr-java-event/src/main/java/nostr/event/json/codec/GenericEventDecoder.java b/nostr-java-event/src/main/java/nostr/event/json/codec/GenericEventDecoder.java index 9b29f13dd..ea0ee6df0 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/codec/GenericEventDecoder.java +++ b/nostr-java-event/src/main/java/nostr/event/json/codec/GenericEventDecoder.java @@ -15,14 +15,12 @@ public class GenericEventDecoder implements IDecoder { private final Class clazz; - private final String jsonEvent; - public GenericEventDecoder(String jsonEvent) { + public GenericEventDecoder() { this.clazz = (Class) GenericEvent.class; - this.jsonEvent = jsonEvent; } @Override - public T decode() { + public T decode(String jsonEvent) { try { var mapper = new ObjectMapper(); mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); diff --git a/nostr-java-event/src/main/java/nostr/event/json/codec/GenericTagDecoder.java b/nostr-java-event/src/main/java/nostr/event/json/codec/GenericTagDecoder.java index 4b15cd6f6..e8658a779 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/codec/GenericTagDecoder.java +++ b/nostr-java-event/src/main/java/nostr/event/json/codec/GenericTagDecoder.java @@ -15,18 +15,16 @@ public class GenericTagDecoder implements IDecoder { private final Class clazz; - private final String json; - public GenericTagDecoder(String json) { + public GenericTagDecoder() { this.clazz = (Class) GenericTag.class; - this.json = json; } @Override - public T decode() { + public T decode(String json) { try { ObjectMapper objectMapper = new ObjectMapper(); - String[] jsonElements = objectMapper.readValue(this.json, String[].class); + String[] jsonElements = objectMapper.readValue(json, String[].class); String code = jsonElements[0]; diff --git a/nostr-java-event/src/main/java/nostr/event/json/codec/Nip05ContentDecoder.java b/nostr-java-event/src/main/java/nostr/event/json/codec/Nip05ContentDecoder.java index 543e3fbef..44cab726e 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/codec/Nip05ContentDecoder.java +++ b/nostr-java-event/src/main/java/nostr/event/json/codec/Nip05ContentDecoder.java @@ -14,17 +14,15 @@ public class Nip05ContentDecoder implements IDecoder { private final Class clazz; - private final String jsonContent; - public Nip05ContentDecoder(String jsonContent) { + public Nip05ContentDecoder() { this.clazz = (Class) Nip05Content.class; - this.jsonContent = jsonContent; } @Override - public T decode() { + public T decode(String jsonContent) { try { - return new ObjectMapper().readValue(this.jsonContent, clazz); + return new ObjectMapper().readValue(jsonContent, clazz); } catch (JsonProcessingException ex) { throw new RuntimeException(ex); } diff --git a/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomEventListDeserializer.java b/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomEventListDeserializer.java index 652fe2c67..ab163dacd 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomEventListDeserializer.java +++ b/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomEventListDeserializer.java @@ -21,8 +21,7 @@ public T deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws JsonNode node = jsonParser.readValueAsTree(); if (node.isArray()) { for (JsonNode n : node) { - GenericEventDecoder decoder = new GenericEventDecoder<>(n.toString()); - eventList.add(decoder.decode()); + eventList.add(new GenericEventDecoder().decode(n.toString())); } } return (T) eventList; diff --git a/nostr-java-event/src/main/java/nostr/event/json/deserializer/TagDeserializer.java b/nostr-java-event/src/main/java/nostr/event/json/deserializer/TagDeserializer.java index bd0a0396e..2e15a377d 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/deserializer/TagDeserializer.java +++ b/nostr-java-event/src/main/java/nostr/event/json/deserializer/TagDeserializer.java @@ -96,8 +96,7 @@ public T deserialize(JsonParser jsonParser, DeserializationContext deserializati return (T) tag; } default -> { - var tag = new GenericTagDecoder(node.toString()).decode(); - return (T) tag; + return (T) new GenericTagDecoder<>().decode(node.toString()); } } diff --git a/nostr-java-event/src/main/java/nostr/event/message/CanonicalAuthenticationMessage.java b/nostr-java-event/src/main/java/nostr/event/message/CanonicalAuthenticationMessage.java index eb24c0432..edd08191f 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/CanonicalAuthenticationMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/CanonicalAuthenticationMessage.java @@ -2,13 +2,19 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Getter; +import lombok.NonNull; import lombok.Setter; import nostr.base.Command; import nostr.base.IEncoder; +import nostr.event.BaseMessage; import nostr.event.impl.CanonicalAuthenticationEvent; import nostr.event.json.codec.BaseEventEncoder; +import java.util.Map; + /** * * @author eric @@ -32,4 +38,9 @@ public String encode() throws JsonProcessingException { .add(IEncoder.MAPPER.readTree( new BaseEventEncoder<>(getEvent()).encode()))); } + + public static T decode(@NonNull Map map, ObjectMapper mapper) { + var event = mapper.convertValue(map, new TypeReference() {}); + return (T) new CanonicalAuthenticationMessage(event); + } } \ No newline at end of file diff --git a/nostr-java-event/src/main/java/nostr/event/message/CloseMessage.java b/nostr-java-event/src/main/java/nostr/event/message/CloseMessage.java index 224430654..91d765bca 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/CloseMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/CloseMessage.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import lombok.Getter; +import lombok.NonNull; import lombok.Setter; import nostr.base.Command; import nostr.base.IEncoder; @@ -35,4 +36,8 @@ public String encode() throws JsonProcessingException { .add(getCommand()) .add(getSubscriptionId())); } + + public static T decode(@NonNull Object arg) { + return (T) new CloseMessage(arg.toString()); + } } diff --git a/nostr-java-event/src/main/java/nostr/event/message/EoseMessage.java b/nostr-java-event/src/main/java/nostr/event/message/EoseMessage.java index 2da444ba6..d00b57cf9 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/EoseMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/EoseMessage.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import lombok.Getter; +import lombok.NonNull; import lombok.Setter; import nostr.base.Command; import nostr.base.IEncoder; @@ -35,4 +36,8 @@ public String encode() throws JsonProcessingException { .add(getCommand()) .add(getSubscriptionId())); } + + public static T decode(@NonNull Object arg) { + return (T) new EoseMessage(arg.toString()); + } } diff --git a/nostr-java-event/src/main/java/nostr/event/message/EventMessage.java b/nostr-java-event/src/main/java/nostr/event/message/EventMessage.java index 61aa4610f..e0ba7f80a 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/EventMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/EventMessage.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Getter; import lombok.NonNull; import lombok.Setter; @@ -10,8 +12,11 @@ import nostr.base.IEvent; import nostr.event.BaseEvent; import nostr.event.BaseMessage; +import nostr.event.impl.GenericEvent; import nostr.event.json.codec.BaseEventEncoder; +import java.util.Map; + @Setter @Getter public class EventMessage extends BaseMessage { @@ -40,4 +45,19 @@ public String encode() throws JsonProcessingException { .add(IEncoder.MAPPER.readTree( new BaseEventEncoder<>((BaseEvent)getEvent()).encode()))); } + + public static T decode(@NonNull Object[] msgArr, ObjectMapper mapper) { + var arg = msgArr[1]; + if (msgArr.length == 2 && arg instanceof Map map) { + var event = mapper.convertValue(map, new TypeReference() {}); + return (T) new EventMessage(event); + } else if (msgArr.length == 3 && arg instanceof String) { + var subId = arg.toString(); + if (msgArr[2] instanceof Map map) { + var event = mapper.convertValue(map, new TypeReference() {}); + return (T) new EventMessage(event, subId); + } + } + throw new AssertionError("Invalid argument: " + arg); + } } diff --git a/nostr-java-event/src/main/java/nostr/event/message/NoticeMessage.java b/nostr-java-event/src/main/java/nostr/event/message/NoticeMessage.java index 261e5fbc7..745e33510 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/NoticeMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/NoticeMessage.java @@ -32,4 +32,8 @@ public String encode() throws JsonProcessingException { .add(getCommand()) .add(getMessage())); } + + public static T decode(@NonNull Object arg) { + return (T) new NoticeMessage(arg.toString()); + } } diff --git a/nostr-java-event/src/main/java/nostr/event/message/OkMessage.java b/nostr-java-event/src/main/java/nostr/event/message/OkMessage.java index 6fe9bf6d6..9245ba1e1 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/OkMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/OkMessage.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import lombok.Getter; +import lombok.NonNull; import lombok.Setter; import nostr.base.Command; import nostr.base.IEncoder; @@ -41,4 +42,13 @@ public String encode() throws JsonProcessingException { .add(getFlag()) .add(getMessage())); } + + public static T decode(@NonNull Object[] msgArr) { + if (msgArr.length == 4 && msgArr[2] instanceof Boolean duplicate) { + String msgArg = msgArr[3].toString(); + return (T) new OkMessage(msgArr[1].toString(), duplicate, msgArg); + } else { + throw new AssertionError("Invalid argument: " + msgArr[2]); + } + } } diff --git a/nostr-java-event/src/main/java/nostr/event/message/RelayAuthenticationMessage.java b/nostr-java-event/src/main/java/nostr/event/message/RelayAuthenticationMessage.java index 4a3e83539..bbd894428 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/RelayAuthenticationMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/RelayAuthenticationMessage.java @@ -3,9 +3,11 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import lombok.Getter; +import lombok.NonNull; import lombok.Setter; import nostr.base.Command; import nostr.base.IEncoder; +import nostr.event.BaseMessage; /** * @@ -30,4 +32,8 @@ public String encode() throws JsonProcessingException { .add(getCommand()) .add(getChallenge())); } + + public static T decode(@NonNull Object arg) { + return (T) new RelayAuthenticationMessage(arg.toString()); + } } diff --git a/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java b/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java index 79dabe367..b750e34f7 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java @@ -2,8 +2,11 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NonNull; import lombok.ToString; import nostr.base.Command; import nostr.base.IEncoder; @@ -57,4 +60,13 @@ public String encode() throws JsonProcessingException { } return IEncoder.MAPPER.writeValueAsString(getArrayNode()); } + + public static T decode(@NonNull Object[] msgArr, ObjectMapper mapper) { + var len = msgArr.length - 2; + var filtersArr = new Object[len]; + System.arraycopy(msgArr, 2, filtersArr, 0, len); + var filtersList = mapper.convertValue(filtersArr, new TypeReference>() { + }); + return (T) new ReqMessage(msgArr[1].toString(), filtersList); + } } diff --git a/nostr-java-event/src/main/java/nostr/event/util/Nip05Validator.java b/nostr-java-event/src/main/java/nostr/event/util/Nip05Validator.java index 476907652..e9589f477 100644 --- a/nostr-java-event/src/main/java/nostr/event/util/Nip05Validator.java +++ b/nostr-java-event/src/main/java/nostr/event/util/Nip05Validator.java @@ -5,8 +5,6 @@ import lombok.extern.java.Log; import nostr.base.PublicKey; import nostr.event.Nip05Content; -import nostr.event.impl.GenericTag; -import nostr.event.json.codec.GenericEventDecoder; import nostr.event.json.codec.Nip05ContentDecoder; import nostr.util.NostrException; @@ -89,7 +87,7 @@ private void validatePublicKey(String domain, String localPart) throws NostrExce private String getPublicKey(StringBuilder content, String localPart) { - Nip05Content nip05Content = new Nip05ContentDecoder(content.toString()).decode(); + Nip05Content nip05Content = new Nip05ContentDecoder<>().decode(content.toString()); // Access the decoded data Map names = nip05Content.getNames(); diff --git a/nostr-java-test/src/test/java/nostr/test/event/DecodeTest.java b/nostr-java-test/src/test/java/nostr/test/event/DecodeTest.java index b5c7f6184..e1272cd28 100644 --- a/nostr-java-test/src/test/java/nostr/test/event/DecodeTest.java +++ b/nostr-java-test/src/test/java/nostr/test/event/DecodeTest.java @@ -36,8 +36,7 @@ public void decodeTest() { + "\"sig\":\"86f25c161fec51b9e441bdb2c09095d5f8b92fdce66cb80d9ef09fad6ce53eaa14c5e16787c42f5404905536e43ebec0e463aee819378a4acbe412c533e60546\"" + "}]"; - BaseMessageDecoder decoder = new BaseMessageDecoder(json); - BaseMessage message = decoder.decode(); + BaseMessage message = new BaseMessageDecoder<>().decode(json); Assertions.assertEquals("EVENT", message.getCommand()); EventMessage eventMessage = (EventMessage) message; diff --git a/nostr-java-test/src/test/java/nostr/test/json/JsonParseTest.java b/nostr-java-test/src/test/java/nostr/test/json/JsonParseTest.java index b10875cb8..d3b176b66 100644 --- a/nostr-java-test/src/test/java/nostr/test/json/JsonParseTest.java +++ b/nostr-java-test/src/test/java/nostr/test/json/JsonParseTest.java @@ -42,8 +42,8 @@ public class JsonParseTest { @Test - public void testBaseReqMessageDecoder() { - System.out.println("testBaseReqMessageDecoder"); + public void testBaseMessageDecoder() { + System.out.println("testBaseMessageDecoder"); final String parseTarget = "[\"REQ\", " + @@ -52,7 +52,7 @@ public void testBaseReqMessageDecoder() { "\"authors\": [\"f1b419a95cb0233a11d431423b41a42734e7165fcab16081cd08ef1c90e0be75\"]," + "\"#e\": [\"fc7f200c5bed175702bd06c7ca5dba90d3497e827350b42fc99c3a4fa276a712\"]}]"; - final var message = new BaseMessageDecoder(parseTarget).decode(); + final var message = new BaseMessageDecoder<>().decode(parseTarget); assertEquals(Command.REQ.toString(), message.getCommand()); assertEquals("npub17x6pn22ukq3n5yw5x9prksdyyu6ww9jle2ckpqwdprh3ey8qhe6stnpujh", ((ReqMessage) message).getSubscriptionId()); @@ -71,8 +71,8 @@ public void testBaseReqMessageDecoder() { } @Test - public void testBaseReqMessageEncoder() throws JsonProcessingException { - System.out.println("testBaseReqMessageEncoder"); + public void testBaseReqMessageDecoder() throws JsonProcessingException { + System.out.println("testBaseReqMessageDecoder"); final var filtersList = new ArrayList(); var publicKey = Identity.generateRandomIdentity().getPublicKey(); @@ -92,7 +92,7 @@ public void testBaseReqMessageEncoder() throws JsonProcessingException { Assertions.assertFalse(parts[2].startsWith("[")); Assertions.assertFalse(parts[parts.length - 1].endsWith("]")); - var message = new BaseMessageDecoder(jsonMessage).decode(); + var message = new BaseMessageDecoder<>().decode(jsonMessage); assertEquals(reqMessage, message); } @@ -114,7 +114,7 @@ public void testBaseEventMessageDecoder() { + "\"tags\":[]" + "}]"; - final var message = new BaseMessageDecoder(parseTarget).decode(); + final var message = new BaseMessageDecoder<>().decode(parseTarget); assertEquals(Command.EVENT.toString(), message.getCommand()); @@ -145,8 +145,7 @@ public void testBaseEventMessageMarkerDecoder() { + "\"sig\":\"86f25c161fec51b9e441bdb2c09095d5f8b92fdce66cb80d9ef09fad6ce53eaa14c5e16787c42f5404905536e43ebec0e463aee819378a4acbe412c533e60546\"" + "}]"; - BaseMessageDecoder decoder = new BaseMessageDecoder(json); - BaseMessage message = decoder.decode(); + BaseMessage message = new BaseMessageDecoder<>().decode(json); final var event = (GenericEvent) (((EventMessage) message).getEvent()); var tags = event.getTags(); @@ -163,7 +162,7 @@ public void testGenericTagDecoder() { System.out.println("testGenericTagDecoder"); final String jsonString = "[\"saturn\", \"jetpack\", false]"; - var tag = new GenericTagDecoder(jsonString).decode(); + var tag = new GenericTagDecoder<>().decode(jsonString); assertEquals("saturn", tag.getCode()); assertEquals(2, tag.getAttributes().size()); @@ -190,7 +189,7 @@ public void testClassifiedListingTagSerializer() throws NostrException, JsonProc + "\"sig\":\"86f25c161fec51b9e441bdb2c09095d5f8b92fdce66cb80d9ef09fad6ce53eaa14c5e16787c42f5404905536e43ebec0e463aee819378a4acbe412c533e60546\"" + "}]"; - GenericEvent event = new GenericEventDecoder<>(classifiedListingEventJson).decode(); + GenericEvent event = new GenericEventDecoder<>().decode(classifiedListingEventJson); EventMessage message = NIP01.createEventMessage(event, "1"); assertEquals(1, message.getNip()); assertEquals("{\"id\":\"28f2fc030e335d061f0b9d03ce0e2c7d1253e6fadb15d89bd47379a96b2c861a\",\"kind\":30402,\"content\":\"content ipsum\",\"pubkey\":\"ec0762fe78b0f0b763d1324452d973a38bef576d1d76662722d2b8ff948af1de\",\"created_at\":1687765220,\"tags\":[[\"p\",\"ec0762fe78b0f0b763d1324452d973a38bef576d1d76662722d2b8ff948af1de\"],[\"title\",\"title ipsum\"],[\"summary\",\"summary ipsum\"],[\"published_at\",\"1687765220\"],[\"location\",\"location ipsum\"],[\"price\",\"11111\",\"BTC\",\"1\"]],\"sig\":\"86f25c161fec51b9e441bdb2c09095d5f8b92fdce66cb80d9ef09fad6ce53eaa14c5e16787c42f5404905536e43ebec0e463aee819378a4acbe412c533e60546\"}", new BaseEventEncoder<>((BaseEvent) message.getEvent()).encode()); @@ -231,7 +230,7 @@ public void testDeserializeTag() throws NostrException { String npubHex = new PublicKey(Bech32.decode("npub1clk6vc9xhjp8q5cws262wuf2eh4zuvwupft03hy4ttqqnm7e0jrq3upup9").data).toString(); final String jsonString = "[\"p\", \"" + npubHex + "\", \"wss://nostr.java\", \"alice\"]"; - var tag = new BaseTagDecoder(jsonString).decode(); + var tag = new BaseTagDecoder<>().decode(jsonString); Assertions.assertTrue(tag instanceof PubKeyTag); @@ -247,7 +246,7 @@ public void testDeserializeGenericTag() throws NostrException { String npubHex = new PublicKey(Bech32.decode("npub1clk6vc9xhjp8q5cws262wuf2eh4zuvwupft03hy4ttqqnm7e0jrq3upup9").data).toString(); final String jsonString = "[\"gt\", \"" + npubHex + "\", \"wss://nostr.java\", \"alice\"]"; - var tag = new BaseTagDecoder(jsonString).decode(); + var tag = new BaseTagDecoder<>().decode(jsonString); Assertions.assertTrue(tag instanceof GenericTag); From e52d61448cad38ae5c97c157d9e9b6ddd0ac6377 Mon Sep 17 00:00:00 2001 From: nick avlo Date: Sun, 2 Jun 2024 01:56:04 -0700 Subject: [PATCH 10/12] cleanup --- nostr-java-base/src/main/java/nostr/base/IDecoder.java | 4 +--- .../main/java/nostr/event/json/codec/BaseMessageDecoder.java | 5 ++--- .../java/nostr/event/json/codec/GenericEventDecoder.java | 1 + 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/nostr-java-base/src/main/java/nostr/base/IDecoder.java b/nostr-java-base/src/main/java/nostr/base/IDecoder.java index f94d95120..c1dd430be 100644 --- a/nostr-java-base/src/main/java/nostr/base/IDecoder.java +++ b/nostr-java-base/src/main/java/nostr/base/IDecoder.java @@ -1,7 +1,5 @@ package nostr.base; -import com.fasterxml.jackson.core.JsonProcessingException; - /** * * @author eric @@ -9,6 +7,6 @@ */ public interface IDecoder { - T decode(String str) throws JsonProcessingException; + T decode(String str); } diff --git a/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java b/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java index 3d99cdc9f..921c6b6da 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java +++ b/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.Data; +import lombok.NonNull; import lombok.SneakyThrows; import nostr.base.IDecoder; import nostr.event.BaseMessage; @@ -20,7 +20,6 @@ /** * @author eric */ -@Data public class BaseMessageDecoder implements IDecoder { private final ObjectMapper mapper; @@ -31,7 +30,7 @@ public BaseMessageDecoder() { @SneakyThrows @Override - public T decode(String jsonString) { + public T decode(@NonNull String jsonString) { Object[] msgArr = mapper.readValue(jsonString, Object[].class); final String strCmd = msgArr[0].toString(); final Object arg = msgArr[1]; diff --git a/nostr-java-event/src/main/java/nostr/event/json/codec/GenericEventDecoder.java b/nostr-java-event/src/main/java/nostr/event/json/codec/GenericEventDecoder.java index ea0ee6df0..d65c76f4b 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/codec/GenericEventDecoder.java +++ b/nostr-java-event/src/main/java/nostr/event/json/codec/GenericEventDecoder.java @@ -19,6 +19,7 @@ public class GenericEventDecoder implements IDecoder public GenericEventDecoder() { this.clazz = (Class) GenericEvent.class; } + @Override public T decode(String jsonEvent) { try { From e4c2f0535a0ea03f201edd58576339ec2f4f22f7 Mon Sep 17 00:00:00 2001 From: nick avlo Date: Sun, 2 Jun 2024 09:27:36 -0700 Subject: [PATCH 11/12] added EOSE --- .../nostr/event/json/codec/BaseMessageDecoder.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java b/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java index 921c6b6da..40dadbbb7 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java +++ b/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java @@ -9,6 +9,7 @@ import nostr.event.impl.GenericMessage; import nostr.event.message.CanonicalAuthenticationMessage; import nostr.event.message.CloseMessage; +import nostr.event.message.EoseMessage; import nostr.event.message.EventMessage; import nostr.event.message.NoticeMessage; import nostr.event.message.OkMessage; @@ -36,14 +37,15 @@ public T decode(@NonNull String jsonString) { final Object arg = msgArr[1]; return switch (strCmd) { - case "NOTICE" -> NoticeMessage.decode(arg); - case "OK" -> OkMessage.decode(msgArr); - case "REQ" -> ReqMessage.decode(msgArr, mapper); - case "EVENT" -> EventMessage.decode(msgArr, mapper); - case "CLOSE" -> CloseMessage.decode(arg); case "AUTH" -> arg instanceof Map map ? CanonicalAuthenticationMessage.decode(map, mapper) : RelayAuthenticationMessage.decode(arg); + case "CLOSE" -> CloseMessage.decode(arg); + case "EOSE" -> EoseMessage.decode(arg); + case "EVENT" -> EventMessage.decode(msgArr, mapper); + case "NOTICE" -> NoticeMessage.decode(arg); + case "OK" -> OkMessage.decode(msgArr); + case "REQ" -> ReqMessage.decode(msgArr, mapper); default -> GenericMessage.decode(msgArr); }; } From b88c99f56f3df2d886325f91182526a6639dda00 Mon Sep 17 00:00:00 2001 From: nick avlo Date: Sun, 2 Jun 2024 09:48:02 -0700 Subject: [PATCH 12/12] removed windows hidden crlf from file --- .../src/main/java/nostr/client/Client.java | 232 +++++++++--------- 1 file changed, 116 insertions(+), 116 deletions(-) diff --git a/nostr-java-client/src/main/java/nostr/client/Client.java b/nostr-java-client/src/main/java/nostr/client/Client.java index c70486213..1dd19f451 100644 --- a/nostr-java-client/src/main/java/nostr/client/Client.java +++ b/nostr-java-client/src/main/java/nostr/client/Client.java @@ -1,117 +1,117 @@ -package nostr.client; - -import lombok.AllArgsConstructor; -import lombok.NoArgsConstructor; -import lombok.NonNull; -import lombok.SneakyThrows; -import lombok.extern.java.Log; -import nostr.base.Relay; -import nostr.connection.impl.ConnectionPool; -import nostr.context.Context; -import nostr.context.RequestContext; -import nostr.context.impl.DefaultRequestContext; -import nostr.event.BaseMessage; -import nostr.event.impl.GenericTag; -import nostr.event.message.CanonicalAuthenticationMessage; -import nostr.util.thread.Task; -import nostr.util.thread.ThreadUtil; - -import java.util.concurrent.TimeoutException; -import java.util.logging.Level; - -@Log -@NoArgsConstructor -public class Client { - - private static class Holder { - private static final Client INSTANCE = new Client(); - } - - private RequestContext context; - - private ConnectionPool connectionPool; - - public static Client getInstance() { - return Holder.INSTANCE; - } - - public Client connect(@NonNull RequestContext context) throws TimeoutException { - if (context instanceof DefaultRequestContext defaultRequestContext) { - Holder.INSTANCE.context = context; - connectionPool = ConnectionPool.getInstance(defaultRequestContext); - ThreadUtil.builder().blocking(true).lock(true).task(new RelayConnectionTask(this.connectionPool)).build().run(context); - } - return this; - } - - public void disconnect() throws TimeoutException { - ThreadUtil.builder().blocking(true).task(new RelayDisconnectionTask(this.connectionPool)).build().run(this.context); - } - - public int getOpenConnectionsCount() { - return connectionPool.connectionCount(); - } - - public void send(@NonNull BaseMessage message) throws TimeoutException { - log.log(Level.FINE, "Requesting to send the message {0}...", message); - ThreadUtil.builder().blocking(false).lock(true).task(new SendMessageTask(message, this.connectionPool)).build().run(this.context); - } - - boolean isConnected(@NonNull Relay relay) { - return this.connectionPool.isConnectedTo(relay); - } - - @AllArgsConstructor - private static class RelayConnectionTask implements Task { - - private final ConnectionPool connectionManager; - - @Override - public Void execute(@NonNull Context context) { - connectionManager.connect(); - return null; - } - } - - @AllArgsConstructor - private static class RelayDisconnectionTask implements Task { - - private final ConnectionPool connectionPool; - - @Override - public Void execute(@NonNull Context context) { - connectionPool.disconnect(); - return null; - } - } - - @AllArgsConstructor - private static class SendMessageTask implements Task { - - private final BaseMessage message; - private final ConnectionPool connectionPool; - - @SneakyThrows - @Override - public Void execute(@NonNull Context context) { - // Only send AUTH messages to the relay mentioned in the tag https://github.com/tcheeric/nostr-java/issues/129 - if (message instanceof CanonicalAuthenticationMessage canonicalAuthenticationMessage) { - log.log(Level.FINE, ">>> Authentication message {0}...", canonicalAuthenticationMessage); - var event = canonicalAuthenticationMessage.getEvent(); - var relayTag = event.getTags().stream().filter(t -> t.getCode().equalsIgnoreCase("relay")).findFirst(); - if (relayTag.isPresent()) { - var relayTagValue = ((GenericTag) relayTag.get()).getAttributes().get(0).getValue().toString(); - log.log(Level.FINEST, "**** Relay found in CanonicalAuthenticationMessage: {0}", relayTagValue); - var r = new Relay(relayTagValue); - connectionPool.send(canonicalAuthenticationMessage.encode(), r); - } else { - log.log(Level.SEVERE, "Relay tag not found in CanonicalAuthenticationMessage. Ignoring..."); - } - } else { - log.log(Level.FINER, "+++ message {0}...", message); - connectionPool.send(message.encode()); - } - return null; - } - } +package nostr.client; + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.SneakyThrows; +import lombok.extern.java.Log; +import nostr.base.Relay; +import nostr.connection.impl.ConnectionPool; +import nostr.context.Context; +import nostr.context.RequestContext; +import nostr.context.impl.DefaultRequestContext; +import nostr.event.BaseMessage; +import nostr.event.impl.GenericTag; +import nostr.event.message.CanonicalAuthenticationMessage; +import nostr.util.thread.Task; +import nostr.util.thread.ThreadUtil; + +import java.util.concurrent.TimeoutException; +import java.util.logging.Level; + +@Log +@NoArgsConstructor +public class Client { + + private static class Holder { + private static final Client INSTANCE = new Client(); + } + + private RequestContext context; + + private ConnectionPool connectionPool; + + public static Client getInstance() { + return Holder.INSTANCE; + } + + public Client connect(@NonNull RequestContext context) throws TimeoutException { + if (context instanceof DefaultRequestContext defaultRequestContext) { + Holder.INSTANCE.context = context; + connectionPool = ConnectionPool.getInstance(defaultRequestContext); + ThreadUtil.builder().blocking(true).lock(true).task(new RelayConnectionTask(this.connectionPool)).build().run(context); + } + return this; + } + + public void disconnect() throws TimeoutException { + ThreadUtil.builder().blocking(true).task(new RelayDisconnectionTask(this.connectionPool)).build().run(this.context); + } + + public int getOpenConnectionsCount() { + return connectionPool.connectionCount(); + } + + public void send(@NonNull BaseMessage message) throws TimeoutException { + log.log(Level.FINE, "Requesting to send the message {0}...", message); + ThreadUtil.builder().blocking(false).lock(true).task(new SendMessageTask(message, this.connectionPool)).build().run(this.context); + } + + boolean isConnected(@NonNull Relay relay) { + return this.connectionPool.isConnectedTo(relay); + } + + @AllArgsConstructor + private static class RelayConnectionTask implements Task { + + private final ConnectionPool connectionManager; + + @Override + public Void execute(@NonNull Context context) { + connectionManager.connect(); + return null; + } + } + + @AllArgsConstructor + private static class RelayDisconnectionTask implements Task { + + private final ConnectionPool connectionPool; + + @Override + public Void execute(@NonNull Context context) { + connectionPool.disconnect(); + return null; + } + } + + @AllArgsConstructor + private static class SendMessageTask implements Task { + + private final BaseMessage message; + private final ConnectionPool connectionPool; + + @SneakyThrows + @Override + public Void execute(@NonNull Context context) { + // Only send AUTH messages to the relay mentioned in the tag https://github.com/tcheeric/nostr-java/issues/129 + if (message instanceof CanonicalAuthenticationMessage canonicalAuthenticationMessage) { + log.log(Level.FINE, ">>> Authentication message {0}...", canonicalAuthenticationMessage); + var event = canonicalAuthenticationMessage.getEvent(); + var relayTag = event.getTags().stream().filter(t -> t.getCode().equalsIgnoreCase("relay")).findFirst(); + if (relayTag.isPresent()) { + var relayTagValue = ((GenericTag) relayTag.get()).getAttributes().get(0).getValue().toString(); + log.log(Level.FINEST, "**** Relay found in CanonicalAuthenticationMessage: {0}", relayTagValue); + var r = new Relay(relayTagValue); + connectionPool.send(canonicalAuthenticationMessage.encode(), r); + } else { + log.log(Level.SEVERE, "Relay tag not found in CanonicalAuthenticationMessage. Ignoring..."); + } + } else { + log.log(Level.FINER, "+++ message {0}...", message); + connectionPool.send(message.encode()); + } + return null; + } + } } \ No newline at end of file