From c79b844f65f3be97a9bb16aa4649f1f16e06b0e5 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 23 Jul 2025 23:55:31 -0500 Subject: [PATCH] Use `WebSocketPool` for raw WebSocket connections --- src/lib/components/EventInput.svelte | 20 +++----- src/lib/ndk.ts | 15 +++--- src/lib/utils/community_checker.ts | 35 ++++++-------- src/lib/utils/relayDiagnostics.ts | 70 +++++++--------------------- 4 files changed, 46 insertions(+), 94 deletions(-) diff --git a/src/lib/components/EventInput.svelte b/src/lib/components/EventInput.svelte index b00fecd..7834a11 100644 --- a/src/lib/components/EventInput.svelte +++ b/src/lib/components/EventInput.svelte @@ -22,6 +22,7 @@ import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; import { Button } from "flowbite-svelte"; import { goto } from "$app/navigation"; + import { WebSocketPool } from "$lib/data_structures/websocket_pool"; let kind = $state(30023); let tags = $state<[string, string][]>([]); @@ -306,17 +307,14 @@ for (const relayUrl of relays) { try { - const ws = new WebSocket(relayUrl); + const ws = await WebSocketPool.instance.acquire(relayUrl); + await new Promise((resolve, reject) => { const timeout = setTimeout(() => { - ws.close(); + WebSocketPool.instance.release(ws); reject(new Error("Timeout")); }, 5000); - ws.onopen = () => { - ws.send(JSON.stringify(["EVENT", signedEvent])); - }; - ws.onmessage = (e) => { const [type, id, ok, message] = JSON.parse(e.data); if (type === "OK" && id === signedEvent.id) { @@ -324,20 +322,14 @@ if (ok) { published = true; relaysPublished.push(relayUrl); - ws.close(); + WebSocketPool.instance.release(ws); resolve(); } else { - ws.close(); + WebSocketPool.instance.release(ws); reject(new Error(message)); } } }; - - ws.onerror = () => { - clearTimeout(timeout); - ws.close(); - reject(new Error("WebSocket error")); - }; }); if (published) break; } catch (e) { diff --git a/src/lib/ndk.ts b/src/lib/ndk.ts index af039c4..17dbf69 100644 --- a/src/lib/ndk.ts +++ b/src/lib/ndk.ts @@ -21,6 +21,7 @@ export { testRelayConnection }; import { userStore } from "./stores/userStore.ts"; import { userPubkey } from "./stores/authStore.Svelte.ts"; import { startNetworkStatusMonitoring, stopNetworkStatusMonitoring } from "./stores/networkStore.ts"; +import { WebSocketPool } from "./data_structures/websocket_pool.ts"; export const ndkInstance: Writable = writable(); export const ndkSignedIn = writable(false); @@ -199,16 +200,14 @@ export function checkWebSocketSupport(): void { // Test if secure WebSocket is supported try { - const testWs = new WebSocket("wss://echo.websocket.org"); - testWs.onopen = () => { + WebSocketPool.instance.acquire("wss://echo.websocket.org").then((ws) => { console.debug("[NDK.ts] ✓ Secure WebSocket (wss://) is supported"); - testWs.close(); - }; - testWs.onerror = () => { + WebSocketPool.instance.release(ws); + }).catch((_) => { console.warn("[NDK.ts] ✗ Secure WebSocket (wss://) may not be supported"); - }; - } catch (error) { - console.warn("[NDK.ts] ✗ WebSocket test failed:", error); + }); + } catch { + console.warn("[NDK.ts] ✗ WebSocket test failed"); } } diff --git a/src/lib/utils/community_checker.ts b/src/lib/utils/community_checker.ts index 7e6ea11..1d19d91 100644 --- a/src/lib/utils/community_checker.ts +++ b/src/lib/utils/community_checker.ts @@ -1,4 +1,5 @@ import { communityRelays } from "$lib/consts"; +import { WebSocketPool } from "../data_structures/websocket_pool.ts"; import { RELAY_CONSTANTS, SEARCH_LIMITS } from "./search_constants"; // Cache for pubkeys with kind 1 events on communityRelay @@ -16,37 +17,31 @@ export async function checkCommunity(pubkey: string): Promise { // Try each community relay until we find one that works for (const relayUrl of communityRelays) { try { - const ws = new WebSocket(relayUrl); + const ws = await WebSocketPool.instance.acquire(relayUrl); const result = await new Promise((resolve) => { - ws.onopen = () => { - ws.send( - JSON.stringify([ - "REQ", - RELAY_CONSTANTS.COMMUNITY_REQUEST_ID, - { - kinds: RELAY_CONSTANTS.COMMUNITY_REQUEST_KINDS, - authors: [pubkey], - limit: SEARCH_LIMITS.COMMUNITY_CHECK, - }, - ]), - ); - }; + ws.send( + JSON.stringify([ + "REQ", + RELAY_CONSTANTS.COMMUNITY_REQUEST_ID, + { + kinds: RELAY_CONSTANTS.COMMUNITY_REQUEST_KINDS, + authors: [pubkey], + limit: SEARCH_LIMITS.COMMUNITY_CHECK, + }, + ]), + ); ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data[0] === "EVENT" && data[2]?.kind === 1) { communityCache.set(pubkey, true); - ws.close(); + WebSocketPool.instance.release(ws); resolve(true); } else if (data[0] === "EOSE") { communityCache.set(pubkey, false); - ws.close(); + WebSocketPool.instance.release(ws); resolve(false); } }; - ws.onerror = () => { - ws.close(); - resolve(false); - }; }); if (result) { diff --git a/src/lib/utils/relayDiagnostics.ts b/src/lib/utils/relayDiagnostics.ts index df61930..6be37c4 100644 --- a/src/lib/utils/relayDiagnostics.ts +++ b/src/lib/utils/relayDiagnostics.ts @@ -1,3 +1,4 @@ +import { WebSocketPool } from "../data_structures/websocket_pool.ts"; import { activeInboxRelays, activeOutboxRelays } from "../ndk.ts"; import { TIMEOUTS } from "./search_constants.ts"; import { get } from "svelte/store"; @@ -13,72 +14,37 @@ export interface RelayDiagnostic { /** * Tests connection to a single relay */ -export function testRelay(url: string): Promise { +export async function testRelay(url: string): Promise { const startTime = Date.now(); + const ws = await WebSocketPool.instance.acquire(url); return new Promise((resolve) => { - const ws = new WebSocket(url); - let resolved = false; - const timeout = setTimeout(() => { - if (!resolved) { - resolved = true; - ws.close(); - resolve({ - url, - connected: false, - requiresAuth: false, - error: "Connection timeout", - responseTime: Date.now() - startTime, - }); - } + WebSocketPool.instance.release(ws); + resolve({ + url, + connected: false, + requiresAuth: false, + error: "Connection timeout", + responseTime: Date.now() - startTime, + }); }, TIMEOUTS.RELAY_DIAGNOSTICS); - ws.onopen = () => { - if (!resolved) { - resolved = true; + ws.onmessage = (event) => { + const data = JSON.parse(event.data); + if (data[0] === "NOTICE" && data[1]?.includes("auth-required")) { clearTimeout(timeout); - ws.close(); + WebSocketPool.instance.release(ws); resolve({ url, connected: true, - requiresAuth: false, + requiresAuth: true, responseTime: Date.now() - startTime, }); } - }; - - ws.onerror = () => { - if (!resolved) { - resolved = true; - clearTimeout(timeout); - resolve({ - url, - connected: false, - requiresAuth: false, - error: "WebSocket error", - responseTime: Date.now() - startTime, - }); - } - }; - - ws.onmessage = (event) => { - const data = JSON.parse(event.data); - if (data[0] === "NOTICE" && data[1]?.includes("auth-required")) { - if (!resolved) { - resolved = true; - clearTimeout(timeout); - ws.close(); - resolve({ - url, - connected: true, - requiresAuth: true, - responseTime: Date.now() - startTime, - }); - } - } - }; + } }); + } /**