/
Time.ts
113 lines (87 loc) · 3.18 KB
/
Time.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/**
* @license
* Copyright 2022-2024 Matter.js Authors
* SPDX-License-Identifier: Apache-2.0
*/
import { NoProviderError } from "../common/MatterError.js";
import { Diagnostic } from "../log/Diagnostic.js";
import { DiagnosticSource } from "../log/DiagnosticSource.js";
export type TimerCallback = () => any;
const registry = new Set<Timer>();
export abstract class Time {
static get: () => Time = () => DefaultTime;
abstract now(): Date;
static readonly now = (): Date => Time.get().now();
abstract nowMs(): number;
static readonly nowMs = (): number => Time.get().nowMs();
/** Returns a timer that will call callback after durationMs has passed. */
abstract getTimer(name: string, durationMs: number, callback: TimerCallback): Timer;
static readonly getTimer = (name: string, durationMs: number, callback: TimerCallback): Timer =>
Time.get().getTimer(name, durationMs, callback);
/** Returns a timer that will periodically call callback at intervalMs intervals. */
abstract getPeriodicTimer(name: string, intervalMs: number, callback: TimerCallback): Timer;
static readonly getPeriodicTimer = (name: string, intervalMs: number, callback: TimerCallback): Timer =>
Time.get().getPeriodicTimer(name, intervalMs, callback);
static readonly sleep = async (name: string, durationMs: number): Promise<void> =>
new Promise(resolve => Time.get().getTimer(name, durationMs, resolve).start());
static register(timer: Timer) {
timer.elapsed = Diagnostic.elapsed();
registry.add(timer);
}
static unregister(timer: Timer) {
registry.delete(timer);
}
}
const DefaultTime = new (class extends Time {
now() {
return new Date();
}
nowMs() {
return this.now().getTime();
}
getTimer(): Timer {
throw new NoProviderError("Default time provider does not implement timers");
}
getPeriodicTimer() {
return this.getTimer();
}
})();
export interface Timer {
/** Name (diagnostics) */
name: string;
/** Set to true to indicate the timer should not prevent program exit */
utility: boolean;
/** System ID (diagnostics) */
systemId: unknown;
/** Interval (diagnostics) */
intervalMs: number;
/** Is the timer periodic? (diagnostics) */
isPeriodic: boolean;
/** Amount of time interval has been active (diagnostics) */
elapsed?: Diagnostic.Elapsed;
/** Is true if this timer is running. */
isRunning: boolean;
/** Starts this timer, chainable. */
start(): Timer;
/** Stops this timer, chainable. */
stop(): Timer;
}
// Hook for testing frameworks
if (typeof MatterHooks !== "undefined") {
MatterHooks.timeSetup?.(Time);
}
DiagnosticSource.add({
get [Diagnostic.value]() {
return Diagnostic.node("⏱", "Timers", {
children: [...registry].map(timer => [
timer.name,
Diagnostic.dict({
periodic: timer.isPeriodic,
interval: Diagnostic.interval(timer.intervalMs),
system: timer.systemId,
elapsed: timer.elapsed,
}),
]),
});
},
});