// Intended to be used with message lists import { stringify } from "querystring"; import { AutoVerifier } from "./auto-verifier"; import { Changes, WithEquals } from "./data-types"; export interface PartialListQuery { channelId: string; messageId: string | null; number: number; } export class AutoVerifierWithArg { private tokenAutoVerifiers = new Map>(); private tokenQueries = new Map(); // TODO: Clear out old autoverifiers that haven't been used for a while. constructor( private tokenizer: (query: K) => string, // must be one-to-one mapping private primaryFunc: (query: K) => Promise, private trustedFunc: (query: K) => Promise, private verifyFunc: (query: K, primaryResult: T | null, trustedResult: T | null) => Promise ) {} static createPartialListAutoVerifier & { id: string }>( primaryFunc: (query: PartialListQuery) => Promise, trustedFunc: (query: PartialListQuery) => Promise, changesFunc: (query: PartialListQuery, changes: Changes) => Promise ) { return new AutoVerifierWithArg( query => `ch#${query.channelId} m#${query.messageId}->${query.number}`, query => primaryFunc(query), query => trustedFunc(query), async (query: PartialListQuery, primaryResult: T[] | null, trustedResult: T[] | null) => { await changesFunc(query, AutoVerifier.getChanges(primaryResult, trustedResult)); } ); } unverifyAll(): void { for (let autoVerifier of this.tokenAutoVerifiers.values()) { autoVerifier.unverify(); } this.tokenAutoVerifiers.clear(); this.tokenQueries.clear(); } unverifySome(toUnverifyFilter: (query: K) => boolean) { let tokensToUnverify = Array.from(this.tokenQueries.values()) .filter(toUnverifyFilter) .map(query => this.tokenizer(query)); for (let token of tokensToUnverify) { this.tokenAutoVerifiers.get(token)?.unverify(); this.tokenAutoVerifiers.delete(token); this.tokenQueries.delete(token); } } async fetchAndVerifyIfNeded(query: K): Promise { let token = this.tokenizer(query); this.tokenQueries.set(token, query); let autoVerifier = this.tokenAutoVerifiers.get(token); if (!autoVerifier) { autoVerifier = new AutoVerifier( async () => await this.primaryFunc(query), async () => await this.trustedFunc(query), async (primaryResult: T | null, trustedResult: T | null) => await this.verifyFunc(query, primaryResult, trustedResult), ); this.tokenAutoVerifiers.set(token, autoVerifier); } return await autoVerifier.fetchAndVerifyIfNeeded(); } }