UNPKG

@nostr-dev-kit/ndk

Version:

NDK - Nostr Development Kit. Includes AI Guardrails to catch common mistakes during development.

104 lines (91 loc) 3.92 kB
import type { NDKEvent } from "../events"; import type { NDKRelay } from "."; import { NDKRelayStatus } from "."; export class NDKRelayPublisher { private ndkRelay: NDKRelay; private debug: debug.Debugger; public constructor(ndkRelay: NDKRelay) { this.ndkRelay = ndkRelay; this.debug = ndkRelay.debug.extend("publisher"); } /** * Published an event to the relay; if the relay is not connected, it will * wait for the relay to connect before publishing the event. * * If the relay does not connect within the timeout, the publish operation * will fail. * @param event The event to publish * @param timeoutMs The timeout for the publish operation in milliseconds * @returns A promise that resolves when the event has been published or rejects if the operation times out */ public async publish(event: NDKEvent, timeoutMs = 2500): Promise<boolean> { let timeout: NodeJS.Timeout | number | undefined; const publishConnected = () => { return new Promise<boolean>((resolve, reject) => { try { this.publishEvent(event) .then((_result) => { this.ndkRelay.emit("published", event); event.emit("relay:published", this.ndkRelay); resolve(true); }) .catch(reject); } catch (err) { reject(err); } }); }; const timeoutPromise = new Promise<boolean>((_, reject) => { timeout = setTimeout(() => { timeout = undefined; reject(new Error(`Timeout: ${timeoutMs}ms`)); }, timeoutMs); }); const onConnectHandler = () => { publishConnected() .then((result) => connectResolve(result)) .catch((err) => connectReject(err)); }; let connectResolve: (value: boolean | PromiseLike<boolean>) => void; // eslint-disable-next-line @typescript-eslint/no-explicit-any let connectReject: (reason?: any) => void; const onError = (err: Error) => { this.ndkRelay.debug("Publish failed", err, event.id); this.ndkRelay.emit("publish:failed", event, err); event.emit("relay:publish:failed", this.ndkRelay, err); throw err; }; const onFinally = () => { if (timeout) clearTimeout(timeout as NodeJS.Timeout); this.ndkRelay.removeListener("connect", onConnectHandler); }; if (this.ndkRelay.status >= NDKRelayStatus.CONNECTED) { /** * If we're already connected, publish the event right now */ return Promise.race([publishConnected(), timeoutPromise]).catch(onError).finally(onFinally); } if (this.ndkRelay.status <= NDKRelayStatus.DISCONNECTED) { console.warn("Relay is disconnected, trying to connect to publish an event", this.ndkRelay.url); this.ndkRelay.connect(); } else { console.warn("Relay not connected, waiting for connection to publish an event", this.ndkRelay.url); } /** * If we are not connected, try to connect and, once connected, publish the event */ return Promise.race([ new Promise<boolean>((resolve, reject) => { connectResolve = resolve; connectReject = reject; this.ndkRelay.on("connect", onConnectHandler); }), timeoutPromise, ]) .catch(onError) .finally(onFinally); } private async publishEvent(event: NDKEvent): Promise<string> { return this.ndkRelay.connectivity.publish(event.rawEvent()); } }