Cache all the things
This commit is contained in:
@ -4,7 +4,7 @@ import { unwrap, sanitizeRelayUrl, ExternalStore, FeedCache } from "@snort/share
|
||||
import { NostrEvent, TaggedNostrEvent } from "./nostr";
|
||||
import { AuthHandler, Connection, RelaySettings, ConnectionStateSnapshot } from "./connection";
|
||||
import { Query } from "./query";
|
||||
import { NoteStore } from "./note-collection";
|
||||
import { NoteCollection, NoteStore, NoteStoreHook, NoteStoreSnapshotData } from "./note-collection";
|
||||
import { BuiltRawReqFilter, RequestBuilder } from "./request-builder";
|
||||
import { RelayMetricHandler } from "./relay-metric-handler";
|
||||
import {
|
||||
@ -19,6 +19,7 @@ import {
|
||||
db,
|
||||
UsersRelays,
|
||||
} from ".";
|
||||
import { EventsCache } from "./cache/events";
|
||||
|
||||
/**
|
||||
* Manages nostr content retrieval system
|
||||
@ -66,22 +67,30 @@ export class NostrSystem extends ExternalStore<SystemSnapshot> implements System
|
||||
*/
|
||||
#relayMetrics: RelayMetricHandler;
|
||||
|
||||
/**
|
||||
* General events cache
|
||||
*/
|
||||
#eventsCache: FeedCache<NostrEvent>;
|
||||
|
||||
constructor(props: {
|
||||
authHandler?: AuthHandler;
|
||||
relayCache?: FeedCache<UsersRelays>;
|
||||
profileCache?: FeedCache<MetadataCache>;
|
||||
relayMetrics?: FeedCache<RelayMetrics>;
|
||||
eventsCache?: FeedCache<NostrEvent>;
|
||||
}) {
|
||||
super();
|
||||
this.#handleAuth = props.authHandler;
|
||||
this.#relayCache = props.relayCache ?? new UserRelaysCache();
|
||||
this.#profileCache = props.profileCache ?? new UserProfileCache();
|
||||
this.#relayMetricsCache = props.relayMetrics ?? new RelayMetricCache();
|
||||
this.#eventsCache = props.eventsCache ?? new EventsCache();
|
||||
|
||||
this.#profileLoader = new ProfileLoaderService(this, this.#profileCache);
|
||||
this.#relayMetrics = new RelayMetricHandler(this.#relayMetricsCache);
|
||||
this.#cleanup();
|
||||
}
|
||||
HandleAuth?: AuthHandler | undefined;
|
||||
|
||||
/**
|
||||
* Profile loader service allows you to request profiles
|
||||
@ -99,7 +108,12 @@ export class NostrSystem extends ExternalStore<SystemSnapshot> implements System
|
||||
*/
|
||||
async Init() {
|
||||
db.ready = await db.isAvailable();
|
||||
const t = [this.#relayCache.preload(), this.#profileCache.preload(), this.#relayMetricsCache.preload()];
|
||||
const t = [
|
||||
this.#relayCache.preload(),
|
||||
this.#profileCache.preload(),
|
||||
this.#relayMetricsCache.preload(),
|
||||
this.#eventsCache.preload()
|
||||
];
|
||||
await Promise.all(t);
|
||||
}
|
||||
|
||||
@ -190,6 +204,33 @@ export class NostrSystem extends ExternalStore<SystemSnapshot> implements System
|
||||
return this.Queries.get(id);
|
||||
}
|
||||
|
||||
Fetch(req: RequestBuilder, cb?: (evs: Array<TaggedNostrEvent>) => void) {
|
||||
const q = this.Query(NoteCollection, req);
|
||||
return new Promise<NoteStoreSnapshotData>((resolve) => {
|
||||
let t: ReturnType<typeof setTimeout> | undefined;
|
||||
let tBuf: Array<TaggedNostrEvent> = [];
|
||||
const releaseOnEvent = cb ? q.feed.onEvent(evs => {
|
||||
if(!t) {
|
||||
tBuf = [...evs];
|
||||
t = setTimeout(() => {
|
||||
t = undefined;
|
||||
cb(tBuf);
|
||||
}, 100);
|
||||
} else {
|
||||
tBuf.push(...evs);
|
||||
}
|
||||
}) : undefined;
|
||||
const releaseFeedHook = q.feed.hook(() => {
|
||||
if(q.progress === 1) {
|
||||
releaseOnEvent?.();
|
||||
releaseFeedHook();
|
||||
q.cancel();
|
||||
resolve(unwrap(q.feed.snapshot.data));
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Query<T extends NoteStore>(type: { new (): T }, req: RequestBuilder): Query {
|
||||
const existing = this.Queries.get(req.id);
|
||||
if (existing) {
|
||||
@ -214,6 +255,11 @@ export class NostrSystem extends ExternalStore<SystemSnapshot> implements System
|
||||
|
||||
const filters = req.build(this.#relayCache);
|
||||
const q = new Query(req.id, req.instance, store, req.options?.leaveOpen);
|
||||
if(filters.some(a => a.filters.some(b=>b.ids))) {
|
||||
q.feed.onEvent(async evs => {
|
||||
await this.#eventsCache.bulkSet(evs);
|
||||
});
|
||||
}
|
||||
this.Queries.set(req.id, q);
|
||||
for (const subQ of filters) {
|
||||
this.SendQuery(q, subQ);
|
||||
@ -224,6 +270,24 @@ export class NostrSystem extends ExternalStore<SystemSnapshot> implements System
|
||||
}
|
||||
|
||||
async SendQuery(q: Query, qSend: BuiltRawReqFilter) {
|
||||
// trim query of cached ids
|
||||
for(const f of qSend.filters) {
|
||||
if (f.ids) {
|
||||
const cacheResults = await this.#eventsCache.bulkGet(f.ids);
|
||||
if(cacheResults.length > 0) {
|
||||
const resultIds = new Set(cacheResults.map(a => a.id));
|
||||
f.ids = f.ids.filter(a => !resultIds.has(a));
|
||||
q.feed.add(cacheResults as Array<TaggedNostrEvent>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for empty filters
|
||||
qSend.filters = qSend.filters.filter(a => Object.values(a).filter(v => Array.isArray(v)).every(b => (b as Array<string | number>).length > 0));
|
||||
if(qSend.filters.length === 0) {
|
||||
return;
|
||||
|
||||
}
|
||||
if (qSend.relay) {
|
||||
this.#log("Sending query to %s %O", qSend.relay, qSend);
|
||||
const s = this.#sockets.get(qSend.relay);
|
||||
|
Reference in New Issue
Block a user