feat: @snort/system CacheRelay

This commit is contained in:
2024-01-23 15:35:28 +00:00
parent d6c578fafc
commit 5cea096067
29 changed files with 296 additions and 380 deletions

View File

@ -5,27 +5,33 @@ import { appendDedupe, dedupe, sanitizeRelayUrl, unixNowMs, unwrap } from "@snor
import EventKind from "./event-kind";
import { NostrLink, NostrPrefix, SystemInterface } from ".";
import { ReqFilter, u256, HexKey } from "./nostr";
import { RelayCache, splitByWriteRelays, splitFlatByWriteRelays } from "./outbox-model";
import { AuthorsRelaysCache, splitByWriteRelays, splitFlatByWriteRelays } from "./outbox-model";
import { CacheRelay } from "cache-relay";
/**
* Which strategy is used when building REQ filters
*/
export enum RequestStrategy {
export const 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
*/
DefaultRelays = 1,
DefaultRelays = "default",
/**
* Using a cached copy of the authors relay lists NIP-65, split a given set of request filters by pubkey
*/
AuthorsRelays = 2,
AuthorsRelays = "authors-relays",
/**
* Use pre-determined relays for query
*/
ExplicitRelays = 3,
ExplicitRelays = "explicit-relays",
/**
* Query the cache relay
*/
CacheRelay = "cache-relay",
}
/**
@ -121,21 +127,24 @@ export class RequestBuilder {
return this.#builders.map(f => f.filter);
}
build(system: SystemInterface): Array<BuiltRawReqFilter> {
const expanded = this.#builders.flatMap(a => a.build(system.relayCache, this.#options));
async build(system: SystemInterface): Promise<Array<BuiltRawReqFilter>> {
const expanded = (
await Promise.all(this.#builders.map(a => a.build(system.relayCache, system.cacheRelay, this.#options)))
).flat();
return this.#groupByRelay(system, expanded);
}
/**
* Detects a change in request from a previous set of filters
*/
buildDiff(system: SystemInterface, prev: Array<ReqFilter>): Array<BuiltRawReqFilter> {
async buildDiff(system: SystemInterface, prev: Array<ReqFilter>): Promise<Array<BuiltRawReqFilter>> {
const start = unixNowMs();
const diff = system.optimizer.getDiff(prev, this.buildRaw());
const ts = unixNowMs() - start;
this.#log("buildDiff %s %d ms +%d", this.id, ts, diff.length);
if (diff.length > 0) {
// todo: fix
return splitFlatByWriteRelays(system.relayCache, diff).map(a => {
return {
strategy: RequestStrategy.AuthorsRelays,
@ -143,8 +152,6 @@ export class RequestBuilder {
relay: a.relay,
};
});
} else {
this.#log(`Wasted ${ts} ms detecting no changes!`);
}
return [];
}
@ -284,12 +291,48 @@ export class RequestFilterBuilder {
/**
* Build/expand this filter into a set of relay specific queries
*/
build(relays: RelayCache, options?: RequestBuilderOptions): Array<BuiltRawReqFilter> {
async build(
relays: AuthorsRelaysCache,
cacheRelay?: CacheRelay,
options?: RequestBuilderOptions,
): Promise<Array<BuiltRawReqFilter>> {
// if since/until are set ignore sync split, cache relay wont be used
if (cacheRelay && this.#filter.since === undefined && this.#filter.until === undefined) {
const latest = await cacheRelay.query([
"REQ",
uuid(),
{
...this.#filter,
since: undefined,
until: undefined,
limit: 1,
},
]);
if (latest.length === 1) {
return [
...this.#buildFromFilter(relays, {
...this.#filter,
since: latest[0].created_at,
until: undefined,
limit: undefined,
}),
{
filters: [this.#filter],
relay: "==CACHE==",
strategy: RequestStrategy.CacheRelay,
},
];
}
}
return this.#buildFromFilter(relays, this.#filter, options);
}
#buildFromFilter(relays: AuthorsRelaysCache, f: ReqFilter, options?: RequestBuilderOptions) {
// use the explicit relay list first
if (this.#relays.size > 0) {
return [...this.#relays].map(r => {
return {
filters: [this.#filter],
filters: [f],
relay: r,
strategy: RequestStrategy.ExplicitRelays,
};
@ -297,8 +340,8 @@ export class RequestFilterBuilder {
}
// 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, options?.outboxPickN);
if (f.authors) {
const split = splitByWriteRelays(relays, f, options?.outboxPickN);
return split.map(a => {
return {
filters: [a.filter],
@ -310,7 +353,7 @@ export class RequestFilterBuilder {
return [
{
filters: [this.#filter],
filters: [f],
relay: "",
strategy: RequestStrategy.DefaultRelays,
},