Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ulixee
GitHub Repository: ulixee/secret-agent
Path: blob/main/commons/Timer.ts
1028 views
1
import TimeoutError from './interfaces/TimeoutError';
2
import Resolvable from './Resolvable';
3
4
export default class Timer {
5
public readonly [Symbol.toStringTag] = 'Timer';
6
public readonly timeout: NodeJS.Timer;
7
8
private readonly time = process.hrtime();
9
private timeoutMessage = 'Timeout waiting';
10
private readonly expirePromise = new Resolvable<void>();
11
12
constructor(readonly timeoutMillis: number, readonly registry?: IRegistry[]) {
13
// NOTE: A zero value will NOT timeout. This is to give users an ability to not timeout certain requests
14
this.timeout =
15
timeoutMillis > 0 ? setTimeout(this.expire.bind(this), timeoutMillis).unref() : null;
16
if (registry && this.timeout) {
17
registry.push({ reject: this.expirePromise.reject, timeout: this.timeout });
18
}
19
}
20
21
public setMessage(message: string): void {
22
this.timeoutMessage = message;
23
}
24
25
public clear(): void {
26
if (this.registry) {
27
const idx = this.registry.findIndex(x => x.timeout === this.timeout);
28
if (idx >= 0) this.registry.splice(idx, 1);
29
}
30
clearTimeout(this.timeout);
31
}
32
33
public throwIfExpired(message?: string): void {
34
if (this.isExpired()) {
35
this.clear();
36
throw new TimeoutError(message ?? this.timeoutMessage);
37
}
38
}
39
40
public isExpired(): boolean {
41
return this.elapsedMillis() >= this.timeoutMillis;
42
}
43
44
public isResolved(): boolean {
45
return this.expirePromise.isResolved;
46
}
47
48
public elapsedMillis(): number {
49
const time = process.hrtime(this.time);
50
return time[0] * 1000 + time[1] / 1000000;
51
}
52
53
public async waitForPromise<Z>(promise: Promise<Z>, message: string): Promise<Z> {
54
this.timeoutMessage = message;
55
const timeout = new TimeoutError(this.timeoutMessage);
56
const result = await Promise.race([promise, this.expirePromise.then(() => timeout)]);
57
if (result instanceof TimeoutError) throw timeout;
58
return result;
59
}
60
61
public waitForTimeout(): Promise<void> {
62
// wait for promise to expire
63
return this.expirePromise.promise;
64
}
65
66
private expire(): void {
67
this.expirePromise.resolve();
68
this.clear();
69
}
70
71
public static expireAll(registry: IRegistry[], error: Error): void {
72
// clear any pending timeouts
73
while (registry.length) {
74
const next = registry.shift();
75
if (next) {
76
const { timeout, reject } = next;
77
clearTimeout(timeout);
78
reject(error);
79
}
80
}
81
}
82
}
83
84
interface IRegistry {
85
timeout: NodeJS.Timer;
86
reject: (err: Error) => any;
87
}
88
89