import {Event, Filter, relayInit, Relay, Sub} from 'nostr-tools'; type SubCallback = ( event: Readonly, relay: Readonly, ) => void; type Subscribe = { cb: SubCallback; filter: Filter; unsub?: boolean; }; const subList: Array = []; const currentSubList: Array = []; const relayMap = new Map(); export const addRelay = async (url: string) => { const relay = relayInit(url); relay.on('connect', () => { console.info(`connected to ${relay.url}`); }); relay.on('error', () => { console.warn(`failed to connect to ${relay.url}`); }); try { await relay.connect(); currentSubList.forEach(({cb, filter}) => subscribe(cb, filter, relay)); relayMap.set(url, relay); } catch { console.warn(`could not connect to ${url}`); } }; export const unsubscribe = (sub: Sub) => { sub.unsub(); subList.splice(subList.indexOf(sub), 1); }; const subscribe = ( cb: SubCallback, filter: Filter, relay: Relay, unsub?: boolean ) => { const sub = relay.sub([filter]); subList.push(sub); sub.on('event', (event: Event) => { cb(event, relay.url); }); if (unsub) { sub.on('eose', () => { // console.log('eose', relay.url); unsubscribe(sub); }); } return sub; }; export const sub = (obj: Subscribe) => { currentSubList.push(obj); relayMap.forEach((relay) => subscribe(obj.cb, obj.filter, relay, obj.unsub)); }; export const subOnce = ( obj: Subscribe & {relay: string} ) => { const relay = relayMap.get(obj.relay); if (relay) { const sub = subscribe(obj.cb, obj.filter, relay); sub.on('eose', () => { // console.log('eose', obj.relay); unsubscribe(sub); }); } }; export const unsubAll = () => { subList.forEach(unsubscribe); currentSubList.length = 0; }; type PublishCallback = ( relay: string, errorMessage?: string, ) => void; export const publish = ( event: Event, cb: PublishCallback, ) => { relayMap.forEach((relay, url) => { const pub = relay.publish(event); pub.on('ok', () => { console.info(`${relay.url} has accepted our event`); cb(relay.url); }); pub.on('failed', (reason: any) => { console.error(`failed to publish to ${relay.url}: ${reason}`); cb(relay.url, reason); }); }); }; addRelay('wss://relay.snort.social'); addRelay('wss://nostr.bitcoiner.social'); addRelay('wss://nostr.mom'); addRelay('wss://relay.nostr.bg'); addRelay('wss://nos.lol'); // addRelay('wss://relay.nostr.ch');