Releasing new design #161

Merged
b merged 241 commits from staging into main 2024-08-21 11:38:25 +00:00
5 changed files with 150 additions and 133 deletions
Showing only changes of commit 03cb6b1732 - Show all commits

View File

@ -1,11 +1,8 @@
import NDK, { NDKEvent, NDKSubscription } from '@nostr-dev-kit/ndk'
import { import {
Event, Event,
EventTemplate,
Filter, Filter,
VerifiedEvent, VerifiedEvent,
kinds, kinds,
nip19,
validateEvent, validateEvent,
verifyEvent verifyEvent
} from 'nostr-tools' } from 'nostr-tools'
@ -13,7 +10,7 @@ import { toast } from 'react-toastify'
import { EventEmitter } from 'tseep' import { EventEmitter } from 'tseep'
import { NostrController, relayController } from '.' import { NostrController, relayController } from '.'
import { localCache } from '../services' import { localCache } from '../services'
import { NostrJoiningBlock, ProfileMetadata, RelaySet } from '../types' import { ProfileMetadata, RelaySet } from '../types'
import { import {
findRelayListAndUpdateCache, findRelayListAndUpdateCache,
findRelayListInCache, findRelayListInCache,
@ -21,7 +18,6 @@ import {
getMostPopularRelays, getMostPopularRelays,
getUserRelaySet, getUserRelaySet,
isOlderThanOneWeek, isOlderThanOneWeek,
queryNip05,
unixNow unixNow
} from '../utils' } from '../utils'
@ -218,128 +214,6 @@ export class MetadataController extends EventEmitter {
}) })
} }
public getNostrJoiningBlockNumber = async (
hexKey: string
): Promise<NostrJoiningBlock | null> => {
const relaySet = await this.findRelayListMetadata(hexKey)
const userRelays: string[] = []
// find user's relays
if (relaySet.write.length > 0) {
userRelays.push(...relaySet.write)
} else {
const metadata = await this.findMetadata(hexKey)
if (!metadata) return null
const metadataContent = this.extractProfileMetadataContent(metadata)
if (metadataContent?.nip05) {
const nip05Profile = await queryNip05(metadataContent.nip05)
if (nip05Profile && nip05Profile.pubkey === hexKey) {
userRelays.push(...nip05Profile.relays)
}
}
}
if (userRelays.length === 0) return null
// filter for finding user's first kind 0 event
const eventFilter: Filter = {
kinds: [kinds.Metadata],
authors: [hexKey]
}
// find user's kind 0 event published on user's relays
const event = await relayController.fetchEvent(eventFilter, userRelays)
if (event) {
const { created_at } = event
// initialize job request
const jobEventTemplate: EventTemplate = {
content: '',
created_at: unixNow(),
kind: 68001,
tags: [
['i', `${created_at * 1000}`],
['j', 'blockChain-block-number']
]
}
// sign job request event
const jobSignedEvent =
await this.nostrController.signEvent(jobEventTemplate)
const relays = [
'wss://relay.damus.io',
'wss://relay.primal.net',
'wss://relayable.org'
]
await relayController.publish(jobSignedEvent, relays).catch((err) => {
console.error(
'Error occurred in publish blockChain-block-number DVM job',
err
)
})
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)
const encodedEventPointer = nip19.neventEncode({
id: event.id,
relays: userRelays,
author: event.pubkey,
kind: event.kind
})
return {
block: parseInt(dvmJobResult),
encodedEventPointer
}
}
return null
}
public validate = (event: Event) => validateEvent(event) && verifyEvent(event) public validate = (event: Event) => validateEvent(event) && verifyEvent(event)
public getEmptyMetadataEvent = (): Event => { public getEmptyMetadataEvent = (): Event => {

View File

@ -12,7 +12,12 @@ import { MetadataController } from '../../controllers'
import { getProfileSettingsRoute } from '../../routes' import { getProfileSettingsRoute } from '../../routes'
import { State } from '../../store/rootReducer' import { State } from '../../store/rootReducer'
import { NostrJoiningBlock, ProfileMetadata } from '../../types' import { NostrJoiningBlock, ProfileMetadata } from '../../types'
import { getRoboHashPicture, hexToNpub, shorten } from '../../utils' import {
getNostrJoiningBlockNumber,
getRoboHashPicture,
hexToNpub,
shorten
} from '../../utils'
import styles from './style.module.scss' import styles from './style.module.scss'
import { Container } from '../../components/Container' import { Container } from '../../components/Container'
@ -51,8 +56,7 @@ export const ProfilePage = () => {
useEffect(() => { useEffect(() => {
if (pubkey) { if (pubkey) {
metadataController getNostrJoiningBlockNumber(pubkey)
.getNostrJoiningBlockNumber(pubkey)
.then((res) => { .then((res) => {
setNostrJoiningBlock(res) setNostrJoiningBlock(res)
}) })

View File

@ -26,7 +26,11 @@ import { setMetadataEvent } from '../../../store/actions'
import { LoadingSpinner } from '../../../components/LoadingSpinner' import { LoadingSpinner } from '../../../components/LoadingSpinner'
import { LoginMethods } from '../../../store/auth/types' import { LoginMethods } from '../../../store/auth/types'
import { SmartToy } from '@mui/icons-material' import { SmartToy } from '@mui/icons-material'
import { getRoboHashPicture, unixNow } from '../../../utils' import {
getNostrJoiningBlockNumber,
getRoboHashPicture,
unixNow
} from '../../../utils'
import { Container } from '../../../components/Container' import { Container } from '../../../components/Container'
export const ProfileSettingsPage = () => { export const ProfileSettingsPage = () => {
@ -71,8 +75,7 @@ export const ProfileSettingsPage = () => {
useEffect(() => { useEffect(() => {
if (pubkey) { if (pubkey) {
metadataController getNostrJoiningBlockNumber(pubkey)
.getNostrJoiningBlockNumber(pubkey)
.then((res) => { .then((res) => {
setNostrJoiningBlock(res) setNostrJoiningBlock(res)
}) })

135
src/utils/dvm.ts Normal file
View File

@ -0,0 +1,135 @@
import { EventTemplate, Filter, kinds, nip19 } from 'nostr-tools'
import { queryNip05, unixNow } from '.'
import {
MetadataController,
NostrController,
relayController
} from '../controllers'
import { NostrJoiningBlock } from '../types'
import NDK, { NDKEvent, NDKSubscription } from '@nostr-dev-kit/ndk'
export const getNostrJoiningBlockNumber = async (
hexKey: string
): Promise<NostrJoiningBlock | null> => {
const metadataController = new MetadataController()
const relaySet = await metadataController.findRelayListMetadata(hexKey)
const userRelays: string[] = []
// find user's relays
if (relaySet.write.length > 0) {
userRelays.push(...relaySet.write)
} else {
const metadata = await metadataController.findMetadata(hexKey)
if (!metadata) return null
const metadataContent =
metadataController.extractProfileMetadataContent(metadata)
if (metadataContent?.nip05) {
const nip05Profile = await queryNip05(metadataContent.nip05)
if (nip05Profile && nip05Profile.pubkey === hexKey) {
userRelays.push(...nip05Profile.relays)
}
}
}
if (userRelays.length === 0) return null
// filter for finding user's first kind 0 event
const eventFilter: Filter = {
kinds: [kinds.Metadata],
authors: [hexKey]
}
// find user's kind 0 event published on user's relays
const event = await relayController.fetchEvent(eventFilter, userRelays)
if (event) {
const { created_at } = event
// initialize job request
const jobEventTemplate: EventTemplate = {
content: '',
created_at: unixNow(),
kind: 68001,
tags: [
['i', `${created_at * 1000}`],
['j', 'blockChain-block-number']
]
}
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'
]
await relayController.publish(jobSignedEvent, relays).catch((err) => {
console.error(
'Error occurred in publish blockChain-block-number DVM job',
err
)
})
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)
const encodedEventPointer = nip19.neventEncode({
id: event.id,
relays: userRelays,
author: event.pubkey,
kind: event.kind
})
return {
block: parseInt(dvmJobResult),
encodedEventPointer
}
}
return null
}

View File

@ -1,4 +1,5 @@
export * from './crypto' export * from './crypto'
export * from './dvm'
export * from './hash' export * from './hash'
export * from './localStorage' export * from './localStorage'
export * from './mark' export * from './mark'