Bound the relay connect handshake so a fetch can't hang forever

This commit is contained in:
randogoth 2026-07-05 16:50:28 +03:00
parent 0e70aba755
commit 60f9e4ccfa
3 changed files with 41 additions and 1 deletions

View file

@ -31,15 +31,23 @@ final class EventsFetched extends FetchResult {
class NostrFetchActor with Handler<FetchMessage, FetchResult> {
final List<String> _relayUrls;
final Duration _eoseDeadline;
final Duration _connectDeadline;
final RelayConnection Function(String url) _connectionFactory;
NostrFetchActor({
required List<String> relayUrls,
Duration eoseDeadline = const Duration(seconds: 5),
// Bounds the WebSocket/TLS handshake. `connect()` awaits `channel.ready`
// with no deadline of its own, so a relay that accepts the socket but never
// completes the upgrade would hang the fetch forever and, for a polling
// consumer, silently wedge its whole loop. On timeout the `finally` below
// closes the half-open socket and the relay is treated as down.
Duration connectDeadline = const Duration(seconds: 10),
RelayConnection Function(String url) connectionFactory =
WebSocketRelayConnection.new,
}) : _relayUrls = relayUrls,
_eoseDeadline = eoseDeadline,
_connectDeadline = connectDeadline,
_connectionFactory = connectionFactory;
@override
@ -78,7 +86,7 @@ class NostrFetchActor with Handler<FetchMessage, FetchResult> {
final collected = <String>[];
try {
await conn.connect();
await conn.connect().timeout(_connectDeadline);
await conn.send(jsonEncode(['REQ', subId, jsonDecode(filter)]));
try {
await for (final raw in conn.messages.timeout(_eoseDeadline)) {