Browse Source

Use `WebSocketPool` for raw WebSocket connections

master
buttercat1791 8 months ago
parent
commit
c79b844f65
  1. 20
      src/lib/components/EventInput.svelte
  2. 15
      src/lib/ndk.ts
  3. 35
      src/lib/utils/community_checker.ts
  4. 70
      src/lib/utils/relayDiagnostics.ts

20
src/lib/components/EventInput.svelte

@ -22,6 +22,7 @@ @@ -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<number>(30023);
let tags = $state<[string, string][]>([]);
@ -306,17 +307,14 @@ @@ -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<void>((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 @@ @@ -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) {

15
src/lib/ndk.ts

@ -21,6 +21,7 @@ export { testRelayConnection }; @@ -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<NDK> = writable();
export const ndkSignedIn = writable(false);
@ -199,16 +200,14 @@ export function checkWebSocketSupport(): void { @@ -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");
}
}

35
src/lib/utils/community_checker.ts

@ -1,4 +1,5 @@ @@ -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<boolean> { @@ -16,37 +17,31 @@ export async function checkCommunity(pubkey: string): Promise<boolean> {
// 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<boolean>((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) {

70
src/lib/utils/relayDiagnostics.ts

@ -1,3 +1,4 @@ @@ -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 { @@ -13,72 +14,37 @@ export interface RelayDiagnostic {
/**
* Tests connection to a single relay
*/
export function testRelay(url: string): Promise<RelayDiagnostic> {
export async function testRelay(url: string): Promise<RelayDiagnostic> {
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,
});
}
}
};
}
});
}
/**

Loading…
Cancel
Save