chore(refactor): use getNDKRelayList function from NDKContext instead of findRelayListMetadata function of metadata controller

This commit is contained in:
daniyal 2024-12-20 21:58:45 +05:00
parent 458de18f12
commit 5c24c5bde0
8 changed files with 64 additions and 134 deletions

View File

@ -1,7 +1,9 @@
import NDK, { import NDK, {
getRelayListForUser, getRelayListForUser,
Hexpubkey,
NDKEvent, NDKEvent,
NDKFilter, NDKFilter,
NDKRelayList,
NDKRelaySet, NDKRelaySet,
NDKSubscriptionCacheUsage, NDKSubscriptionCacheUsage,
NDKSubscriptionOptions, NDKSubscriptionOptions,
@ -19,6 +21,7 @@ import {
DEFAULT_LOOK_UP_RELAY_LIST, DEFAULT_LOOK_UP_RELAY_LIST,
hexToNpub, hexToNpub,
orderEventsChronologically, orderEventsChronologically,
SIGIT_RELAY,
timeout timeout
} from '../utils' } from '../utils'
@ -41,6 +44,7 @@ export interface NDKContextType {
opts?: NDKSubscriptionOptions, opts?: NDKSubscriptionOptions,
storeProfileEvent?: boolean storeProfileEvent?: boolean
) => Promise<NDKUserProfile | null> ) => Promise<NDKUserProfile | null>
getNDKRelayList: (pubkey: Hexpubkey) => Promise<NDKRelayList>
publish: (event: NDKEvent, explicitRelayUrls?: string[]) => Promise<string[]> publish: (event: NDKEvent, explicitRelayUrls?: string[]) => Promise<string[]>
} }
@ -214,6 +218,19 @@ export const NDKContextProvider = ({ children }: { children: ReactNode }) => {
) )
} }
const getNDKRelayList = async (pubkey: Hexpubkey) => {
const ndkRelayList = await Promise.race([
getRelayListForUser(pubkey, ndk),
timeout(10000)
]).catch(() => {
const relayList = new NDKRelayList(ndk)
relayList.bothRelayUrls = [SIGIT_RELAY]
return relayList
})
return ndkRelayList
}
const publish = async ( const publish = async (
event: NDKEvent, event: NDKEvent,
explicitRelayUrls?: string[] explicitRelayUrls?: string[]
@ -247,6 +264,7 @@ export const NDKContextProvider = ({ children }: { children: ReactNode }) => {
fetchEventsFromUserRelays, fetchEventsFromUserRelays,
fetchEventFromUserRelays, fetchEventFromUserRelays,
findMetadata, findMetadata,
getNDKRelayList,
publish publish
}} }}
> >

View File

@ -1,56 +0,0 @@
import { Event } from 'nostr-tools'
import { EventEmitter } from 'tseep'
import { ProfileMetadata, RelaySet } from '../types'
import {
findRelayListAndUpdateCache,
findRelayListInCache,
getDefaultRelaySet,
getUserRelaySet
} from '../utils'
import { DEFAULT_LOOK_UP_RELAY_LIST } from '../utils/const'
export class MetadataController extends EventEmitter {
private static instance: MetadataController
constructor() {
super()
}
public static getInstance(): MetadataController {
if (!MetadataController.instance) {
MetadataController.instance = new MetadataController()
}
return MetadataController.instance
}
/**
* Based on the hexKey of the current user, this method attempts to retrieve a relay set.
* @func findRelayListInCache first checks if there is already an up-to-date
* relay list available in cache; if not -
* @func findRelayListAndUpdateCache checks if the relevant relay event is available from
* the purple pages relay;
* @func findRelayListAndUpdateCache will run again if the previous two calls return null and
* check if the relevant relay event can be obtained from 'most popular relays'
* If relay event is found, it will be saved in cache for future use
* @param hexKey of the current user
* @return RelaySet which will contain either relays extracted from the user Relay Event
* or a fallback RelaySet with Sigit's Relay
*/
public findRelayListMetadata = async (hexKey: string): Promise<RelaySet> => {
const relayEvent =
(await findRelayListInCache(hexKey)) ||
(await findRelayListAndUpdateCache(DEFAULT_LOOK_UP_RELAY_LIST, hexKey))
return relayEvent ? getUserRelaySet(relayEvent.tags) : getDefaultRelaySet()
}
public extractProfileMetadataContent = (event: Event) => {
try {
if (!event.content) return {}
return JSON.parse(event.content) as ProfileMetadata
} catch (error) {
console.log('error in parsing metadata event content :>> ', error)
return null
}
}
}

View File

@ -1,4 +1,2 @@
export * from './AuthController'
export * from './MetadataController'
export * from './NostrController' export * from './NostrController'
export * from './RelayController' export * from './RelayController'

View File

@ -44,7 +44,7 @@ export const MainLayout = () => {
const navigate = useNavigate() const navigate = useNavigate()
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const logout = useLogout() const logout = useLogout()
const { findMetadata } = useNDKContext() const { findMetadata, getNDKRelayList } = useNDKContext()
const { authAndGetMetadataAndRelaysMap } = useAuth() const { authAndGetMetadataAndRelaysMap } = useAuth()
const [isLoading, setIsLoading] = useState(true) const [isLoading, setIsLoading] = useState(true)
@ -191,13 +191,13 @@ export const MainLayout = () => {
if (pubkey && !hasSubscribed.current) { if (pubkey && !hasSubscribed.current) {
// Call `subscribeForSigits` only if it hasn't been called before // Call `subscribeForSigits` only if it hasn't been called before
// #193 disabled websocket subscribtion, until #194 is done // #193 disabled websocket subscribtion, until #194 is done
subscribeForSigits(pubkey) subscribeForSigits(pubkey, getNDKRelayList)
// Mark `subscribeForSigits` as called // Mark `subscribeForSigits` as called
hasSubscribed.current = true hasSubscribed.current = true
} }
} }
}, [authState, isLoggedIn, usersAppData]) }, [authState, isLoggedIn, usersAppData, getNDKRelayList])
/** /**
* When authState change user logged in / or app reloaded * When authState change user logged in / or app reloaded
@ -214,7 +214,7 @@ export const MainLayout = () => {
setIsLoading(true) setIsLoading(true)
setLoadingSpinnerDesc(`Loading SIGit history...`) setLoadingSpinnerDesc(`Loading SIGit history...`)
getUsersAppData() getUsersAppData(getNDKRelayList)
.then((appData) => { .then((appData) => {
if (appData) { if (appData) {
dispatch(updateUserAppData(appData)) dispatch(updateUserAppData(appData))

View File

@ -20,11 +20,7 @@ import { useLocation, useNavigate } from 'react-router-dom'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { LoadingSpinner } from '../../components/LoadingSpinner' import { LoadingSpinner } from '../../components/LoadingSpinner'
import { UserAvatar } from '../../components/UserAvatar' import { UserAvatar } from '../../components/UserAvatar'
import { import { NostrController, RelayController } from '../../controllers'
MetadataController,
NostrController,
RelayController
} from '../../controllers'
import { appPrivateRoutes } from '../../routes' import { appPrivateRoutes } from '../../routes'
import { import {
CreateSignatureEventContent, CreateSignatureEventContent,
@ -87,7 +83,7 @@ type FoundUser = Event & { npub: string }
export const CreatePage = () => { export const CreatePage = () => {
const navigate = useNavigate() const navigate = useNavigate()
const location = useLocation() const location = useLocation()
const { findMetadata } = useNDKContext() const { findMetadata, getNDKRelayList } = useNDKContext()
const { uploadedFiles } = location.state || {} const { uploadedFiles } = location.state || {}
const [currentFile, setCurrentFile] = useState<File>() const [currentFile, setCurrentFile] = useState<File>()
@ -160,18 +156,18 @@ export const CreatePage = () => {
setSearchUsersLoading(true) setSearchUsersLoading(true)
const relayController = RelayController.getInstance() const relayController = RelayController.getInstance()
const metadataController = MetadataController.getInstance()
const relaySet = await metadataController.findRelayListMetadata(usersPubkey)
const searchTerm = searchString.trim() const searchTerm = searchString.trim()
const ndkRelayList = await getNDKRelayList(usersPubkey)
relayController relayController
.fetchEvents( .fetchEvents(
{ {
kinds: [0], kinds: [0],
search: searchTerm search: searchTerm
}, },
[...relaySet.write] [...ndkRelayList.writeRelayUrls]
) )
.then((events) => { .then((events) => {
console.log('events', events) console.log('events', events)
@ -777,7 +773,9 @@ export const CreatePage = () => {
: viewers.map((viewer) => viewer.pubkey) : viewers.map((viewer) => viewer.pubkey)
).filter((receiver) => receiver !== usersPubkey) ).filter((receiver) => receiver !== usersPubkey)
return receivers.map((receiver) => sendNotification(receiver, meta)) return receivers.map((receiver) =>
sendNotification(receiver, meta, getNDKRelayList)
)
} }
const extractNostrId = (stringifiedEvent: string): string => { const extractNostrId = (stringifiedEvent: string): string => {

View File

@ -56,6 +56,7 @@ import {
import { ARRAY_BUFFER, DEFLATE } from '../../utils/const.ts' import { ARRAY_BUFFER, DEFLATE } from '../../utils/const.ts'
import { generateTimestamp } from '../../utils/opentimestamps.ts' import { generateTimestamp } from '../../utils/opentimestamps.ts'
import { MARK_TYPE_CONFIG } from '../../components/MarkTypeStrategy/MarkStrategy.tsx' import { MARK_TYPE_CONFIG } from '../../components/MarkTypeStrategy/MarkStrategy.tsx'
import { useNDKContext } from '../../hooks/useNDKContext.ts'
enum SignedStatus { enum SignedStatus {
Fully_Signed, Fully_Signed,
@ -67,6 +68,7 @@ export const SignPage = () => {
const navigate = useNavigate() const navigate = useNavigate()
const location = useLocation() const location = useLocation()
const params = useParams() const params = useParams()
const { getNDKRelayList } = useNDKContext()
const usersAppData = useAppSelector((state) => state.userAppData) const usersAppData = useAppSelector((state) => state.userAppData)
@ -781,7 +783,7 @@ export const SignPage = () => {
setLoadingSpinnerDesc('Sending notifications') setLoadingSpinnerDesc('Sending notifications')
const users = Array.from(userSet) const users = Array.from(userSet)
const promises = users.map((user) => const promises = users.map((user) =>
sendNotification(npubToHex(user)!, meta) sendNotification(npubToHex(user)!, meta, getNDKRelayList)
) )
await Promise.all(promises) await Promise.all(promises)
.then(() => { .then(() => {

View File

@ -29,7 +29,7 @@ import styles from './style.module.scss'
import { useLocation, useParams } from 'react-router-dom' import { useLocation, useParams } from 'react-router-dom'
import axios from 'axios' import axios from 'axios'
import { FONT_SIZE, FONT_TYPE, inPx } from '../../utils/pdf.ts' import { FONT_SIZE, FONT_TYPE, inPx } from '../../utils/pdf.ts'
import { useAppSelector } from '../../hooks' import { useAppSelector, useNDKContext } from '../../hooks'
import { getLastSignersSig } from '../../utils/sign.ts' import { getLastSignersSig } from '../../utils/sign.ts'
import { saveAs } from 'file-saver' import { saveAs } from 'file-saver'
import { Container } from '../../components/Container' import { Container } from '../../components/Container'
@ -166,6 +166,7 @@ const SlimPdfView = ({
export const VerifyPage = () => { export const VerifyPage = () => {
const location = useLocation() const location = useLocation()
const params = useParams() const params = useParams()
const { getNDKRelayList } = useNDKContext()
const usersAppData = useAppSelector((state) => state.userAppData) const usersAppData = useAppSelector((state) => state.userAppData)
const usersPubkey = useAppSelector((state) => state.auth.usersPubkey) const usersPubkey = useAppSelector((state) => state.auth.usersPubkey)
@ -364,7 +365,7 @@ export const VerifyPage = () => {
const users = Array.from(userSet) const users = Array.from(userSet)
const promises = users.map((user) => const promises = users.map((user) =>
sendNotification(npubToHex(user)!, updatedMeta) sendNotification(npubToHex(user)!, updatedMeta, getNDKRelayList)
) )
await Promise.all(promises) await Promise.all(promises)

View File

@ -18,11 +18,7 @@ import {
} from 'nostr-tools' } from 'nostr-tools'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { NIP05_REGEX } from '../constants' import { NIP05_REGEX } from '../constants'
import { import { NostrController, relayController } from '../controllers'
MetadataController,
NostrController,
relayController
} from '../controllers'
import { import {
updateProcessedGiftWraps, updateProcessedGiftWraps,
updateUserAppData as updateUserAppDataAction updateUserAppData as updateUserAppDataAction
@ -35,7 +31,7 @@ import { parseJson, removeLeadingSlash } from './string'
import { timeout } from './utils' import { timeout } from './utils'
import { getHash } from './hash' import { getHash } from './hash'
import { SIGIT_BLOSSOM } from './const.ts' import { SIGIT_BLOSSOM } from './const.ts'
import { NDKEvent } from '@nostr-dev-kit/ndk' import { Hexpubkey, NDKEvent, NDKRelayList } from '@nostr-dev-kit/ndk'
/** /**
* Generates a `d` tag for userAppData * Generates a `d` tag for userAppData
@ -334,7 +330,9 @@ export const createWrap = (unsignedEvent: UnsignedEvent, receiver: string) => {
* *
* @returns The user application data or null if an error occurs or no data is found. * @returns The user application data or null if an error occurs or no data is found.
*/ */
export const getUsersAppData = async (): Promise<UserAppData | null> => { export const getUsersAppData = async (
getNDKRelayList: (pubkey: Hexpubkey) => Promise<NDKRelayList>
): Promise<UserAppData | null> => {
// Initialize an array to hold relay URLs // Initialize an array to hold relay URLs
const relays: string[] = [] const relays: string[] = []
@ -344,27 +342,17 @@ export const getUsersAppData = async (): Promise<UserAppData | null> => {
// Check if relayMap is undefined in the Redux store // Check if relayMap is undefined in the Redux store
if (!relayMap) { if (!relayMap) {
// If relayMap is not present, fetch relay list metadata // If relayMap is not present, get relay list using NDKContext
const metadataController = MetadataController.getInstance()
const relaySet = await metadataController
.findRelayListMetadata(usersPubkey)
.catch((err) => {
// Log error and return null if fetching metadata fails
console.log(
`An error occurred while finding relay list metadata for ${hexToNpub(usersPubkey)}`,
err
)
return null
})
// Return null if metadata retrieval failed const ndkRelayList = await getNDKRelayList(usersPubkey)
if (!relaySet) return null
// Ensure that the relay list is not empty // Ensure that the relay list is not empty
if (relaySet.write.length === 0) return null if (ndkRelayList.writeRelayUrls.length === 0) return null
// Add write relays to the relays array // Add write relays to the relays array
relays.push(...relaySet.write) relays.push(...ndkRelayList.writeRelayUrls)
// // Ensure that the relay list is not empty
} else { } else {
// If relayMap exists, filter and add write relays from the stored map // If relayMap exists, filter and add write relays from the stored map
const writeRelays = Object.keys(relayMap).filter( const writeRelays = Object.keys(relayMap).filter(
@ -816,25 +804,14 @@ const getUserAppDataFromBlossom = async (url: string, privateKey: string) => {
* @param pubkey - The public key to subscribe to. * @param pubkey - The public key to subscribe to.
* @returns A promise that resolves when the subscription is successful. * @returns A promise that resolves when the subscription is successful.
*/ */
export const subscribeForSigits = async (pubkey: string) => { export const subscribeForSigits = async (
// Instantiate the MetadataController to retrieve relay list metadata pubkey: string,
const metadataController = MetadataController.getInstance() getNDKRelayList: (pubkey: Hexpubkey) => Promise<NDKRelayList>
const relaySet = await metadataController ) => {
.findRelayListMetadata(pubkey) const ndkRelayList = await getNDKRelayList(pubkey)
.catch((err) => {
// Log an error if retrieving relay list metadata fails
console.log(
`An error occurred while finding relay list metadata for ${hexToNpub(pubkey)}`,
err
)
return null
})
// Return if metadata retrieval failed
if (!relaySet) return
// Ensure relay list is not empty // Ensure relay list is not empty
if (relaySet.read.length === 0) return if (ndkRelayList.readRelayUrls.length === 0) return
// Define the filter for the subscription // Define the filter for the subscription
const filter: Filter = { const filter: Filter = {
@ -843,7 +820,9 @@ export const subscribeForSigits = async (pubkey: string) => {
} }
// Process the received event synchronously // Process the received event synchronously
const events = await relayController.fetchEvents(filter, relaySet.read) const events = await relayController.fetchEvents(filter, [
...ndkRelayList.readRelayUrls
])
for (const e of events) { for (const e of events) {
await processReceivedEvent(e) await processReceivedEvent(e)
} }
@ -908,7 +887,11 @@ const processReceivedEvent = async (event: Event, difficulty: number = 5) => {
* @param receiver - The recipient's public key. * @param receiver - The recipient's public key.
* @param meta - Metadata associated with the notification. * @param meta - Metadata associated with the notification.
*/ */
export const sendNotification = async (receiver: string, meta: Meta) => { export const sendNotification = async (
receiver: string,
meta: Meta,
getNDKRelayList: (pubkey: Hexpubkey) => Promise<NDKRelayList>
) => {
// Retrieve the user's public key from the state // Retrieve the user's public key from the state
const usersPubkey = store.getState().auth.usersPubkey! const usersPubkey = store.getState().auth.usersPubkey!
@ -924,28 +907,14 @@ export const sendNotification = async (receiver: string, meta: Meta) => {
// Wrap the unsigned event with the receiver's information // Wrap the unsigned event with the receiver's information
const wrappedEvent = createWrap(unsignedEvent, receiver) const wrappedEvent = createWrap(unsignedEvent, receiver)
// Instantiate the MetadataController to retrieve relay list metadata const ndkRelayList = await getNDKRelayList(receiver)
const metadataController = MetadataController.getInstance()
const relaySet = await metadataController
.findRelayListMetadata(receiver)
.catch((err) => {
// Log an error if retrieving relay list metadata fails
console.log(
`An error occurred while finding relay list metadata for ${hexToNpub(receiver)}`,
err
)
return null
})
// Return if metadata retrieval failed
if (!relaySet) return
// Ensure relay list is not empty // Ensure relay list is not empty
if (relaySet.read.length === 0) return if (ndkRelayList.readRelayUrls.length === 0) return
// Publish the notification event to the recipient's read relays // Publish the notification event to the recipient's read relays
await Promise.race([ await Promise.race([
relayController.publish(wrappedEvent, relaySet.read), relayController.publish(wrappedEvent, [...ndkRelayList.readRelayUrls]),
timeout(40 * 1000) timeout(40 * 1000)
]).catch((err) => { ]).catch((err) => {
// Log an error if publishing the notification event fails // Log an error if publishing the notification event fails