cordis/client/webapp/auto-verifier-with-args.ts
2021-12-04 06:02:11 -06:00

109 lines
4.4 KiB
TypeScript

import * as electronRemote from '@electron/remote';
const electronConsole = electronRemote.getGlobal('console') as Console;
import Logger from '../../logger/logger';
const LOG = Logger.create(__filename, electronConsole);
import { AutoVerifier, AutoVerifierChangesType } from "./auto-verifier";
import { Changes, WithEquals } from "./data-types";
import Q from './q-module';
export interface PartialMessageListQuery {
channelId: string;
messageId: string | null;
number: number;
}
export interface IDQuery {
id: string;
}
export class AutoVerifierWithArg<T, K> {
private tokenAutoVerifiers = new Map<string, AutoVerifier<T>>();
private tokenQueries = new Map<string, K>();
// 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<T | null>,
private trustedFunc: (query: K) => Promise<T | null>,
private verifyFunc: (query: K, primaryResult: T | null, trustedResult: T | null) => Promise<void>
) {}
static createStandardPartialMessageListAutoVerifier<T extends WithEquals<T> & { id: string }>(
primaryFunc: (query: PartialMessageListQuery) => Promise<T[] | null>,
trustedFunc: (query: PartialMessageListQuery) => Promise<T[] | null>,
changesFunc: (query: PartialMessageListQuery, changesType: AutoVerifierChangesType, changes: Changes<T>) => Promise<void>
) {
return new AutoVerifierWithArg<T[], PartialMessageListQuery>(
query => `ch#${query.channelId} m#${query.messageId}->${query.number}`,
query => primaryFunc(query),
query => trustedFunc(query),
async (query: PartialMessageListQuery, primaryResult: T[] | null, trustedResult: T[] | null) => {
// LOG.debug('messages verify: ', {
// query,
// // primaryResult: primaryResult?.map((e: any) => e.sent).sort(),
// // trustedResult: trustedResult?.map((e: any) => e.sent).sort(),
// zipped: primaryResult && trustedResult && primaryResult.length === trustedResult.length && Q.zip(
// primaryResult?.sort((a: any, b: any) => a.sent.getTime() - b.sent.getTime()).map((e: any) => e.text),
// trustedResult?.sort((a: any, b: any) => a.sent.getTime() - b.sent.getTime()).map((e: any) => e.text)
// )
// });
let changes = AutoVerifier.getChanges<T>(primaryResult, trustedResult);
//LOG.debug('changes:', { changes });
let changesType = AutoVerifier.getListChangesType<T>(primaryResult, trustedResult, changes);
await changesFunc(query, changesType, changes);
}
);
}
static createStandardIDQueriedSingleAutoVerifier<T extends WithEquals<T> & { id: string }>(
primaryFunc: (query: IDQuery) => Promise<T | null>,
trustedFunc: (query: IDQuery) => Promise<T | null>,
changesFunc: (query: IDQuery, changesType: AutoVerifierChangesType, primaryResult: T | null, trustedResult: T | null) => Promise<void>
) {
return new AutoVerifierWithArg<T, IDQuery>(
query => `id#${query.id}`,
query => primaryFunc(query),
query => trustedFunc(query),
async (query: IDQuery, primaryResult: T | null, trustedResult: T | null) => {
let changesType = AutoVerifier.getSingleChangesType<T>(primaryResult, trustedResult);
await changesFunc(query, changesType, 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, lazyVerify: boolean = false): Promise<T | null> {
let token = this.tokenizer(query);
this.tokenQueries.set(token, query);
let autoVerifier = this.tokenAutoVerifiers.get(token);
if (!autoVerifier) {
autoVerifier = new AutoVerifier<T>(
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(lazyVerify);
}
}