Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ To use the library in your project, add the following dependency to your pom.xml
</dependency>
```

I recommend having a look at the [nostr-example](https://github.com/tcheeric/nostr-java/tree/main/nostr-java-examples) module and the [nostr-client](https://github.com/tcheeric/nostr-client/) project for a simple example on how to use the library.
I recommend having a look at:
- [nostr-example](https://github.com/tcheeric/nostr-java/tree/main/nostr-java-examples) module
- [nostr-client](https://github.com/tcheeric/nostr-client/) project
- [SuperConductor](https://github.com/avlo/superconductor) nostr relay

for simple examples on how to use the library.

## Supported NIPs
The following NIPs are supported by the API out-of-the-box:
Expand Down
16 changes: 7 additions & 9 deletions nostr-java-event/src/main/java/nostr/event/impl/GenericTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,16 @@ public void addAttribute(ElementAttribute attribute) {
}

public static GenericTag create(String code, Integer nip, String... params) {
return create(code, nip, List.of(params));
}

public static GenericTag create(String code, Integer nip, List<String> params) {
List<ElementAttribute> attributes = new ArrayList<>();
for (int i = 0; i < params.length; i++) {
for (int i = 0; i < params.size(); i++) {
String name = "param" + i;
var p = params[i];
var p = params.get(i);
attributes.add(i, ElementAttribute.builder().name(name).value(p).build());
}
return new GenericTag(code, nip, attributes);
}

public static GenericTag create(String code, Integer nip, String param) {
List<ElementAttribute> attributes = new ArrayList<>();
attributes.add(0, ElementAttribute.builder().name("param0").value(param).build());
return new GenericTag(code, nip, attributes);
}
}
}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice.

Original file line number Diff line number Diff line change
Expand Up @@ -4,102 +4,44 @@
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;

import java.io.IOException;
import nostr.base.PublicKey;
import nostr.event.BaseTag;
import nostr.event.Marker;
import nostr.event.json.codec.GenericTagDecoder;
import nostr.event.tag.EventTag;
import nostr.event.tag.GeohashTag;
import nostr.event.tag.HashtagTag;
import nostr.event.tag.NonceTag;
import nostr.event.tag.PriceTag;
import nostr.event.tag.PubKeyTag;
import nostr.event.tag.RelaysTag;
import nostr.event.tag.SubjectTag;

import java.io.IOException;

public class TagDeserializer<T extends BaseTag> extends JsonDeserializer<T> {

@Override
public T deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);

JsonNode node = jsonParser.getCodec().readTree(jsonParser);
// Extract relevant data from the JSON node
String code = node.get(0).asText();

if (null == code) {
throw new IOException("Unknown tag code: " + null);
} else // Perform custom deserialization logic based on the concrete class
{
switch (code) {
case "p" -> {
// Deserialization logic for ConcreteTag1
PubKeyTag tag = new PubKeyTag();

final JsonNode nodePubKey = node.get(1);
if (nodePubKey != null) {
tag.setPublicKey(new PublicKey(nodePubKey.asText()));
}

final JsonNode nodeMainUrl = node.get(2);
if (nodeMainUrl != null) {
tag.setMainRelayUrl(nodeMainUrl.asText());
}

final JsonNode nodePetName = node.get(3);
if (nodePetName != null) {
tag.setPetName(nodePetName.asText());
}

return (T) tag;
}

case "nonce" -> {
// Deserialization logic for ConcreteTag2
NonceTag tag = new NonceTag();

final JsonNode nodeNonce = node.get(1);
if (nodeNonce != null) {
tag.setNonce(Integer.valueOf(nodeNonce.asText()));
}

final JsonNode nodeDifficulty = node.get(2);
if (nodeDifficulty != null) {
tag.setDifficulty(Integer.valueOf(nodeDifficulty.asText()));
}
return (T) tag;
}
case "e" -> {
// Deserialization logic for ConcreteTag2
EventTag tag = new EventTag();

final JsonNode nodeIdEvent = node.get(1);
if (nodeIdEvent != null) {
tag.setIdEvent(nodeIdEvent.asText());
}

final JsonNode nodeRelay = node.get(2);
if (nodeRelay != null) {
tag.setRecommendedRelayUrl(nodeRelay.asText());
}

final JsonNode nodeMarker = node.get(3);
if (nodeMarker != null) {
tag.setMarker(Marker.valueOf(nodeMarker.asText().toUpperCase()));
}
return (T) tag;
}
case "subject" -> {
SubjectTag tag = new SubjectTag();

final JsonNode nodeSubject = node.get(1);
if (nodeSubject != null) {
tag.setSubject(nodeSubject.asText());
}
return (T) tag;
}
default -> {
return (T) new GenericTagDecoder<>().decode(node.toString());
}

}
return switch (code) {
case "e" -> EventTag.deserialize(node);
case "g" -> GeohashTag.deserialize(node);
case "p" -> PubKeyTag.deserialize(node);
case "t" -> HashtagTag.deserialize(node);

case "nonce" -> NonceTag.deserialize(node);
case "price" -> PriceTag.deserialize(node);
case "relays" -> RelaysTag.deserialize(node);
case "subject" -> SubjectTag.deserialize(node);
default -> (T) new GenericTagDecoder<>().decode(node.toString());
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class RelaysTagSerializer extends JsonSerializer<RelaysTag> {
@Override
public void serialize(@NonNull RelaysTag relaysTag, @NonNull JsonGenerator jsonGenerator, @NonNull SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartArray();
jsonGenerator.writeFieldName("relays");
jsonGenerator.writeString("relays");
relaysTag.getRelays().forEach(json -> writeString(jsonGenerator, json.getUri()));
jsonGenerator.writeEndArray();
}
Expand Down
128 changes: 75 additions & 53 deletions nostr-java-event/src/main/java/nostr/event/tag/EventTag.java
Original file line number Diff line number Diff line change
@@ -1,53 +1,75 @@
/*
* 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.tag;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import nostr.base.annotation.Key;
import nostr.base.annotation.Tag;
import nostr.event.BaseTag;
import nostr.event.Marker;

/**
*
* @author squirrel
*/
@Builder
@Data
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@Tag(code = "e", name = "event")
@JsonPropertyOrder({"idEvent", "recommendedRelayUrl", "marker"})
@NoArgsConstructor
public class EventTag extends BaseTag {

@Key
@JsonProperty("idEvent")
private String idEvent;

@Key
@JsonProperty("recommendedRelayUrl")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String recommendedRelayUrl;

@Key(nip = 10)
@JsonProperty("marker")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Marker marker;

public EventTag(String idEvent) {
this.recommendedRelayUrl = null;
this.idEvent = idEvent;
this.marker = this.idEvent == null ? Marker.ROOT : Marker.REPLY;
}
}
/*
* 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.tag;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import nostr.base.annotation.Key;
import nostr.base.annotation.Tag;
import nostr.event.BaseTag;
import nostr.event.Marker;

/**
*
* @author squirrel
*/
@Builder
@Data
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@Tag(code = "e", name = "event")
@JsonPropertyOrder({"idEvent", "recommendedRelayUrl", "marker"})
@NoArgsConstructor
public class EventTag extends BaseTag {

@Key
@JsonProperty("idEvent")
private String idEvent;

@Key
@JsonProperty("recommendedRelayUrl")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String recommendedRelayUrl;

@Key(nip = 10)
@JsonProperty("marker")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Marker marker;

public EventTag(String idEvent) {
this.recommendedRelayUrl = null;
this.idEvent = idEvent;
this.marker = this.idEvent == null ? Marker.ROOT : Marker.REPLY;
}

public static <T extends BaseTag> T deserialize(@NonNull JsonNode node) {
EventTag tag = new EventTag();

final JsonNode nodeIdEvent = node.get(1);
if (nodeIdEvent != null) {
tag.setIdEvent(nodeIdEvent.asText());
}

final JsonNode nodeRelay = node.get(2);
if (nodeRelay != null) {
tag.setRecommendedRelayUrl(nodeRelay.asText());
}

final JsonNode nodeMarker = node.get(3);
if (nodeMarker != null) {
tag.setMarker(Marker.valueOf(nodeMarker.asText().toUpperCase()));
}
return (T) tag;
}
}
13 changes: 13 additions & 0 deletions nostr-java-event/src/main/java/nostr/event/tag/GeohashTag.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package nostr.event.tag;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import nostr.base.annotation.Key;
import nostr.base.annotation.Tag;
import nostr.event.BaseTag;
Expand All @@ -25,4 +27,15 @@ public class GeohashTag extends BaseTag {
@Key
@JsonProperty("g")
private String location;

public static <T extends BaseTag> T deserialize(@NonNull JsonNode node) {
GeohashTag tag = new GeohashTag();

final JsonNode nodePubKey = node.get(1);
if (nodePubKey != null) {
tag.setLocation(nodePubKey.asText());
}

return (T) tag;
}
}
12 changes: 12 additions & 0 deletions nostr-java-event/src/main/java/nostr/event/tag/HashtagTag.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package nostr.event.tag;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import nostr.base.annotation.Key;
import nostr.base.annotation.Tag;
import nostr.event.BaseTag;
Expand All @@ -26,4 +28,14 @@ public class HashtagTag extends BaseTag {
@JsonProperty("t")
private String hashTag;

public static <T extends BaseTag> T deserialize(@NonNull JsonNode node) {
HashtagTag tag = new HashtagTag();

final JsonNode nodePubKey = node.get(1);
if (nodePubKey != null) {
tag.setHashTag(nodePubKey.asText());
}

return (T) tag;
}
}
16 changes: 16 additions & 0 deletions nostr-java-event/src/main/java/nostr/event/tag/NonceTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.JsonNode;
import nostr.base.annotation.Key;
import nostr.event.BaseTag;
import lombok.Builder;
Expand Down Expand Up @@ -36,4 +37,19 @@ public NonceTag(@NonNull Integer nonce, @NonNull Integer difficulty) {
this.nonce = nonce;
this.difficulty = difficulty;
}

public static <T extends BaseTag> T deserialize(@NonNull JsonNode node) {
NonceTag tag = new NonceTag();

final JsonNode nodeNonce = node.get(1);
if (nodeNonce != null) {
tag.setNonce(Integer.valueOf(nodeNonce.asText()));
}

final JsonNode nodeDifficulty = node.get(2);
if (nodeDifficulty != null) {
tag.setDifficulty(Integer.valueOf(nodeDifficulty.asText()));
}
return (T) tag;
}
}
Loading