@hla4ts/session 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +377 -377
- package/package.json +3 -3
- package/src/errors.ts +98 -98
- package/src/index.ts +147 -147
- package/src/messages.ts +329 -329
- package/src/sequence-number.ts +200 -200
- package/src/session.ts +976 -976
- package/src/timeout-timer.ts +204 -204
- package/src/types.ts +235 -235
package/src/timeout-timer.ts
CHANGED
|
@@ -1,204 +1,204 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Timeout Timer
|
|
3
|
-
*
|
|
4
|
-
* Utility class to execute a callback after a timer expires.
|
|
5
|
-
* Supports extending the timeout and pausing/resuming.
|
|
6
|
-
*
|
|
7
|
-
* Can be configured as "eager" (may trigger early) or "lazy" (never triggers early).
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Timer that executes a callback after a timeout.
|
|
12
|
-
* Supports extending, pausing, and resuming.
|
|
13
|
-
*/
|
|
14
|
-
export class TimeoutTimer {
|
|
15
|
-
private readonly _timeoutDurationMs: number;
|
|
16
|
-
private readonly _checkIntervalMs: number;
|
|
17
|
-
private readonly _offsetTimeMs: number;
|
|
18
|
-
private _timeoutTimestampMs: number = Number.MAX_SAFE_INTEGER;
|
|
19
|
-
private _intervalHandle: ReturnType<typeof setInterval> | null = null;
|
|
20
|
-
private _onTimeout: (() => void) | null = null;
|
|
21
|
-
private _cancelled: boolean = false;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Create a new timeout timer.
|
|
25
|
-
*
|
|
26
|
-
* @param timeoutDurationMs - Duration until timeout in milliseconds
|
|
27
|
-
* @param eager - If true, timeout may trigger early but never late. If false, never triggers early.
|
|
28
|
-
*/
|
|
29
|
-
private constructor(timeoutDurationMs: number, eager: boolean) {
|
|
30
|
-
this._timeoutDurationMs = timeoutDurationMs;
|
|
31
|
-
|
|
32
|
-
// Calculate check interval (check 6 times per timeout period)
|
|
33
|
-
const wakeUpTimesPerInterval = 6;
|
|
34
|
-
this._checkIntervalMs = Math.max(
|
|
35
|
-
1,
|
|
36
|
-
Math.floor(timeoutDurationMs / wakeUpTimesPerInterval)
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
// For eager mode, trigger slightly before the full timeout
|
|
40
|
-
this._offsetTimeMs = eager
|
|
41
|
-
? this._checkIntervalMs * (wakeUpTimesPerInterval - 1)
|
|
42
|
-
: timeoutDurationMs;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Create a lazy timeout timer (never triggers early, may trigger late)
|
|
47
|
-
*/
|
|
48
|
-
static createLazy(timeoutDurationMs: number): TimeoutTimer {
|
|
49
|
-
return new TimeoutTimer(timeoutDurationMs, false);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Create an eager timeout timer (may trigger early, never triggers late)
|
|
54
|
-
*/
|
|
55
|
-
static createEager(timeoutDurationMs: number): TimeoutTimer {
|
|
56
|
-
return new TimeoutTimer(timeoutDurationMs, true);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Get the configured timeout duration
|
|
61
|
-
*/
|
|
62
|
-
get timeoutDurationMs(): number {
|
|
63
|
-
return this._timeoutDurationMs;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Check if the timer is currently running
|
|
68
|
-
*/
|
|
69
|
-
get isRunning(): boolean {
|
|
70
|
-
return this._intervalHandle !== null && !this._cancelled;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Start the timer with a callback to execute on timeout.
|
|
75
|
-
*
|
|
76
|
-
* @param onTimeout - Callback to execute when the timer expires
|
|
77
|
-
*/
|
|
78
|
-
start(onTimeout: () => void): void {
|
|
79
|
-
if (this._timeoutDurationMs === 0) {
|
|
80
|
-
// Zero timeout means no timeout checking
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (this._cancelled) {
|
|
85
|
-
throw new Error("Cannot start a cancelled timer");
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
this._onTimeout = onTimeout;
|
|
89
|
-
|
|
90
|
-
// Start the periodic check
|
|
91
|
-
this._intervalHandle = setInterval(() => {
|
|
92
|
-
this._checkTimeout();
|
|
93
|
-
}, this._checkIntervalMs);
|
|
94
|
-
|
|
95
|
-
// Set initial timeout timestamp
|
|
96
|
-
this.extend();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Check if the timeout has been reached
|
|
101
|
-
*/
|
|
102
|
-
private _checkTimeout(): void {
|
|
103
|
-
const now = Date.now();
|
|
104
|
-
if (now >= this._timeoutTimestampMs) {
|
|
105
|
-
this.pause();
|
|
106
|
-
this._onTimeout?.();
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Pause the timer (prevents timeout from triggering)
|
|
112
|
-
*/
|
|
113
|
-
pause(): void {
|
|
114
|
-
this._timeoutTimestampMs = Number.MAX_SAFE_INTEGER;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Resume the timer after being paused
|
|
119
|
-
*/
|
|
120
|
-
resume(): void {
|
|
121
|
-
this.extend();
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Extend the timeout by resetting the timer
|
|
126
|
-
*/
|
|
127
|
-
extend(): void {
|
|
128
|
-
this._timeoutTimestampMs = Date.now() + this._offsetTimeMs;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Cancel the timer permanently
|
|
133
|
-
*/
|
|
134
|
-
cancel(): void {
|
|
135
|
-
this._cancelled = true;
|
|
136
|
-
if (this._intervalHandle !== null) {
|
|
137
|
-
clearInterval(this._intervalHandle);
|
|
138
|
-
this._intervalHandle = null;
|
|
139
|
-
}
|
|
140
|
-
this._onTimeout = null;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Get remaining time until timeout (approximate)
|
|
145
|
-
*/
|
|
146
|
-
get remainingMs(): number {
|
|
147
|
-
const remaining = this._timeoutTimestampMs - Date.now();
|
|
148
|
-
return Math.max(0, remaining);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Simple one-shot timer that executes a callback after a delay.
|
|
154
|
-
* Can be cancelled before execution.
|
|
155
|
-
*/
|
|
156
|
-
export class OneShotTimer {
|
|
157
|
-
private _handle: ReturnType<typeof setTimeout> | null = null;
|
|
158
|
-
private _cancelled: boolean = false;
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Schedule a callback to execute after the specified delay.
|
|
162
|
-
*
|
|
163
|
-
* @param callback - Callback to execute
|
|
164
|
-
* @param delayMs - Delay in milliseconds
|
|
165
|
-
*/
|
|
166
|
-
schedule(callback: () => void, delayMs: number): void {
|
|
167
|
-
if (this._cancelled) {
|
|
168
|
-
throw new Error("Cannot schedule on a cancelled timer");
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
this.clear();
|
|
172
|
-
this._handle = setTimeout(() => {
|
|
173
|
-
this._handle = null;
|
|
174
|
-
if (!this._cancelled) {
|
|
175
|
-
callback();
|
|
176
|
-
}
|
|
177
|
-
}, delayMs);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Clear the scheduled callback without executing it
|
|
182
|
-
*/
|
|
183
|
-
clear(): void {
|
|
184
|
-
if (this._handle !== null) {
|
|
185
|
-
clearTimeout(this._handle);
|
|
186
|
-
this._handle = null;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Cancel the timer permanently
|
|
192
|
-
*/
|
|
193
|
-
cancel(): void {
|
|
194
|
-
this._cancelled = true;
|
|
195
|
-
this.clear();
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Check if a callback is currently scheduled
|
|
200
|
-
*/
|
|
201
|
-
get isScheduled(): boolean {
|
|
202
|
-
return this._handle !== null;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Timeout Timer
|
|
3
|
+
*
|
|
4
|
+
* Utility class to execute a callback after a timer expires.
|
|
5
|
+
* Supports extending the timeout and pausing/resuming.
|
|
6
|
+
*
|
|
7
|
+
* Can be configured as "eager" (may trigger early) or "lazy" (never triggers early).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Timer that executes a callback after a timeout.
|
|
12
|
+
* Supports extending, pausing, and resuming.
|
|
13
|
+
*/
|
|
14
|
+
export class TimeoutTimer {
|
|
15
|
+
private readonly _timeoutDurationMs: number;
|
|
16
|
+
private readonly _checkIntervalMs: number;
|
|
17
|
+
private readonly _offsetTimeMs: number;
|
|
18
|
+
private _timeoutTimestampMs: number = Number.MAX_SAFE_INTEGER;
|
|
19
|
+
private _intervalHandle: ReturnType<typeof setInterval> | null = null;
|
|
20
|
+
private _onTimeout: (() => void) | null = null;
|
|
21
|
+
private _cancelled: boolean = false;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create a new timeout timer.
|
|
25
|
+
*
|
|
26
|
+
* @param timeoutDurationMs - Duration until timeout in milliseconds
|
|
27
|
+
* @param eager - If true, timeout may trigger early but never late. If false, never triggers early.
|
|
28
|
+
*/
|
|
29
|
+
private constructor(timeoutDurationMs: number, eager: boolean) {
|
|
30
|
+
this._timeoutDurationMs = timeoutDurationMs;
|
|
31
|
+
|
|
32
|
+
// Calculate check interval (check 6 times per timeout period)
|
|
33
|
+
const wakeUpTimesPerInterval = 6;
|
|
34
|
+
this._checkIntervalMs = Math.max(
|
|
35
|
+
1,
|
|
36
|
+
Math.floor(timeoutDurationMs / wakeUpTimesPerInterval)
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// For eager mode, trigger slightly before the full timeout
|
|
40
|
+
this._offsetTimeMs = eager
|
|
41
|
+
? this._checkIntervalMs * (wakeUpTimesPerInterval - 1)
|
|
42
|
+
: timeoutDurationMs;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Create a lazy timeout timer (never triggers early, may trigger late)
|
|
47
|
+
*/
|
|
48
|
+
static createLazy(timeoutDurationMs: number): TimeoutTimer {
|
|
49
|
+
return new TimeoutTimer(timeoutDurationMs, false);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Create an eager timeout timer (may trigger early, never triggers late)
|
|
54
|
+
*/
|
|
55
|
+
static createEager(timeoutDurationMs: number): TimeoutTimer {
|
|
56
|
+
return new TimeoutTimer(timeoutDurationMs, true);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get the configured timeout duration
|
|
61
|
+
*/
|
|
62
|
+
get timeoutDurationMs(): number {
|
|
63
|
+
return this._timeoutDurationMs;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Check if the timer is currently running
|
|
68
|
+
*/
|
|
69
|
+
get isRunning(): boolean {
|
|
70
|
+
return this._intervalHandle !== null && !this._cancelled;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Start the timer with a callback to execute on timeout.
|
|
75
|
+
*
|
|
76
|
+
* @param onTimeout - Callback to execute when the timer expires
|
|
77
|
+
*/
|
|
78
|
+
start(onTimeout: () => void): void {
|
|
79
|
+
if (this._timeoutDurationMs === 0) {
|
|
80
|
+
// Zero timeout means no timeout checking
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (this._cancelled) {
|
|
85
|
+
throw new Error("Cannot start a cancelled timer");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this._onTimeout = onTimeout;
|
|
89
|
+
|
|
90
|
+
// Start the periodic check
|
|
91
|
+
this._intervalHandle = setInterval(() => {
|
|
92
|
+
this._checkTimeout();
|
|
93
|
+
}, this._checkIntervalMs);
|
|
94
|
+
|
|
95
|
+
// Set initial timeout timestamp
|
|
96
|
+
this.extend();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Check if the timeout has been reached
|
|
101
|
+
*/
|
|
102
|
+
private _checkTimeout(): void {
|
|
103
|
+
const now = Date.now();
|
|
104
|
+
if (now >= this._timeoutTimestampMs) {
|
|
105
|
+
this.pause();
|
|
106
|
+
this._onTimeout?.();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Pause the timer (prevents timeout from triggering)
|
|
112
|
+
*/
|
|
113
|
+
pause(): void {
|
|
114
|
+
this._timeoutTimestampMs = Number.MAX_SAFE_INTEGER;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Resume the timer after being paused
|
|
119
|
+
*/
|
|
120
|
+
resume(): void {
|
|
121
|
+
this.extend();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Extend the timeout by resetting the timer
|
|
126
|
+
*/
|
|
127
|
+
extend(): void {
|
|
128
|
+
this._timeoutTimestampMs = Date.now() + this._offsetTimeMs;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Cancel the timer permanently
|
|
133
|
+
*/
|
|
134
|
+
cancel(): void {
|
|
135
|
+
this._cancelled = true;
|
|
136
|
+
if (this._intervalHandle !== null) {
|
|
137
|
+
clearInterval(this._intervalHandle);
|
|
138
|
+
this._intervalHandle = null;
|
|
139
|
+
}
|
|
140
|
+
this._onTimeout = null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get remaining time until timeout (approximate)
|
|
145
|
+
*/
|
|
146
|
+
get remainingMs(): number {
|
|
147
|
+
const remaining = this._timeoutTimestampMs - Date.now();
|
|
148
|
+
return Math.max(0, remaining);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Simple one-shot timer that executes a callback after a delay.
|
|
154
|
+
* Can be cancelled before execution.
|
|
155
|
+
*/
|
|
156
|
+
export class OneShotTimer {
|
|
157
|
+
private _handle: ReturnType<typeof setTimeout> | null = null;
|
|
158
|
+
private _cancelled: boolean = false;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Schedule a callback to execute after the specified delay.
|
|
162
|
+
*
|
|
163
|
+
* @param callback - Callback to execute
|
|
164
|
+
* @param delayMs - Delay in milliseconds
|
|
165
|
+
*/
|
|
166
|
+
schedule(callback: () => void, delayMs: number): void {
|
|
167
|
+
if (this._cancelled) {
|
|
168
|
+
throw new Error("Cannot schedule on a cancelled timer");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
this.clear();
|
|
172
|
+
this._handle = setTimeout(() => {
|
|
173
|
+
this._handle = null;
|
|
174
|
+
if (!this._cancelled) {
|
|
175
|
+
callback();
|
|
176
|
+
}
|
|
177
|
+
}, delayMs);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Clear the scheduled callback without executing it
|
|
182
|
+
*/
|
|
183
|
+
clear(): void {
|
|
184
|
+
if (this._handle !== null) {
|
|
185
|
+
clearTimeout(this._handle);
|
|
186
|
+
this._handle = null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Cancel the timer permanently
|
|
192
|
+
*/
|
|
193
|
+
cancel(): void {
|
|
194
|
+
this._cancelled = true;
|
|
195
|
+
this.clear();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Check if a callback is currently scheduled
|
|
200
|
+
*/
|
|
201
|
+
get isScheduled(): boolean {
|
|
202
|
+
return this._handle !== null;
|
|
203
|
+
}
|
|
204
|
+
}
|