diff --git a/nostr-java-base/src/main/java/nostr/base/Relay.java b/nostr-java-base/src/main/java/nostr/base/Relay.java index eb56edb40..87ec25e3b 100644 --- a/nostr-java-base/src/main/java/nostr/base/Relay.java +++ b/nostr-java-base/src/main/java/nostr/base/Relay.java @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.List; +import java.lang.RuntimeException; /** * @author squirrel @@ -26,7 +27,11 @@ public class Relay { @EqualsAndHashCode.Include @ToString.Include - private String uri; + private String scheme; + + @EqualsAndHashCode.Include + @ToString.Include + private String host; @ToString.Exclude @EqualsAndHashCode.Exclude @@ -36,6 +41,16 @@ public Relay(@NonNull String uri) { this(uri, new RelayInformationDocument()); } + public Relay(@NonNull String uri, RelayInformationDocument doc) { + this.informationDocument = doc; + String[] s = uri.split("://", 2); + if (s.length != 2) { + throw new RuntimeException("uri must contain scheme and host, passed in uri: \"" + uri + "\""); + } + this.scheme = s[0]; + this.host = s[1]; + } + // Helper method public List getSupportedNips() { return this.getInformationDocument().getSupportedNips(); @@ -70,6 +85,16 @@ public String getName() { return this.getInformationDocument().getName(); } + // Helper method + public String getUri() { + return this.scheme + "://" + this.host; + } + + // Helper method + public String getHttpUri() { + return this.scheme.replaceFirst("ws", "http") + "://" + this.host; + } + @Data @Builder diff --git a/nostr-java-connection/pom.xml b/nostr-java-connection/pom.xml index 63baff204..bc1344deb 100644 --- a/nostr-java-connection/pom.xml +++ b/nostr-java-connection/pom.xml @@ -30,5 +30,16 @@ ${project.version} compile + + com.squareup.okio + okio + ${okio.version} + + + com.squareup.okhttp3 + okhttp + ${okhttp.version} + + diff --git a/nostr-java-connection/src/main/java/module-info.java b/nostr-java-connection/src/main/java/module-info.java index 570da7bf9..f43974ed2 100644 --- a/nostr-java-connection/src/main/java/module-info.java +++ b/nostr-java-connection/src/main/java/module-info.java @@ -3,7 +3,8 @@ requires static lombok; - requires java.net.http; + requires okio; + requires okhttp3; requires java.logging; diff --git a/nostr-java-connection/src/main/java/nostr/connection/impl/ConnectionImpl.java b/nostr-java-connection/src/main/java/nostr/connection/impl/ConnectionImpl.java index 8c8d2e1b4..802daea21 100644 --- a/nostr-java-connection/src/main/java/nostr/connection/impl/ConnectionImpl.java +++ b/nostr-java-connection/src/main/java/nostr/connection/impl/ConnectionImpl.java @@ -15,8 +15,10 @@ import nostr.context.Context; import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.WebSocket; +import okhttp3.OkHttpClient; +import okhttp3.WebSocket; +import okhttp3.Request; +import okhttp3.HttpUrl; import java.time.Duration; import java.util.Arrays; import java.util.UUID; @@ -57,14 +59,12 @@ public void connect() { return; } - log.log(Level.INFO, "Connecting to {0}...", relay); - var client = HttpClient.newHttpClient(); + log.log(Level.INFO, "Connecting to {0}... httpUrl = {1}", new Object[]{relay, HttpUrl.parse(relay.getHttpUri())}); + var client = new OkHttpClient(); var compositeListener = new CompositeListener(Arrays.asList(new OpenListener(relay), new TextListener(relay, context), new CloseListener(relay), new ErrorListener(relay))); - - webSocket = client.newWebSocketBuilder() - .connectTimeout(Duration.ofMillis(10000)) // TODO - make this configurable and add to the context. - .buildAsync(URI.create(relay.getUri()), compositeListener) - .join(); + + webSocket = client.newWebSocket((new Request.Builder()).url(HttpUrl.parse(relay.getHttpUri())).build(), compositeListener); + //.connectTimeout(Duration.ofMillis(10000)) // TODO - make this configurable and add to the context. connected.set(true); @@ -80,6 +80,7 @@ public boolean isConnected() { return connected.get() && webSocket != null; } + @Override public void send(@NonNull String message) { if (!isConnected()) { log.log(Level.WARNING, "FAIL - Not properly connected with Relay: {0}", relay); @@ -87,14 +88,15 @@ public void send(@NonNull String message) { } log.log(Level.INFO, "Sending message: {0} - Relay: {1}", new Object[]{message, relay}); - webSocket.sendText(message, true); + webSocket.send(message); } @Override public void disconnect() { if (isConnected()) { log.log(Level.INFO, "Disconnecting from {0}", relay); - webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "bye").join(); + // NORMAL_CLOSURE is 1000 + webSocket.close(1000, "bye"); // TODO check return result of close } connected.set(false); } diff --git a/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/CloseListener.java b/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/CloseListener.java index 78f6c973a..2bfb06c96 100644 --- a/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/CloseListener.java +++ b/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/CloseListener.java @@ -8,7 +8,8 @@ import nostr.base.Relay; import nostr.event.Response; -import java.net.http.WebSocket; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -18,7 +19,7 @@ @AllArgsConstructor @Log -public class CloseListener implements WebSocket.Listener { +public class CloseListener extends WebSocketListener { @Getter @EqualsAndHashCode.Include @@ -28,9 +29,14 @@ public class CloseListener implements WebSocket.Listener { private final Set responses = Collections.synchronizedSet(new HashSet<>()); @Override - public CompletionStage onClose(WebSocket webSocket, int statusCode, String reason) { + public void onClosed(WebSocket webSocket, int statusCode, String reason) { log.log(Level.INFO, "WebSocket connection to {0} closed: {1}, {2}", new Object[]{relay, statusCode, reason}); responses.clear(); - return CompletableFuture.completedFuture(null); + } + + @Override + public void onClosing(WebSocket webSocket, int statusCode, String reason) { + log.log(Level.INFO, "WebSocket connection to {0} closing: {1}, {2}", new Object[]{relay, statusCode, reason}); + responses.clear(); } } diff --git a/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/CompositeListener.java b/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/CompositeListener.java index 7351e7516..7b4f4413e 100644 --- a/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/CompositeListener.java +++ b/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/CompositeListener.java @@ -1,65 +1,48 @@ package nostr.connection.impl.listeners; -import java.net.http.WebSocket; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; +import okhttp3.Response; +import okio.ByteString; import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; -public class CompositeListener implements WebSocket.Listener { - private final List listeners; +public class CompositeListener extends WebSocketListener { + private final List listeners; - public CompositeListener(List listeners) { + public CompositeListener(List listeners) { this.listeners = listeners; } @Override - public void onOpen(WebSocket webSocket) { - listeners.forEach(listener -> listener.onOpen(webSocket)); + public void onOpen(WebSocket webSocket, Response response) { + listeners.forEach(listener -> listener.onOpen(webSocket, response)); } @Override - public CompletionStage onText(WebSocket webSocket, CharSequence data, boolean last) { - return CompletableFuture.allOf(listeners.stream() - .map(listener -> { - CompletionStage stage = listener.onText(webSocket, data, last); - return stage != null ? stage : CompletableFuture.completedFuture(null); - }) - .toArray(CompletableFuture[]::new)); + public void onMessage(WebSocket webSocket, String data) { + listeners.forEach(listener -> listener.onMessage(webSocket, data)); } @Override - public CompletionStage onPing(WebSocket webSocket, ByteBuffer message) { - return CompletableFuture.allOf(listeners.stream() - .map(listener -> { - CompletionStage stage = listener.onPing(webSocket, message); - return stage != null ? stage : CompletableFuture.completedFuture(null); - }) - .toArray(CompletableFuture[]::new)); + public void onMessage(WebSocket webSocket, ByteString bytes) { + listeners.forEach(listener -> listener.onMessage(webSocket, bytes)); } @Override - public CompletionStage onPong(WebSocket webSocket, ByteBuffer message) { - return CompletableFuture.allOf(listeners.stream() - .map(listener -> { - CompletionStage stage = listener.onPong(webSocket, message); - return stage != null ? stage : CompletableFuture.completedFuture(null); - }) - .toArray(CompletableFuture[]::new)); + public void onClosing(WebSocket webSocket, int statusCode, String reason) { + listeners.forEach(listener -> listener.onClosing(webSocket, statusCode, reason)); } @Override - public CompletionStage onClose(WebSocket webSocket, int statusCode, String reason) { - return CompletableFuture.allOf(listeners.stream() - .map(listener -> { - CompletionStage stage = listener.onClose(webSocket, statusCode, reason); - return stage != null ? stage : CompletableFuture.completedFuture(null); - }) - .toArray(CompletableFuture[]::new)); + public void onClosed(WebSocket webSocket, int statusCode, String reason) { + listeners.forEach(listener -> listener.onClosed(webSocket, statusCode, reason)); } @Override - public void onError(WebSocket webSocket, Throwable error) { - listeners.forEach(listener -> listener.onError(webSocket, error)); + public void onFailure(WebSocket webSocket, Throwable error, Response response) { + listeners.forEach(listener -> listener.onFailure(webSocket, error, response)); } } diff --git a/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/ErrorListener.java b/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/ErrorListener.java index 79b5410f0..607159813 100644 --- a/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/ErrorListener.java +++ b/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/ErrorListener.java @@ -7,20 +7,22 @@ import lombok.extern.java.Log; import nostr.base.Relay; -import java.net.http.WebSocket; +import okhttp3.WebSocketListener; +import okhttp3.WebSocket; +import okhttp3.Response; import java.util.logging.Level; @Getter @Log @AllArgsConstructor -public class ErrorListener implements WebSocket.Listener { +public class ErrorListener extends WebSocketListener { @EqualsAndHashCode.Include @ToString.Include private final Relay relay; @Override - public void onError(WebSocket webSocket, Throwable error) { + public void onFailure(WebSocket webSocket, Throwable error, Response response) { log.log(Level.WARNING, "WebSocket error: {0} - Relay {1}", new Object[]{error, relay}); error.printStackTrace(); } diff --git a/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/OpenListener.java b/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/OpenListener.java index 5ccf2962b..fb3e69d74 100644 --- a/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/OpenListener.java +++ b/nostr-java-connection/src/main/java/nostr/connection/impl/listeners/OpenListener.java @@ -7,20 +7,23 @@ import lombok.extern.java.Log; import nostr.base.Relay; -import java.net.http.WebSocket; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; +import okhttp3.Response; import java.util.logging.Level; @Getter @AllArgsConstructor @Log -public class OpenListener implements WebSocket.Listener { +public class OpenListener extends WebSocketListener { + @Getter @EqualsAndHashCode.Include @ToString.Include private final Relay relay; @Override - public void onOpen(WebSocket webSocket) { + public void onOpen(WebSocket webSocket, Response response) { log.log(Level.INFO, "WebSocket opened to {0}", relay); } } 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 0dbb7c2ba..6678b617a 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 @@ -17,14 +17,14 @@ import nostr.event.message.ClosedMessage; import nostr.event.message.RelayAuthenticationMessage; -import java.net.http.WebSocket; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; +import okhttp3.WebSocketListener; +import okhttp3.WebSocket; +import okio.ByteString; import java.util.logging.Level; @AllArgsConstructor @Log -public class TextListener implements WebSocket.Listener { +public class TextListener extends WebSocketListener { @Getter @EqualsAndHashCode.Include @@ -34,18 +34,21 @@ public class TextListener implements WebSocket.Listener { private Context context; @Override - public CompletionStage onText(WebSocket webSocket, CharSequence data, boolean last) { - - webSocket.request(1L); + public void onMessage(WebSocket webSocket, String message) { + // nocheckin + log.log(Level.INFO, "WebSocket received: " + message + " - Relay: {0}", new Object[]{relay}); + handleReceivedText(message); + } - log.log(Level.INFO, "WebSocket received: {0} - Relay: {1}", new Object[]{data, relay}); - return CompletableFuture.completedFuture(data) - .thenAccept(o -> handleReceivedText(o)); + @Override + public void onMessage(WebSocket webSocket, ByteString bytes) { + String message = bytes.toString(); + log.log(Level.INFO, "WebSocket received: {0} - Relay: {1}", new Object[]{message, relay}); + handleReceivedText(message); } - private void handleReceivedText(@NonNull CharSequence data) { - log.log(Level.INFO, "Received message {0} from {1}", new Object[]{data, relay}); - String message = data.toString(); + 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(); final String strCommand = msg.getCommand(); diff --git a/nostr-java-event/src/main/java/nostr/event/BaseTag.java b/nostr-java-event/src/main/java/nostr/event/BaseTag.java index 7063dde26..6e8a3a5f4 100644 --- a/nostr-java-event/src/main/java/nostr/event/BaseTag.java +++ b/nostr-java-event/src/main/java/nostr/event/BaseTag.java @@ -15,8 +15,8 @@ import nostr.event.json.serializer.TagSerializer; import nostr.util.NostrException; -import java.beans.IntrospectionException; -import java.beans.PropertyDescriptor; +import com.googlecode.openbeans.IntrospectionException; +import com.googlecode.openbeans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; diff --git a/pom.xml b/pom.xml index c927b4e94..f3fdb4533 100644 --- a/pom.xml +++ b/pom.xml @@ -36,6 +36,8 @@ 19 1.0.2 + 4.9.3 + 2.8.0 1.18.30