chore: remove dvm utils file and use useDvm hook instead
This commit is contained in:
parent
3615de70ad
commit
0ea6ba0033
@ -193,70 +193,6 @@ export class RelayController {
|
|||||||
return events[0] || null
|
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<void>((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 (
|
publish = async (
|
||||||
event: Event,
|
event: Event,
|
||||||
relayUrls: string[] = []
|
relayUrls: string[] = []
|
||||||
|
@ -13,15 +13,17 @@ import {
|
|||||||
createAndSaveAuthToken,
|
createAndSaveAuthToken,
|
||||||
getAuthToken,
|
getAuthToken,
|
||||||
getEmptyMetadataEvent,
|
getEmptyMetadataEvent,
|
||||||
getRelayMap,
|
getRelayMapFromNDKRelayList,
|
||||||
unixNow
|
unixNow
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
import { useAppDispatch, useAppSelector } from './store'
|
import { useAppDispatch, useAppSelector } from './store'
|
||||||
import { useNDKContext } from './useNDKContext'
|
import { useNDKContext } from './useNDKContext'
|
||||||
|
import { useDvm } from './useDvm'
|
||||||
|
|
||||||
export const useAuth = () => {
|
export const useAuth = () => {
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const { findMetadata } = useNDKContext()
|
const { getRelayInfo } = useDvm()
|
||||||
|
const { findMetadata, getNDKRelayList } = useNDKContext()
|
||||||
|
|
||||||
const { auth: authState, relays: relaysState } = useAppSelector(
|
const { auth: authState, relays: relaysState } = useAppSelector(
|
||||||
(state) => state
|
(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
|
// Navigate user to relays page if relay map is empty
|
||||||
return appPrivateRoutes.relays
|
return appPrivateRoutes.relays
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
getRelayInfo(relays)
|
||||||
authState.loggedIn &&
|
|
||||||
!compareObjects(relaysState?.map, relayMap.map)
|
const relayMap = getRelayMapFromNDKRelayList(ndkRelayList)
|
||||||
) {
|
|
||||||
dispatch(setRelayMapAction(relayMap.map))
|
if (authState.loggedIn && !compareObjects(relaysState?.map, relayMap)) {
|
||||||
|
dispatch(setRelayMapAction(relayMap))
|
||||||
}
|
}
|
||||||
|
|
||||||
return appPrivateRoutes.homePage
|
return appPrivateRoutes.homePage
|
||||||
},
|
},
|
||||||
[dispatch, findMetadata, authState, relaysState]
|
[
|
||||||
|
dispatch,
|
||||||
|
findMetadata,
|
||||||
|
getNDKRelayList,
|
||||||
|
getRelayInfo,
|
||||||
|
authState,
|
||||||
|
relaysState
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -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<string> => {
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,172 +1,43 @@
|
|||||||
import { Event, Filter, kinds, UnsignedEvent } from 'nostr-tools'
|
import NDK, { NDKEvent, NDKRelayList } from '@nostr-dev-kit/ndk'
|
||||||
import { RelayList } from 'nostr-tools/kinds'
|
import { kinds, UnsignedEvent } from 'nostr-tools'
|
||||||
import { getRelayInfo, unixNow } from '.'
|
import { normalizeWebSocketURL, unixNow } from '.'
|
||||||
import { NostrController, relayController } from '../controllers'
|
import { NostrController } from '../controllers'
|
||||||
import { localCache } from '../services'
|
import { RelayMap } from '../types'
|
||||||
import { RelayMap, RelaySet } from '../types'
|
import { SIGIT_RELAY } from './const'
|
||||||
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'
|
|
||||||
|
|
||||||
const READ_MARKER = 'read'
|
export const getRelayMapFromNDKRelayList = (ndkRelayList: NDKRelayList) => {
|
||||||
const WRITE_MARKER = 'write'
|
const relayMap: RelayMap = {}
|
||||||
|
|
||||||
/**
|
ndkRelayList.readRelayUrls.forEach((relayUrl) => {
|
||||||
* Attempts to find a relay list from the provided lookUpRelays.
|
const normalizedUrl = normalizeWebSocketURL(relayUrl)
|
||||||
* If the relay list is found, it will be added to the user relay list metadata.
|
|
||||||
* @param lookUpRelays
|
relayMap[normalizedUrl] = {
|
||||||
* @param hexKey
|
read: true,
|
||||||
* @return found relay list or null
|
write: false
|
||||||
*/
|
|
||||||
const findRelayListAndUpdateCache = async (
|
|
||||||
lookUpRelays: string[],
|
|
||||||
hexKey: string
|
|
||||||
): Promise<Event | null> => {
|
|
||||||
try {
|
|
||||||
const eventFilter: Filter = {
|
|
||||||
kinds: [RelayList],
|
|
||||||
authors: [hexKey]
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const event = await relayController.fetchEvent(eventFilter, lookUpRelays)
|
ndkRelayList.writeRelayUrls.forEach((relayUrl) => {
|
||||||
if (event) {
|
const normalizedUrl = normalizeWebSocketURL(relayUrl)
|
||||||
await localCache.addUserRelayListMetadata(event)
|
|
||||||
|
const existing = relayMap[normalizedUrl]
|
||||||
|
if (existing) {
|
||||||
|
existing.write = true
|
||||||
|
} else {
|
||||||
|
relayMap[normalizedUrl] = {
|
||||||
|
read: false,
|
||||||
|
write: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return event
|
})
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
return relayMap
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export const getDefaultRelayMap = (): 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<Event | null> => {
|
|
||||||
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<RelaySet>(toRelaySet, getDefaultRelaySet())
|
|
||||||
}
|
|
||||||
|
|
||||||
const getDefaultRelaySet = (): RelaySet => ({
|
|
||||||
read: [SIGIT_RELAY],
|
|
||||||
write: [SIGIT_RELAY]
|
|
||||||
})
|
|
||||||
|
|
||||||
const getDefaultRelayMap = (): RelayMap => ({
|
|
||||||
[SIGIT_RELAY]: { write: true, read: true }
|
[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.
|
* Publishes relay map.
|
||||||
* @param relayMap - relay map.
|
* @param relayMap - relay map.
|
||||||
@ -174,7 +45,7 @@ const getRelayMap = async (
|
|||||||
* @param extraRelaysToPublish - optional relays to publish relay map.
|
* @param extraRelaysToPublish - optional relays to publish relay map.
|
||||||
* @returns - promise that resolves into a string representing publishing result.
|
* @returns - promise that resolves into a string representing publishing result.
|
||||||
*/
|
*/
|
||||||
const publishRelayMap = async (
|
export const publishRelayMap = async (
|
||||||
relayMap: RelayMap,
|
relayMap: RelayMap,
|
||||||
npub: string,
|
npub: string,
|
||||||
ndk: NDK,
|
ndk: NDK,
|
||||||
@ -218,15 +89,3 @@ const publishRelayMap = async (
|
|||||||
|
|
||||||
return Promise.reject('Publishing updated relay map was unsuccessful.')
|
return Promise.reject('Publishing updated relay map was unsuccessful.')
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
|
||||||
findRelayListAndUpdateCache,
|
|
||||||
findRelayListInCache,
|
|
||||||
getDefaultRelayMap,
|
|
||||||
getDefaultRelaySet,
|
|
||||||
getRelayMap,
|
|
||||||
getUserRelaySet,
|
|
||||||
isOlderThanOneDay,
|
|
||||||
isOlderThanOneWeek,
|
|
||||||
publishRelayMap
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user