74 lines
1.7 KiB
TypeScript
74 lines
1.7 KiB
TypeScript
import { backoff } from "./time";
|
|
|
|
export class InvalidateSync {
|
|
private _invalidated = false;
|
|
private _invalidatedDouble = false;
|
|
private _stopped = false;
|
|
private _command: () => Promise<void>;
|
|
private _pendings: (() => void)[] = [];
|
|
|
|
constructor(command: () => Promise<void>) {
|
|
this._command = command;
|
|
}
|
|
|
|
invalidate() {
|
|
if (this._stopped) {
|
|
return;
|
|
}
|
|
if (!this._invalidated) {
|
|
this._invalidated = true;
|
|
this._invalidatedDouble = false;
|
|
this._doSync();
|
|
} else {
|
|
if (!this._invalidatedDouble) {
|
|
this._invalidatedDouble = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
async invalidateAndAwait() {
|
|
if (this._stopped) {
|
|
return;
|
|
}
|
|
await new Promise<void>(resolve => {
|
|
this._pendings.push(resolve);
|
|
this.invalidate();
|
|
});
|
|
}
|
|
|
|
stop() {
|
|
if (this._stopped) {
|
|
return;
|
|
}
|
|
this._notifyPendings();
|
|
this._stopped = true;
|
|
}
|
|
|
|
private _notifyPendings = () => {
|
|
for (let pending of this._pendings) {
|
|
pending();
|
|
}
|
|
this._pendings = [];
|
|
}
|
|
|
|
|
|
private _doSync = async () => {
|
|
await backoff(async () => {
|
|
if (this._stopped) {
|
|
return;
|
|
}
|
|
await this._command();
|
|
});
|
|
if (this._stopped) {
|
|
this._notifyPendings();
|
|
return;
|
|
}
|
|
if (this._invalidatedDouble) {
|
|
this._invalidatedDouble = false;
|
|
this._doSync();
|
|
} else {
|
|
this._invalidated = false;
|
|
this._notifyPendings();
|
|
}
|
|
}
|
|
} |