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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ The format is inspired by Keep a Changelog, and this project adheres to semantic
- `BaseKey` now directly implements `Serializable` (previously implemented the now-deleted `IKey` interface).
- `Nip05Validator` now creates `HttpClient` instances directly via a `Function<Duration, HttpClient>` factory (previously used deleted `HttpClientProvider`/`DefaultHttpClientProvider` interface).

## [2.0.1] - 2026-05-06

### Fixed
- `NostrRelayClient` log statements were emitting `Sending request to relay null: ...` (and similar) once the WebSocket session had closed, because the relay URI was being read via `clientSession.getUri()` which returns `null` after close. Captured the URI in a `private final String relayUri` field set in each constructor and replaced 8 `clientSession.getUri()` log call-sites. Resolves 188 occurrences per 2-hour window observed in a downstream consumer's staging logs ([#523](https://github.com/tcheeric/nostr-java/pull/523)).

## [2.0.0] - 2026-02-24

This is a major release that implements the full design simplification described in `docs/developer/SIMPLIFICATION_PROPOSAL.md`, reducing the library from 9 modules with ~180 classes to 4 modules with ~40 classes.
Expand Down
2 changes: 1 addition & 1 deletion nostr-java-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>xyz.tcheeric</groupId>
<artifactId>nostr-java</artifactId>
<version>2.0.0</version>
<version>2.0.1</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ public class NostrRelayClient extends TextWebSocketHandler implements AutoClosea
private int maxEventsPerRequest = DEFAULT_MAX_EVENTS_PER_REQUEST;

private final WebSocketSession clientSession;
/**
* Relay URI captured at construction time. Used for logging so that
* messages remain meaningful even after the underlying WebSocket session
* has been closed (at which point {@link WebSocketSession#getUri()} may
* return {@code null} on some implementations).
*/
private final String relayUri;
private final ReentrantLock sendLock = new ReentrantLock();
private PendingRequest pendingRequest;
private final Map<String, ListenerRegistration> listeners = new ConcurrentHashMap<>();
Expand Down Expand Up @@ -119,6 +126,7 @@ int eventCount() {

public NostrRelayClient(@Value("${nostr.relay.uri}") String relayUri)
throws java.util.concurrent.ExecutionException, InterruptedException {
this.relayUri = relayUri;
this.clientSession = connectSession(relayUri);
connectionState.set(ConnectionState.CONNECTED);
}
Expand All @@ -129,6 +137,7 @@ public NostrRelayClient(String relayUri, long awaitTimeoutMs)
throw new IllegalArgumentException("awaitTimeoutMs must be positive");
}
this.awaitTimeoutMs = awaitTimeoutMs;
this.relayUri = relayUri;
log.info("NostrRelayClient created for {} with awaitTimeoutMs={}", relayUri, awaitTimeoutMs);
this.clientSession = connectSession(relayUri);
connectionState.set(ConnectionState.CONNECTED);
Expand All @@ -143,6 +152,14 @@ public NostrRelayClient(String relayUri, long awaitTimeoutMs)
}
this.clientSession = clientSession;
this.awaitTimeoutMs = awaitTimeoutMs;
URI sessionUri = null;
try {
sessionUri = clientSession.getUri();
} catch (Exception ignored) {
// Some WebSocketSession implementations may throw before the session
// is fully initialised; fall through and store null.
}
this.relayUri = sessionUri == null ? null : sessionUri.toString();
connectionState.set(ConnectionState.CONNECTED);
}

Expand Down Expand Up @@ -253,7 +270,7 @@ public void afterConnectionClosed(@NonNull WebSocketSession session, @NonNull Cl
public <T extends BaseMessage> List<String> send(T eventMessage) throws IOException {
String json = eventMessage.encode();
log.debug("Sending {} to relay {} (size={} bytes)",
eventMessage.getCommand(), clientSession.getUri(), json.length());
eventMessage.getCommand(), relayUri, json.length());
return send(json);
}

Expand All @@ -269,7 +286,7 @@ public List<String> send(String json) throws IOException {
}
request = new PendingRequest(maxEventsPerRequest);
pendingRequest = request;
log.info("Sending request to relay {}: {}", clientSession.getUri(), json);
log.info("Sending request to relay {}: {}", relayUri, json);
clientSession.sendMessage(new TextMessage(json));
} finally {
sendLock.unlock();
Expand All @@ -280,7 +297,7 @@ public List<String> send(String json) throws IOException {

try {
List<String> result = request.getFuture().get(timeout, TimeUnit.MILLISECONDS);
log.info("Received {} relay events via {}", result.size(), clientSession.getUri());
log.info("Received {} relay events via {}", result.size(), relayUri);
return result;
} catch (TimeoutException e) {
log.error("Timed out waiting for relay response after {}ms", timeout);
Expand Down Expand Up @@ -350,7 +367,7 @@ public <T extends BaseMessage> AutoCloseable subscribe(
throws IOException {
String json = requestMessage.encode();
log.debug("Subscribing with {} on relay {} (size={} bytes)",
requestMessage.getCommand(), clientSession.getUri(), json.length());
requestMessage.getCommand(), relayUri, json.length());
return subscribe(json, messageListener, errorListener, closeListener);
}

Expand Down Expand Up @@ -425,15 +442,15 @@ public <T extends BaseMessage> CompletableFuture<AutoCloseable> subscribeAsync(
@Recover
public List<String> recover(IOException ex, String json) throws IOException {
log.error("Failed to send message to relay {} after retries (size={} bytes)",
clientSession.getUri(), json.length(), ex);
relayUri, json.length(), ex);
throw ex;
}

@Recover
public List<String> recover(IOException ex, BaseMessage eventMessage) throws IOException {
String json = eventMessage.encode();
log.error("Failed to send {} to relay {} after retries (size={} bytes)",
eventMessage.getCommand(), clientSession.getUri(), json.length(), ex);
eventMessage.getCommand(), relayUri, json.length(), ex);
throw ex;
}

Expand All @@ -446,7 +463,7 @@ public AutoCloseable recoverSubscription(
Runnable closeListener)
throws IOException {
log.error("Failed to subscribe on relay {} after retries (size={} bytes)",
clientSession.getUri(), json.length(), ex);
relayUri, json.length(), ex);
throw ex;
}

Expand All @@ -460,7 +477,7 @@ public AutoCloseable recoverSubscription(
throws IOException {
String json = requestMessage.encode();
log.error("Failed to subscribe with {} on relay {} after retries (size={} bytes)",
requestMessage.getCommand(), clientSession.getUri(), json.length(), ex);
requestMessage.getCommand(), relayUri, json.length(), ex);
throw ex;
}

Expand Down
2 changes: 1 addition & 1 deletion nostr-java-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>xyz.tcheeric</groupId>
<artifactId>nostr-java</artifactId>
<version>2.0.0</version>
<version>2.0.1</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion nostr-java-event/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>xyz.tcheeric</groupId>
<artifactId>nostr-java</artifactId>
<version>2.0.0</version>
<version>2.0.1</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion nostr-java-identity/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>xyz.tcheeric</groupId>
<artifactId>nostr-java</artifactId>
<version>2.0.0</version>
<version>2.0.1</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<groupId>xyz.tcheeric</groupId>
<artifactId>nostr-java</artifactId>
<version>2.0.0</version>
<version>2.0.1</version>
Comment thread
tcheeric marked this conversation as resolved.
<packaging>pom</packaging>

<name>nostr-java</name>
Expand Down