refactor request builder to handle relay hints
This commit is contained in:
@ -1,10 +1,14 @@
|
||||
import { RawReqFilter, u256, HexKey, EventKind } from "@snort/nostr";
|
||||
import { appendDedupe } from "SnortUtils";
|
||||
import { appendDedupe, dedupe } from "SnortUtils";
|
||||
import { QueryBase } from "./Query";
|
||||
import { diffFilters } from "./RequestSplitter";
|
||||
import { RelayCache, splitByWriteRelays } from "./GossipModel";
|
||||
import { mergeSimilar } from "./RequestMerger";
|
||||
|
||||
/**
|
||||
* Which strategy is used when building REQ filters
|
||||
*/
|
||||
export enum NostrRequestStrategy {
|
||||
export enum RequestStrategy {
|
||||
/**
|
||||
* Use the users default relays to fetch events,
|
||||
* this is the fallback option when there is no better way to query a given filter set
|
||||
@ -26,10 +30,9 @@ export enum NostrRequestStrategy {
|
||||
* A built REQ filter ready for sending to System
|
||||
*/
|
||||
export interface BuiltRawReqFilter {
|
||||
id: string;
|
||||
filter: Array<RawReqFilter>;
|
||||
relays: Array<string>;
|
||||
strategy: NostrRequestStrategy;
|
||||
filter: RawReqFilter;
|
||||
relay: string;
|
||||
strategy: RequestStrategy;
|
||||
}
|
||||
|
||||
export interface RequestBuilderOptions {
|
||||
@ -76,8 +79,55 @@ export class RequestBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
build(): Array<RawReqFilter> {
|
||||
return this.#builders.map(a => a.filter);
|
||||
buildRaw(): Array<RawReqFilter> {
|
||||
return this.#builders.map(f => f.filter);
|
||||
}
|
||||
|
||||
build(relays: RelayCache): Array<BuiltRawReqFilter> {
|
||||
const expanded = this.#builders.map(a => a.build(relays)).flat();
|
||||
return this.#mergeSimilar(expanded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects a change in request from a previous set of filters
|
||||
* @param q All previous filters merged
|
||||
* @returns
|
||||
*/
|
||||
buildDiff(relays: RelayCache, q: QueryBase): Array<BuiltRawReqFilter> {
|
||||
const next = this.buildRaw();
|
||||
const diff = diffFilters(q.filters, next);
|
||||
if (diff.changed) {
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge a set of expanded filters into the smallest number of subscriptions by merging similar requests
|
||||
* @param expanded
|
||||
* @returns
|
||||
*/
|
||||
#mergeSimilar(expanded: Array<BuiltRawReqFilter>) {
|
||||
const relayMerged = expanded.reduce((acc, v) => {
|
||||
const existing = acc.get(v.relay);
|
||||
if (existing) {
|
||||
existing.push(v);
|
||||
} else {
|
||||
acc.set(v.relay, [v]);
|
||||
}
|
||||
return acc;
|
||||
}, new Map<string, Array<BuiltRawReqFilter>>());
|
||||
|
||||
const filtersSquashed = [...relayMerged.values()].flatMap(a => {
|
||||
return mergeSimilar(a.map(b => b.filter)).map(b => {
|
||||
return {
|
||||
filter: b,
|
||||
relay: a[0].relay,
|
||||
strategy: a[0].strategy,
|
||||
} as BuiltRawReqFilter;
|
||||
});
|
||||
});
|
||||
|
||||
return filtersSquashed;
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,7 +136,7 @@ export class RequestBuilder {
|
||||
*/
|
||||
export class RequestFilterBuilder {
|
||||
#filter: RawReqFilter = {};
|
||||
#relayHints: Map<u256, Array<string>> = new Map();
|
||||
#relayHints = new Map<u256, Array<string>>();
|
||||
|
||||
get filter() {
|
||||
return { ...this.#filter };
|
||||
@ -149,4 +199,44 @@ export class RequestFilterBuilder {
|
||||
this.#filter.search = keyword;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build/expand this filter into a set of relay specific queries
|
||||
*/
|
||||
build(relays: RelayCache): Array<BuiltRawReqFilter> {
|
||||
// when querying for specific event ids with relay hints
|
||||
// take the first approach which is to split the filter by relay
|
||||
if (this.#filter.ids && this.#relayHints.size > 0) {
|
||||
const relays = dedupe([...this.#relayHints.values()].flat());
|
||||
return relays.map(r => {
|
||||
return {
|
||||
filter: {
|
||||
...this.#filter,
|
||||
ids: [...this.#relayHints.entries()].filter(([, v]) => v.includes(r)).map(([k]) => k),
|
||||
},
|
||||
relay: r,
|
||||
strategy: RequestStrategy.RelayHintedEventIds,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// If any authors are set use the gossip model to fetch data for each author
|
||||
if (this.#filter.authors) {
|
||||
const split = splitByWriteRelays(relays, this.#filter);
|
||||
return split.map(a => {
|
||||
return {
|
||||
...a,
|
||||
strategy: RequestStrategy.AuthorsRelays,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
filter: this.filter,
|
||||
relay: "*",
|
||||
strategy: RequestStrategy.DefaultRelays,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user