From 0ea6ba003345e4a2bd89c1a9387ca7daa5c4f54e Mon Sep 17 00:00:00 2001 From: daniyal Date: Sun, 22 Dec 2024 21:53:00 +0500 Subject: [PATCH] chore: remove dvm utils file and use useDvm hook instead --- src/controllers/RelayController.ts | 64 --------- src/hooks/useAuth.ts | 31 +++-- src/utils/dvm.ts | 98 -------------- src/utils/relays.ts | 203 +++++------------------------ 4 files changed, 52 insertions(+), 344 deletions(-) delete mode 100644 src/utils/dvm.ts diff --git a/src/controllers/RelayController.ts b/src/controllers/RelayController.ts index df33b4b..ee66472 100644 --- a/src/controllers/RelayController.ts +++ b/src/controllers/RelayController.ts @@ -193,70 +193,6 @@ export class RelayController { return events[0] || null } - /** - * Subscribes to events from multiple relays. - * - * This method connects to the specified relay URLs and subscribes to events - * using the provided filter. It handles incoming events through the given - * `eventHandler` callback and manages the subscription lifecycle. - * - * @param filter - The filter criteria to apply when subscribing to events. - * @param relayUrls - An optional array of relay URLs to connect to. The default relay URL (`SIGIT_RELAY`) is added automatically. - * @param eventHandler - A callback function to handle incoming events. It receives an `Event` object. - * - */ - subscribeForEvents = async ( - filter: Filter, - relayUrls: string[] = [], - eventHandler: (event: Event) => void - ) => { - if (!relayUrls.includes(SIGIT_RELAY)) { - /** - * NOTE: To avoid side-effects on external relayUrls array passed as argument - * re-assigned relayUrls with added sigit relay instead of just appending to same array - */ - relayUrls = [...relayUrls, SIGIT_RELAY] // Add app relay to relays array if not exists already - } - - // connect to all specified relays - const relays = await settleAllFullfilfedPromises( - relayUrls, - this.connectRelay - ) - - // Check if any relays are connected - if (relays.length === 0) { - throw new Error('No relay is connected to fetch events!') - } - - const processedEvents: string[] = [] // To keep track of processed events - - // Create a promise for each relay subscription - const subPromises = relays.map((relay) => { - return new Promise((resolve) => { - // Subscribe to the relay with the specified filter - const sub = relay.subscribe([filter], { - // Handle incoming events - onevent: (e) => { - // Process event only if it hasn't been processed before - if (!processedEvents.includes(e.id)) { - processedEvents.push(e.id) - eventHandler(e) // Call the event handler with the event - } - }, - // Handle the End-Of-Stream (EOSE) message - oneose: () => { - sub.close() // Close the subscription - resolve() // Resolve the promise when EOSE is received - } - }) - }) - }) - - // Wait for all subscriptions to complete - await Promise.allSettled(subPromises) - } - publish = async ( event: Event, relayUrls: string[] = [] diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts index 4ad0cd0..ff38a06 100644 --- a/src/hooks/useAuth.ts +++ b/src/hooks/useAuth.ts @@ -13,15 +13,17 @@ import { createAndSaveAuthToken, getAuthToken, getEmptyMetadataEvent, - getRelayMap, + getRelayMapFromNDKRelayList, unixNow } from '../utils' import { useAppDispatch, useAppSelector } from './store' import { useNDKContext } from './useNDKContext' +import { useDvm } from './useDvm' export const useAuth = () => { const dispatch = useAppDispatch() - const { findMetadata } = useNDKContext() + const { getRelayInfo } = useDvm() + const { findMetadata, getNDKRelayList } = useNDKContext() const { auth: authState, relays: relaysState } = useAppSelector( (state) => state @@ -101,23 +103,32 @@ export const useAuth = () => { }) ) - const relayMap = await getRelayMap(pubkey) + const ndkRelayList = await getNDKRelayList(pubkey) + const relays = ndkRelayList.relays - if (Object.keys(relayMap).length < 1) { + if (relays.length < 1) { // Navigate user to relays page if relay map is empty return appPrivateRoutes.relays } - if ( - authState.loggedIn && - !compareObjects(relaysState?.map, relayMap.map) - ) { - dispatch(setRelayMapAction(relayMap.map)) + getRelayInfo(relays) + + const relayMap = getRelayMapFromNDKRelayList(ndkRelayList) + + if (authState.loggedIn && !compareObjects(relaysState?.map, relayMap)) { + dispatch(setRelayMapAction(relayMap)) } return appPrivateRoutes.homePage }, - [dispatch, findMetadata, authState, relaysState] + [ + dispatch, + findMetadata, + getNDKRelayList, + getRelayInfo, + authState, + relaysState + ] ) return { diff --git a/src/utils/dvm.ts b/src/utils/dvm.ts deleted file mode 100644 index 24d637e..0000000 --- a/src/utils/dvm.ts +++ /dev/null @@ -1,98 +0,0 @@ -import NDK, { NDKEvent, NDKSubscription } from '@nostr-dev-kit/ndk' -import { EventTemplate } from 'nostr-tools' -import { compareObjects, unixNow } from '.' -import { NostrController, relayController } from '../controllers' -import { setRelayInfoAction } from '../store/actions' -import store from '../store/store' -import { RelayInfoObject } from '../types' - -/** - * Sets information about relays into relays.info app state. - * @param relayURIs - relay URIs to get information about - */ -export const getRelayInfo = async (relayURIs: string[]) => { - // initialize job request - const jobEventTemplate: EventTemplate = { - content: '', - created_at: unixNow(), - kind: 68001, - tags: [ - ['i', `${JSON.stringify(relayURIs)}`], - ['j', 'relay-info'] - ] - } - - const nostrController = NostrController.getInstance() - - // sign job request event - const jobSignedEvent = await nostrController.signEvent(jobEventTemplate) - - const relays = [ - 'wss://relay.damus.io', - 'wss://relay.primal.net', - 'wss://relayable.org' - ] - - // publish job request - await relayController.publish(jobSignedEvent, relays) - - console.log('jobSignedEvent :>> ', jobSignedEvent) - - const subscribeWithTimeout = ( - subscription: NDKSubscription, - timeoutMs: number - ): Promise => { - return new Promise((resolve, reject) => { - const eventHandler = (event: NDKEvent) => { - subscription.stop() - resolve(event.content) - } - - subscription.on('event', eventHandler) - - // Set up a timeout to stop the subscription after a specified time - const timeout = setTimeout(() => { - subscription.stop() // Stop the subscription - reject(new Error('Subscription timed out')) // Reject the promise with a timeout error - }, timeoutMs) - - // Handle subscription close event - subscription.on('close', () => clearTimeout(timeout)) - }) - } - - const dvmNDK = new NDK({ - explicitRelayUrls: relays - }) - - await dvmNDK.connect(2000) - - // filter for getting DVM job's result - const sub = dvmNDK.subscribe({ - kinds: [68002 as number], - '#e': [jobSignedEvent.id], - '#p': [jobSignedEvent.pubkey] - }) - - // asynchronously get block number from dvm job with 20 seconds timeout - const dvmJobResult = await subscribeWithTimeout(sub, 20000) - - if (!dvmJobResult) { - return Promise.reject(`Relay(s) information wasn't received`) - } - - let relaysInfo: RelayInfoObject - - try { - relaysInfo = JSON.parse(dvmJobResult) - } catch (error) { - return Promise.reject(`Invalid relay(s) information.`) - } - - if ( - relaysInfo && - !compareObjects(store.getState().relays?.info, relaysInfo) - ) { - store.dispatch(setRelayInfoAction(relaysInfo)) - } -} diff --git a/src/utils/relays.ts b/src/utils/relays.ts index bcbbad9..bcb2e98 100644 --- a/src/utils/relays.ts +++ b/src/utils/relays.ts @@ -1,172 +1,43 @@ -import { Event, Filter, kinds, UnsignedEvent } from 'nostr-tools' -import { RelayList } from 'nostr-tools/kinds' -import { getRelayInfo, unixNow } from '.' -import { NostrController, relayController } from '../controllers' -import { localCache } from '../services' -import { RelayMap, RelaySet } from '../types' -import { - DEFAULT_LOOK_UP_RELAY_LIST, - ONE_DAY_IN_MS, - ONE_WEEK_IN_MS, - SIGIT_RELAY -} from './const' -import NDK, { NDKEvent } from '@nostr-dev-kit/ndk' +import NDK, { NDKEvent, NDKRelayList } from '@nostr-dev-kit/ndk' +import { kinds, UnsignedEvent } from 'nostr-tools' +import { normalizeWebSocketURL, unixNow } from '.' +import { NostrController } from '../controllers' +import { RelayMap } from '../types' +import { SIGIT_RELAY } from './const' -const READ_MARKER = 'read' -const WRITE_MARKER = 'write' +export const getRelayMapFromNDKRelayList = (ndkRelayList: NDKRelayList) => { + const relayMap: RelayMap = {} -/** - * Attempts to find a relay list from the provided lookUpRelays. - * If the relay list is found, it will be added to the user relay list metadata. - * @param lookUpRelays - * @param hexKey - * @return found relay list or null - */ -const findRelayListAndUpdateCache = async ( - lookUpRelays: string[], - hexKey: string -): Promise => { - try { - const eventFilter: Filter = { - kinds: [RelayList], - authors: [hexKey] + ndkRelayList.readRelayUrls.forEach((relayUrl) => { + const normalizedUrl = normalizeWebSocketURL(relayUrl) + + relayMap[normalizedUrl] = { + read: true, + write: false } + }) - const event = await relayController.fetchEvent(eventFilter, lookUpRelays) - if (event) { - await localCache.addUserRelayListMetadata(event) + ndkRelayList.writeRelayUrls.forEach((relayUrl) => { + const normalizedUrl = normalizeWebSocketURL(relayUrl) + + const existing = relayMap[normalizedUrl] + if (existing) { + existing.write = true + } else { + relayMap[normalizedUrl] = { + read: false, + write: true + } } - return event - } catch (error) { - console.error(error) - return null - } + }) + + return relayMap } -/** - * Attempts to find a relay list in cache. If it is present, it will check that the cached event is not - * older than one week. - * @param hexKey - * @return RelayList event if it's not older than a week; otherwise null - */ -const findRelayListInCache = async (hexKey: string): Promise => { - try { - // Attempt to retrieve the metadata event from the local cache - const cachedRelayListMetadataEvent = - await localCache.getUserRelayListMetadata(hexKey) - - // Check if the cached event is not older than one week - if ( - cachedRelayListMetadataEvent && - !isOlderThanOneWeek(cachedRelayListMetadataEvent.cachedAt) - ) { - return cachedRelayListMetadataEvent.event - } - - return null - } catch (error) { - console.error(error) - return null - } -} - -/** - * Transforms a list of relay tags from a Nostr Event to a RelaySet. - * @param tags - */ -const getUserRelaySet = (tags: string[][]): RelaySet => { - return tags - .filter(isRelayTag) - .reduce(toRelaySet, getDefaultRelaySet()) -} - -const getDefaultRelaySet = (): RelaySet => ({ - read: [SIGIT_RELAY], - write: [SIGIT_RELAY] -}) - -const getDefaultRelayMap = (): RelayMap => ({ +export const getDefaultRelayMap = (): RelayMap => ({ [SIGIT_RELAY]: { write: true, read: true } }) -const isOlderThanOneWeek = (cachedAt: number) => { - return Date.now() - cachedAt > ONE_WEEK_IN_MS -} - -const isOlderThanOneDay = (cachedAt: number) => { - return Date.now() - cachedAt > ONE_DAY_IN_MS -} - -const isRelayTag = (tag: string[]): boolean => tag[0] === 'r' - -const toRelaySet = (obj: RelaySet, tag: string[]): RelaySet => { - if (tag.length >= 3) { - const marker = tag[2] - - if (marker === READ_MARKER) { - obj.read.push(tag[1]) - } else if (marker === WRITE_MARKER) { - obj.write.push(tag[1]) - } - } - if (tag.length === 2) { - obj.read.push(tag[1]) - obj.write.push(tag[1]) - } - - return obj -} - -/** - * Provides relay map. - * @param npub - user's npub - * @returns - promise that resolves into relay map and a timestamp when it has been updated. - */ -const getRelayMap = async ( - npub: string -): Promise<{ map: RelayMap; mapUpdated?: number }> => { - // More info about this kind of event available https://github.com/nostr-protocol/nips/blob/master/65.md - const eventFilter: Filter = { - kinds: [kinds.RelayList], - authors: [npub] - } - - const event = await relayController - .fetchEvent(eventFilter, DEFAULT_LOOK_UP_RELAY_LIST) - .catch((err) => { - return Promise.reject(err) - }) - - if (event) { - // Handle founded 10002 event - const relaysMap: RelayMap = {} - - // 'r' stands for 'relay' - const relayTags = event.tags.filter((tag) => tag[0] === 'r') - - relayTags.forEach((tag) => { - const uri = tag[1] - const relayType = tag[2] - - // if 3rd element of relay tag is undefined, relay is WRITE and READ - relaysMap[uri] = { - write: relayType ? relayType === 'write' : true, - read: relayType ? relayType === 'read' : true - } - }) - - Object.keys(relaysMap).forEach((relayUrl) => - relayController.connectRelay(relayUrl) - ) - - getRelayInfo(Object.keys(relaysMap)) - - return Promise.resolve({ map: relaysMap, mapUpdated: event.created_at }) - } else { - return Promise.resolve({ map: getDefaultRelayMap() }) - } -} - /** * Publishes relay map. * @param relayMap - relay map. @@ -174,7 +45,7 @@ const getRelayMap = async ( * @param extraRelaysToPublish - optional relays to publish relay map. * @returns - promise that resolves into a string representing publishing result. */ -const publishRelayMap = async ( +export const publishRelayMap = async ( relayMap: RelayMap, npub: string, ndk: NDK, @@ -218,15 +89,3 @@ const publishRelayMap = async ( return Promise.reject('Publishing updated relay map was unsuccessful.') } - -export { - findRelayListAndUpdateCache, - findRelayListInCache, - getDefaultRelayMap, - getDefaultRelaySet, - getRelayMap, - getUserRelaySet, - isOlderThanOneDay, - isOlderThanOneWeek, - publishRelayMap -}