Improve DVM feeds
This commit is contained in:
Generated
+8
-8
@@ -3061,10 +3061,10 @@
|
|||||||
},
|
},
|
||||||
"packages/feeds": {
|
"packages/feeds": {
|
||||||
"name": "@welshman/feeds",
|
"name": "@welshman/feeds",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@welshman/util": "0.0.1"
|
"@welshman/util": "0.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"gts": "^5.0.1",
|
"gts": "^5.0.1",
|
||||||
@@ -3074,7 +3074,7 @@
|
|||||||
},
|
},
|
||||||
"packages/lib": {
|
"packages/lib": {
|
||||||
"name": "@welshman/lib",
|
"name": "@welshman/lib",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@scure/base": "^1.1.6",
|
"@scure/base": "^1.1.6",
|
||||||
@@ -3098,11 +3098,11 @@
|
|||||||
},
|
},
|
||||||
"packages/net": {
|
"packages/net": {
|
||||||
"name": "@welshman/net",
|
"name": "@welshman/net",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@welshman/lib": "0.0.1",
|
"@welshman/lib": "0.0.2",
|
||||||
"@welshman/util": "0.0.1",
|
"@welshman/util": "0.0.2",
|
||||||
"isomorphic-ws": "^5.0.0",
|
"isomorphic-ws": "^5.0.0",
|
||||||
"ws": "^8.16.0"
|
"ws": "^8.16.0"
|
||||||
},
|
},
|
||||||
@@ -3115,10 +3115,10 @@
|
|||||||
},
|
},
|
||||||
"packages/util": {
|
"packages/util": {
|
||||||
"name": "@welshman/util",
|
"name": "@welshman/util",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@welshman/lib": "0.0.1",
|
"@welshman/lib": "0.0.2",
|
||||||
"nostr-tools": "^2.3.2"
|
"nostr-tools": "^2.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {uniq, now, isNil} from '@welshman/lib'
|
import {uniq, tryCatch, now, isNil} from '@welshman/lib'
|
||||||
import type {Rumor, Filter} from '@welshman/util'
|
import type {Rumor, Filter} from '@welshman/util'
|
||||||
import {Tags, getIdFilters, mergeFilters} from '@welshman/util'
|
import {Tags, getIdFilters, mergeFilters} from '@welshman/util'
|
||||||
import type {RequestItem, DVMItem, Scope, Feed, DynamicFilter, FeedOptions} from './core'
|
import type {RequestItem, DVMItem, Scope, Feed, DynamicFilter, FeedOptions} from './core'
|
||||||
@@ -82,9 +82,10 @@ export class FeedCompiler<E extends Rumor> {
|
|||||||
await this.options.request({
|
await this.options.request({
|
||||||
relays: [],
|
relays: [],
|
||||||
filters: getIdFilters(addresses),
|
filters: getIdFilters(addresses),
|
||||||
onEvent: events.push,
|
onEvent: (e: E) => events.push(e),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
relays: [],
|
relays: [],
|
||||||
filters: this._getFiltersFromTags(Tags.fromEvents(events)),
|
filters: this._getFiltersFromTags(Tags.fromEvents(events)),
|
||||||
@@ -92,21 +93,27 @@ export class FeedCompiler<E extends Rumor> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _compileDvms(requests: DVMItem[]): Promise<RequestItem> {
|
async _compileDvms(requests: DVMItem[]): Promise<RequestItem> {
|
||||||
const events: E[] = []
|
const responseTags: Tags[] = []
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
requests.map(request =>
|
requests.map(request =>
|
||||||
this.options.requestDvm({
|
this.options.requestDvm({
|
||||||
tags: [],
|
|
||||||
...request,
|
...request,
|
||||||
onEvent: events.push,
|
onEvent: async (e: E) => {
|
||||||
|
const tags = Tags.fromEvent(e)
|
||||||
|
const {id, pubkey} = await tryCatch(() => JSON.parse(tags.get("request")?.value())) || {}
|
||||||
|
|
||||||
|
responseTags.push(tags.filterByKey(["t", "p", "e", "a"]).rejectByValue([id, pubkey]))
|
||||||
|
},
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const mergedTags = Tags.from(responseTags.flatMap(tags => tags.valueOf()))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
relays: [],
|
relays: mergedTags.relays().valueOf(),
|
||||||
filters: this._getFiltersFromTags(Tags.fromEvents(events)),
|
filters: this._getFiltersFromTags(mergedTags),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,6 +167,11 @@ export class FeedCompiler<E extends Rumor> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we don't have any filters, return nothing instead of everything
|
||||||
|
if (filters.length === 0) {
|
||||||
|
filters.push({authors: []})
|
||||||
|
}
|
||||||
|
|
||||||
return filters
|
return filters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ export type RequestOpts<E> = RequestItem & {
|
|||||||
export type DVMItem = {
|
export type DVMItem = {
|
||||||
kind: number
|
kind: number
|
||||||
tags?: string[][]
|
tags?: string[][]
|
||||||
|
relays?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DVMOpts<E> = DVMItem & {
|
export type DVMOpts<E> = DVMItem & {
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ export class FeedLoader<E extends Rumor> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _getRequestLoader({relays, filters}: RequestItem, {onEvent, onExhausted}: LoadOpts<E>) {
|
async _getRequestLoader({relays, filters}: RequestItem, {onEvent, onExhausted}: LoadOpts<E>) {
|
||||||
|
// Make sure we have some kind of filter to send if we've been given an empty one, as happens with relay feeds
|
||||||
|
if (filters.length === 0) {
|
||||||
|
filters = [{}]
|
||||||
|
}
|
||||||
|
|
||||||
const untils = filters.flatMap((filter: Filter) => filter.until ? [filter.until] : [])
|
const untils = filters.flatMap((filter: Filter) => filter.until ? [filter.until] : [])
|
||||||
const sinces = filters.flatMap((filter: Filter) => filter.since ? [filter.since] : [])
|
const sinces = filters.flatMap((filter: Filter) => filter.since ? [filter.since] : [])
|
||||||
const maxUntil = untils.length === filters.length ? max(untils) : now()
|
const maxUntil = untils.length === filters.length ? max(untils) : now()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@welshman/feeds",
|
"name": "@welshman/feeds",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"author": "hodlbod",
|
"author": "hodlbod",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"description": "Utilities for building dynamic nostr feeds.",
|
"description": "Utilities for building dynamic nostr feeds.",
|
||||||
@@ -31,6 +31,6 @@
|
|||||||
"typescript": "~5.1.6"
|
"typescript": "~5.1.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@welshman/util": "0.0.1"
|
"@welshman/util": "0.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,24 @@ export const randomId = (): string => Math.random().toString().slice(2)
|
|||||||
|
|
||||||
export const stripProtocol = (url: string) => url.replace(/.*:\/\//, "")
|
export const stripProtocol = (url: string) => url.replace(/.*:\/\//, "")
|
||||||
|
|
||||||
|
export const sleep = (t: number) => new Promise(resolve => setTimeout(resolve, t))
|
||||||
|
|
||||||
|
export const concat = <T>(...xs: (T | Nil)[][]) => xs.flatMap(x => x || [])
|
||||||
|
|
||||||
|
export const append = <T>(xs: (T | Nil)[], x: T) => concat(xs, [x])
|
||||||
|
|
||||||
|
export const clamp = ([min, max]: [number, number], n: number) => Math.min(max, Math.max(min, n))
|
||||||
|
|
||||||
|
export const tryCatch = async <T>(f: () => Promise<T | void> | T | void, onError?: (e: Error) => void): Promise<T | void> => {
|
||||||
|
try {
|
||||||
|
return await f()
|
||||||
|
} catch (e) {
|
||||||
|
onError?.(e as Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
// Curried utils
|
// Curried utils
|
||||||
|
|
||||||
export const nth = (i: number) => <T>(xs: T[], ...args: unknown[]) => xs[i]
|
export const nth = (i: number) => <T>(xs: T[], ...args: unknown[]) => xs[i]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@welshman/lib",
|
"name": "@welshman/lib",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"author": "hodlbod",
|
"author": "hodlbod",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"description": "A collection of utilities.",
|
"description": "A collection of utilities.",
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export type SubscribeRequest = {
|
|||||||
relays: string[]
|
relays: string[]
|
||||||
filters: Filter[]
|
filters: Filter[]
|
||||||
timeout?: number
|
timeout?: number
|
||||||
|
tracker?: Tracker
|
||||||
immediate?: boolean
|
immediate?: boolean
|
||||||
closeOnEose?: boolean
|
closeOnEose?: boolean
|
||||||
}
|
}
|
||||||
@@ -53,8 +54,8 @@ export type Subscription = {
|
|||||||
export const makeSubscription = (request: SubscribeRequest) => {
|
export const makeSubscription = (request: SubscribeRequest) => {
|
||||||
const id = randomId()
|
const id = randomId()
|
||||||
const emitter = new Emitter()
|
const emitter = new Emitter()
|
||||||
const tracker = new Tracker()
|
|
||||||
const result = defer<Event[]>()
|
const result = defer<Event[]>()
|
||||||
|
const tracker = request.tracker || new Tracker()
|
||||||
const close = () => emitter.emit('abort')
|
const close = () => emitter.emit('abort')
|
||||||
|
|
||||||
emitter.setMaxListeners(100)
|
emitter.setMaxListeners(100)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@welshman/net",
|
"name": "@welshman/net",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"author": "hodlbod",
|
"author": "hodlbod",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"description": "Utilities for connecting with nostr relays.",
|
"description": "Utilities for connecting with nostr relays.",
|
||||||
@@ -32,8 +32,8 @@
|
|||||||
"typescript": "~5.1.6"
|
"typescript": "~5.1.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@welshman/lib": "0.0.1",
|
"@welshman/lib": "0.0.2",
|
||||||
"@welshman/util": "0.0.1",
|
"@welshman/util": "0.0.2",
|
||||||
"isomorphic-ws": "^5.0.0",
|
"isomorphic-ws": "^5.0.0",
|
||||||
"ws": "^8.16.0"
|
"ws": "^8.16.0"
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-4
@@ -1,4 +1,4 @@
|
|||||||
import {Emitter, uniq, omit, now, range, identity} from '@welshman/lib'
|
import {Emitter, chunk, sleep, uniq, omit, now, range, identity} from '@welshman/lib'
|
||||||
import {matchFilters, matchFilter} from './Filters'
|
import {matchFilters, matchFilter} from './Filters'
|
||||||
import {encodeAddress, addressFromEvent} from './Address'
|
import {encodeAddress, addressFromEvent} from './Address'
|
||||||
import {isReplaceable} from './Events'
|
import {isReplaceable} from './Events'
|
||||||
@@ -24,9 +24,15 @@ export class Relay<E extends Rumor> extends Emitter {
|
|||||||
return Array.from(this.eventsById.values())
|
return Array.from(this.eventsById.values())
|
||||||
}
|
}
|
||||||
|
|
||||||
load(events: E[]) {
|
async load(events: E[], chunkSize = 1000) {
|
||||||
for (const event of events) {
|
for (const eventsChunk of chunk(chunkSize, events)) {
|
||||||
this._addEvent(event)
|
for (const event of eventsChunk) {
|
||||||
|
this._addEvent(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventsChunk.length === chunkSize) {
|
||||||
|
await sleep(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@welshman/util",
|
"name": "@welshman/util",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"author": "hodlbod",
|
"author": "hodlbod",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"description": "A collection of nostr-related utilities.",
|
"description": "A collection of nostr-related utilities.",
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
"typescript": "~5.1.6"
|
"typescript": "~5.1.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@welshman/lib": "0.0.1",
|
"@welshman/lib": "0.0.2",
|
||||||
"nostr-tools": "^2.3.2"
|
"nostr-tools": "^2.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user