add assertion on trustedPromise !== null
This commit is contained in:
parent
cdc3307cb2
commit
5df8948886
@ -6,6 +6,7 @@ const LOG = Logger.create(__filename, electronConsole);
|
|||||||
import { Changes, WithEquals } from './data-types';
|
import { Changes, WithEquals } from './data-types';
|
||||||
|
|
||||||
import * as uuid from 'uuid';
|
import * as uuid from 'uuid';
|
||||||
|
import assert from 'assert';
|
||||||
|
|
||||||
export enum AutoVerifierChangesType {
|
export enum AutoVerifierChangesType {
|
||||||
NONE, // both primaryFunc and trustedFunc returned null
|
NONE, // both primaryFunc and trustedFunc returned null
|
||||||
@ -217,40 +218,23 @@ export class AutoVerifier<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tryResolveTrustedPromise = async () => {
|
const tryResolveTrustedPromise = async () => {
|
||||||
if (this.trustedPromise) {
|
assert(this.trustedPromise !== null)
|
||||||
// there is a trusted promise that we can check
|
|
||||||
|
|
||||||
if (this.trustedStatus === 'fetching') {
|
if (this.trustedStatus === 'fetching') {
|
||||||
// no one has started verifying the trusted yet
|
// no one has started verifying the trusted yet
|
||||||
|
|
||||||
this.trustedStatus = 'verifying';
|
this.trustedStatus = 'verifying';
|
||||||
|
|
||||||
// note: Promises that have already resolved will return the same value when awaited again :)
|
// note: Promises that have already resolved will return the same value when awaited again :)
|
||||||
const origTrustedPromise: Promise<T | null> | null = this.trustedPromise;
|
const origTrustedPromise: Promise<T | null> = this.trustedPromise;
|
||||||
let trustedResult = undefined;
|
let trustedResult = undefined;
|
||||||
try {
|
try {
|
||||||
trustedResult = await origTrustedPromise;
|
trustedResult = await origTrustedPromise;
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
if (this.trustedPromise === origTrustedPromise) {
|
if (this.trustedPromise === origTrustedPromise) {
|
||||||
throw e;
|
throw e;
|
||||||
} else {
|
} else {
|
||||||
console.warn('trusted promise rejected after unverify', e);
|
console.warn('trusted promise rejected after unverify', e);
|
||||||
if (this.trustedPromise === null) {
|
|
||||||
this.trustedStatus = 'fetching';
|
|
||||||
this.trustedPromise = this.trustedFunc();
|
|
||||||
}
|
|
||||||
await tryResolveTrustedPromise();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.trustedPromise !== origTrustedPromise) {
|
|
||||||
// we've been invalidated while we were waiting for the trusted result!
|
|
||||||
// TODO: This happens when a socket fetch is sent before the socket is connected to.
|
|
||||||
console.warn(
|
|
||||||
'RARE ALERT: we got unverified while trying to fetch a trusted promise for verification!',
|
|
||||||
new Error(),
|
|
||||||
);
|
|
||||||
if (this.trustedPromise === null) {
|
if (this.trustedPromise === null) {
|
||||||
this.trustedStatus = 'fetching';
|
this.trustedStatus = 'fetching';
|
||||||
this.trustedPromise = this.trustedFunc();
|
this.trustedPromise = this.trustedFunc();
|
||||||
@ -258,87 +242,96 @@ export class AutoVerifier<T> {
|
|||||||
await tryResolveTrustedPromise();
|
await tryResolveTrustedPromise();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// make sure to verify BEFORE potentially resolving
|
if (this.trustedPromise !== origTrustedPromise) {
|
||||||
// this way the conflicts can be resolved before the result is returned
|
// we've been invalidated while we were waiting for the trusted result!
|
||||||
this.verifyPromise = this.verifyFunc(primaryResult, trustedResult);
|
// TODO: This happens when a socket fetch is sent before the socket is connected to.
|
||||||
const primaryUpToDate = await this.verifyPromise;
|
console.warn(
|
||||||
|
'RARE ALERT: we got unverified while trying to fetch a trusted promise for verification!',
|
||||||
if (this.trustedPromise === origTrustedPromise) {
|
new Error(),
|
||||||
if (trustedResult !== null && primaryUpToDate) {
|
);
|
||||||
// we got a good trusted result and the primary data has been updated
|
if (this.trustedPromise === null) {
|
||||||
// to reflect the trusted data (or already reflects it).
|
this.trustedStatus = 'fetching';
|
||||||
this.trustedStatus = 'verified';
|
this.trustedPromise = this.trustedFunc();
|
||||||
} else {
|
|
||||||
// we have to re-fetch the trusted promise again next fetch
|
|
||||||
this.trustedStatus = 'none';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// this actually could be quite common
|
|
||||||
//console.warn('RARE ALERT: we got unverified during verification!');
|
|
||||||
// ** complexity:
|
|
||||||
// if primaryUpToDate is false or we got unverified during verification, this path will still return
|
|
||||||
// the trustedResult that was passed to the verify function
|
|
||||||
}
|
}
|
||||||
|
await tryResolveTrustedPromise();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!resolved) {
|
// make sure to verify BEFORE potentially resolving
|
||||||
// removed 01/09/2021 pretty sure should not be here... && trustedResult
|
// this way the conflicts can be resolved before the result is returned
|
||||||
resolve(trustedResult);
|
this.verifyPromise = this.verifyFunc(primaryResult, trustedResult);
|
||||||
resolved = true;
|
const primaryUpToDate = await this.verifyPromise;
|
||||||
|
|
||||||
|
if (this.trustedPromise === origTrustedPromise) {
|
||||||
|
if (trustedResult !== null && primaryUpToDate) {
|
||||||
|
// we got a good trusted result and the primary data has been updated
|
||||||
|
// to reflect the trusted data (or already reflects it).
|
||||||
|
this.trustedStatus = 'verified';
|
||||||
|
} else {
|
||||||
|
// we have to re-fetch the trusted promise again next fetch
|
||||||
|
this.trustedStatus = 'none';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// some code is already dealing with (or dealt with) verifying the trusted result
|
// this actually could be quite common
|
||||||
// await the same trusted promise and return its result if we didn't get a result
|
//console.warn('RARE ALERT: we got unverified during verification!');
|
||||||
// from the primary source.
|
// ** complexity:
|
||||||
|
// if primaryUpToDate is false or we got unverified during verification, this path will still return
|
||||||
|
// the trustedResult that was passed to the verify function
|
||||||
|
}
|
||||||
|
|
||||||
// note: Promises that have already resolved will return the same value when awaited again :)
|
if (!resolved) {
|
||||||
const origTrustedPromise: Promise<T | null> | null = this.trustedPromise;
|
// removed 01/09/2021 pretty sure should not be here... && trustedResult
|
||||||
let trustedResult = undefined;
|
resolve(trustedResult);
|
||||||
try {
|
resolved = true;
|
||||||
trustedResult = await origTrustedPromise;
|
}
|
||||||
} catch (e: unknown) {
|
} else {
|
||||||
if (this.trustedPromise === origTrustedPromise) {
|
// some code is already dealing with (or dealt with) verifying the trusted result
|
||||||
// TODO: decide if can unverify here rather than in the "catch-all"
|
// await the same trusted promise and return its result if we didn't get a result
|
||||||
// maybe this will let us get rid of the catch all?
|
// from the primary source.
|
||||||
throw e;
|
|
||||||
} else {
|
|
||||||
console.warn('trusted promise from another path rejected after unverify', e);
|
|
||||||
// TODO: only retry if there is another trusted promise available...
|
|
||||||
// OR always reject?
|
|
||||||
await tryResolveTrustedPromise();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.trustedPromise !== origTrustedPromise) {
|
// note: Promises that have already resolved will return the same value when awaited again :)
|
||||||
// we've been invalidated while we were waiting for the trusted result!
|
const origTrustedPromise: Promise<T | null> | null = this.trustedPromise;
|
||||||
console.warn(
|
let trustedResult = undefined;
|
||||||
'ULTRA RARE ALERT: we got unverified while awaiting a trusted promise another path was verifying!',
|
try {
|
||||||
);
|
trustedResult = await origTrustedPromise;
|
||||||
|
} catch (e: unknown) {
|
||||||
|
if (this.trustedPromise === origTrustedPromise) {
|
||||||
|
// TODO: decide if can unverify here rather than in the "catch-all"
|
||||||
|
// maybe this will let us get rid of the catch all?
|
||||||
|
throw e;
|
||||||
|
} else {
|
||||||
|
console.warn('trusted promise from another path rejected after unverify', e);
|
||||||
|
// TODO: only retry if there is another trusted promise available...
|
||||||
|
// OR always reject?
|
||||||
await tryResolveTrustedPromise();
|
await tryResolveTrustedPromise();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.verifyPromise; // we don't care about the result, just that we wait for the verification to finish
|
|
||||||
if (this.trustedPromise !== origTrustedPromise) {
|
|
||||||
// we've been invalidated while we were waiting for the verify!
|
|
||||||
console.warn(
|
|
||||||
'ULTRA RARE ALERT: we got unverified while awaiting a verify promise another path was calling!',
|
|
||||||
);
|
|
||||||
// ** complexity:
|
|
||||||
// if primaryUpToDate is false or we got unverified during verification, this path will still return
|
|
||||||
// the trustedResult that was passed to the verify function
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!resolved) {
|
|
||||||
resolve(trustedResult);
|
|
||||||
resolved = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// we are all up to date, make sure to resolve if primaryResult is null
|
if (this.trustedPromise !== origTrustedPromise) {
|
||||||
|
// we've been invalidated while we were waiting for the trusted result!
|
||||||
|
console.warn(
|
||||||
|
'ULTRA RARE ALERT: we got unverified while awaiting a trusted promise another path was verifying!',
|
||||||
|
);
|
||||||
|
await tryResolveTrustedPromise();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.verifyPromise; // we don't care about the result, just that we wait for the verification to finish
|
||||||
|
if (this.trustedPromise !== origTrustedPromise) {
|
||||||
|
// we've been invalidated while we were waiting for the verify!
|
||||||
|
console.warn(
|
||||||
|
'ULTRA RARE ALERT: we got unverified while awaiting a verify promise another path was calling!',
|
||||||
|
);
|
||||||
|
// ** complexity:
|
||||||
|
// if primaryUpToDate is false or we got unverified during verification, this path will still return
|
||||||
|
// the trustedResult that was passed to the verify function
|
||||||
|
}
|
||||||
|
|
||||||
if (!resolved) {
|
if (!resolved) {
|
||||||
resolve(null);
|
resolve(trustedResult);
|
||||||
resolved = true;
|
resolved = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user