@keeex/utils 7.2.1 → 7.4.0
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/lib/async/eventqueue.d.ts +60 -0
- package/lib/async/eventqueue.js +129 -0
- package/lib/async/keycache.d.ts +1 -1
- package/lib/async/timecache.d.ts +1 -1
- package/lib/benchmark.d.ts +1 -1
- package/lib/benchmark.js +2 -2
- package/lib/bits/arraybuffer.js +2 -1
- package/lib/bits/triggers/base.d.ts +30 -0
- package/lib/bits/triggers/base.js +171 -0
- package/lib/bits/triggers/debounce.d.ts +30 -0
- package/lib/bits/triggers/debounce.js +36 -0
- package/lib/bits/triggers/grenade.d.ts +33 -0
- package/lib/bits/triggers/grenade.js +37 -0
- package/lib/bits/triggers/types.d.ts +43 -0
- package/lib/bits/triggers/types.js +30 -0
- package/lib/cron.d.ts +2 -2
- package/lib/cron.js +1 -1
- package/lib/marshalling/marshaller.d.ts +1 -1
- package/lib/promise.d.ts +21 -2
- package/lib/promise.js +43 -4
- package/lib/triggers.d.ts +21 -0
- package/lib/triggers.js +21 -0
- package/lib/types/array.d.ts +6 -6
- package/lib/types/array.js +3 -3
- package/lib/types/enum.d.ts +3 -3
- package/lib/types/enum.js +2 -2
- package/lib/types/record.d.ts +7 -7
- package/lib/types/record.js +3 -3
- package/lib/types/utils.d.ts +4 -3
- package/lib/types/utils.js +13 -6
- package/package.json +1 -1
- package/web/async/eventqueue.d.ts +60 -0
- package/web/async/eventqueue.js +126 -0
- package/web/async/keycache.d.ts +1 -1
- package/web/async/timecache.d.ts +1 -1
- package/web/benchmark.d.ts +1 -1
- package/web/benchmark.js +2 -2
- package/web/bits/arraybuffer.js +3 -1
- package/web/bits/triggers/base.d.ts +30 -0
- package/web/bits/triggers/base.js +173 -0
- package/web/bits/triggers/debounce.d.ts +30 -0
- package/web/bits/triggers/debounce.js +36 -0
- package/web/bits/triggers/grenade.d.ts +33 -0
- package/web/bits/triggers/grenade.js +37 -0
- package/web/bits/triggers/types.d.ts +43 -0
- package/web/bits/triggers/types.js +30 -0
- package/web/cron.d.ts +2 -2
- package/web/marshalling/marshaller.d.ts +1 -1
- package/web/promise.d.ts +21 -2
- package/web/promise.js +37 -4
- package/web/triggers.d.ts +21 -0
- package/web/triggers.js +21 -0
- package/web/types/array.d.ts +6 -6
- package/web/types/array.js +3 -3
- package/web/types/enum.d.ts +3 -3
- package/web/types/enum.js +2 -2
- package/web/types/record.d.ts +7 -7
- package/web/types/record.js +3 -3
- package/web/types/utils.d.ts +4 -3
- package/web/types/utils.js +6 -6
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import * as kxLog from "@keeex/log";
|
|
17
|
+
/**
|
|
18
|
+
* Provides asynchronous handling of a sequential event queue.
|
|
19
|
+
*
|
|
20
|
+
* This should work as a regular sequential event queue, except that the handling of these events
|
|
21
|
+
* can be done using asynchronous functions.
|
|
22
|
+
* All handlers will be called on all input events in the order they came in, but there is no
|
|
23
|
+
* guarantee on the *order* of the event handlers when there is more than one.
|
|
24
|
+
*
|
|
25
|
+
* More events can be triggered while some events are processed, in which case they'll cause more
|
|
26
|
+
* calls to the handlers as needed.
|
|
27
|
+
*/
|
|
28
|
+
export class EventQueue {
|
|
29
|
+
#activeDispenser = null;
|
|
30
|
+
#closed = false;
|
|
31
|
+
#events = [];
|
|
32
|
+
#handlers = [];
|
|
33
|
+
#log;
|
|
34
|
+
#merger;
|
|
35
|
+
constructor(merger, logger = kxLog.createLogger({
|
|
36
|
+
tag: "EventQueue",
|
|
37
|
+
numbered: true
|
|
38
|
+
})) {
|
|
39
|
+
this.#log = logger;
|
|
40
|
+
this.#merger = merger;
|
|
41
|
+
}
|
|
42
|
+
addHandler = handler => {
|
|
43
|
+
this.#handlers.push(handler);
|
|
44
|
+
};
|
|
45
|
+
removeHandler = handler => {
|
|
46
|
+
const index = this.#handlers.indexOf(handler);
|
|
47
|
+
if (index !== -1) this.#handlers.splice(index, 1);
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Cancel all pending events.
|
|
51
|
+
*
|
|
52
|
+
* Currently pending events that are not being processed are dropped.
|
|
53
|
+
* This does not prevent more events from being sent, and will not stop current processing.
|
|
54
|
+
*/
|
|
55
|
+
cancelAll = () => {
|
|
56
|
+
this.#events.length = 0;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Disable all further event processing.
|
|
60
|
+
*
|
|
61
|
+
* This will not stop current processing.
|
|
62
|
+
*/
|
|
63
|
+
close = (cancelAll = false) => {
|
|
64
|
+
this.#closed = true;
|
|
65
|
+
if (cancelAll) this.cancelAll();
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Wait for all handlers to complete.
|
|
69
|
+
*
|
|
70
|
+
* If there are currently events being processed, this will wait until they are all processed.
|
|
71
|
+
* If more events show up while waiting, it will wait for those events to be processed too.
|
|
72
|
+
* If there are no events currently being processed, it will resolve immediately.
|
|
73
|
+
*/
|
|
74
|
+
wait = () => this.#activeDispenser ?? Promise.resolve();
|
|
75
|
+
/** Trigger an event to be handled */
|
|
76
|
+
trigger = data => {
|
|
77
|
+
if (this.#closed) {
|
|
78
|
+
try {
|
|
79
|
+
this.#log.error("Received event while closed", data);
|
|
80
|
+
} catch {
|
|
81
|
+
this.#log.error("Received event while closed (can't display)");
|
|
82
|
+
}
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
this.#events.push(data);
|
|
86
|
+
try {
|
|
87
|
+
this.#log.debug("Event trigger with data", data);
|
|
88
|
+
} catch {
|
|
89
|
+
this.#log.debug("Event trigger with data (can't display)");
|
|
90
|
+
}
|
|
91
|
+
this.#activeDispenser ??= this.#triggerAsync();
|
|
92
|
+
};
|
|
93
|
+
/** Call the event handlers sequentially on all buffered data */
|
|
94
|
+
#triggerAsync = async () => {
|
|
95
|
+
this.#log.debug("Dispensing events to handlers");
|
|
96
|
+
try {
|
|
97
|
+
// We could do this with recursive calls after instead, but there is no need for a deep stack
|
|
98
|
+
// trace for this.
|
|
99
|
+
while (this.#events.length > 0) {
|
|
100
|
+
// eslint-disable-next-line no-await-in-loop
|
|
101
|
+
const nextEvent = await this.#getNextEvent();
|
|
102
|
+
// eslint-disable-next-line no-await-in-loop
|
|
103
|
+
await Promise.all(this.#handlers.map(handler => handler(nextEvent)));
|
|
104
|
+
if (this.#events.length > 0) {
|
|
105
|
+
this.#log.debug("More events in queue");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} finally {
|
|
109
|
+
this.#log.debug("Done dispensing events");
|
|
110
|
+
this.#activeDispenser = null;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
/** Return the next event to process */
|
|
114
|
+
#getNextEvent = async () => {
|
|
115
|
+
if (this.#events.length === 0) throw new Error("No more events to process");
|
|
116
|
+
if (this.#merger && this.#events.length > 1) {
|
|
117
|
+
this.#log.debug(`Merging ${this.#events.length} events into one`);
|
|
118
|
+
const allEvents = [...this.#events];
|
|
119
|
+
this.#events.length = 0;
|
|
120
|
+
const merged = await this.#merger(allEvents);
|
|
121
|
+
return merged;
|
|
122
|
+
}
|
|
123
|
+
const nextEvent = this.#events.shift();
|
|
124
|
+
return nextEvent;
|
|
125
|
+
};
|
|
126
|
+
}
|
package/web/async/keycache.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
14
|
*
|
|
15
15
|
*/
|
|
16
|
-
import { Awaitable } from "../types/types.js";
|
|
16
|
+
import { type Awaitable } from "../types/types.js";
|
|
17
17
|
/**
|
|
18
18
|
* Function used to fill a cache entry on a cache miss.
|
|
19
19
|
*
|
package/web/async/timecache.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
14
|
*
|
|
15
15
|
*/
|
|
16
|
-
import { Awaitable } from "../types/types.js";
|
|
16
|
+
import { type Awaitable } from "../types/types.js";
|
|
17
17
|
/** Function used to refresh a timed cache */
|
|
18
18
|
export type ProbeFunc<T> = () => Awaitable<T>;
|
|
19
19
|
type HandlerFunc<T> = (error?: Error, value?: T) => void;
|
package/web/benchmark.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
14
|
*
|
|
15
15
|
*/
|
|
16
|
-
import { Awaitable } from "./types/types.js";
|
|
16
|
+
import { type Awaitable } from "./types/types.js";
|
|
17
17
|
export type BenchmarkFunction = (() => Promise<void>) | (() => void);
|
|
18
18
|
/**
|
|
19
19
|
* Run the provided function for given iterations and return the average runtime in ms.
|
package/web/benchmark.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
14
|
*
|
|
15
15
|
*/
|
|
16
|
-
import
|
|
16
|
+
import * as kxLog from "@keeex/log";
|
|
17
17
|
/** Return now() up to the best precision available */
|
|
18
18
|
const getNow = typeof performance.now === "function" ? () => performance.now() : () => Date.now();
|
|
19
19
|
/**
|
|
@@ -73,7 +73,7 @@ const addToAverageWindow = (value, window, len) => {
|
|
|
73
73
|
};
|
|
74
74
|
let logger = null;
|
|
75
75
|
const getLogger = () => {
|
|
76
|
-
logger ??= createLogger({
|
|
76
|
+
logger ??= kxLog.createLogger({
|
|
77
77
|
tag: "@keeex/js-utils:benchmark"
|
|
78
78
|
});
|
|
79
79
|
return logger;
|
package/web/bits/arraybuffer.js
CHANGED
|
@@ -23,7 +23,9 @@ import { b64EffectiveData, B64_PAD2, B64_PAD1, B64_PAD0, B64_CHARBLOCK } from ".
|
|
|
23
23
|
export const getArrayBuffer = typedArray => {
|
|
24
24
|
if (typedArray instanceof ArrayBuffer) return typedArray;
|
|
25
25
|
const ab = typedArray.buffer;
|
|
26
|
-
if (typedArray.byteOffset === 0 && typedArray.byteLength === ab.byteLength)
|
|
26
|
+
if (typedArray.byteOffset === 0 && typedArray.byteLength === ab.byteLength) {
|
|
27
|
+
return ab;
|
|
28
|
+
}
|
|
27
29
|
return ab.slice(typedArray.byteOffset, typedArray.byteOffset + typedArray.byteLength);
|
|
28
30
|
};
|
|
29
31
|
/**
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import * as kxLog from "@keeex/log";
|
|
17
|
+
import * as types from "./types.js";
|
|
18
|
+
/**
|
|
19
|
+
* Base implementation for all triggers.
|
|
20
|
+
*/
|
|
21
|
+
export declare abstract class BaseTrigger implements types.Trigger {
|
|
22
|
+
#private;
|
|
23
|
+
constructor(handler: types.TriggerHandler, delayMs: number, logger?: kxLog.Logger | string);
|
|
24
|
+
protected get state(): types.TriggerState;
|
|
25
|
+
protected set state(value: types.TriggerState);
|
|
26
|
+
protected get logger(): kxLog.Logger;
|
|
27
|
+
abstract trigger(): void;
|
|
28
|
+
cancel: () => void;
|
|
29
|
+
stop: () => void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import * as kxLog from "@keeex/log";
|
|
17
|
+
import { dropPromise } from "../../promise.js";
|
|
18
|
+
import * as types from "./types.js";
|
|
19
|
+
/**
|
|
20
|
+
* Base implementation for all triggers.
|
|
21
|
+
*/
|
|
22
|
+
export class BaseTrigger {
|
|
23
|
+
#state = types.TriggerState.inactive;
|
|
24
|
+
#timeout = null;
|
|
25
|
+
#delay;
|
|
26
|
+
#handler;
|
|
27
|
+
#logger;
|
|
28
|
+
constructor(handler, delayMs, logger) {
|
|
29
|
+
this.#handler = handler;
|
|
30
|
+
this.#delay = delayMs;
|
|
31
|
+
if (typeof logger === "string") {
|
|
32
|
+
this.#logger = kxLog.createLogger({
|
|
33
|
+
tag: logger,
|
|
34
|
+
numbered: true
|
|
35
|
+
});
|
|
36
|
+
} else if (logger) {
|
|
37
|
+
this.#logger = logger;
|
|
38
|
+
} else {
|
|
39
|
+
this.#logger = kxLog.createLogger({
|
|
40
|
+
tag: "PromiseTrigger",
|
|
41
|
+
numbered: true
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
this.#logger.debug(`Initialized with timer of ${delayMs}`);
|
|
45
|
+
}
|
|
46
|
+
get state() {
|
|
47
|
+
return this.#state;
|
|
48
|
+
}
|
|
49
|
+
set state(value) {
|
|
50
|
+
const oldState = this.#state;
|
|
51
|
+
this.#logger.debug(`State transition: ${oldState} → ${value}`);
|
|
52
|
+
this.#state = value;
|
|
53
|
+
switch (oldState) {
|
|
54
|
+
case types.TriggerState.inactive:
|
|
55
|
+
this.#stateFromInactive(value);
|
|
56
|
+
break;
|
|
57
|
+
case types.TriggerState.pending:
|
|
58
|
+
this.#stateFromPending(value);
|
|
59
|
+
break;
|
|
60
|
+
case types.TriggerState.running:
|
|
61
|
+
this.#stateFromRunning(value);
|
|
62
|
+
break;
|
|
63
|
+
case types.TriggerState.runningRetrigger:
|
|
64
|
+
this.#stateFromRunningRetrigger(value);
|
|
65
|
+
break;
|
|
66
|
+
case types.TriggerState.runningStop:
|
|
67
|
+
this.#stateFromRunningStop(value);
|
|
68
|
+
break;
|
|
69
|
+
case types.TriggerState.stop:
|
|
70
|
+
this.#stateFromStop(value);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
get logger() {
|
|
75
|
+
return this.#logger;
|
|
76
|
+
}
|
|
77
|
+
cancel = () => {
|
|
78
|
+
this.state = types.TriggerState.inactive;
|
|
79
|
+
};
|
|
80
|
+
stop = () => {
|
|
81
|
+
this.state = types.TriggerState.stop;
|
|
82
|
+
};
|
|
83
|
+
#stateFromInactive = value => {
|
|
84
|
+
switch (value) {
|
|
85
|
+
case types.TriggerState.pending:
|
|
86
|
+
this.#armTimeout();
|
|
87
|
+
break;
|
|
88
|
+
case types.TriggerState.running:
|
|
89
|
+
case types.TriggerState.runningRetrigger:
|
|
90
|
+
throw new Error("Cannot transition from inactive to running");
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
#stateFromPending = value => {
|
|
94
|
+
switch (value) {
|
|
95
|
+
case types.TriggerState.inactive:
|
|
96
|
+
this.#disarmTimeout();
|
|
97
|
+
break;
|
|
98
|
+
case types.TriggerState.running:
|
|
99
|
+
this.#timeout = null;
|
|
100
|
+
break;
|
|
101
|
+
case types.TriggerState.stop:
|
|
102
|
+
this.#disarmTimeout();
|
|
103
|
+
this.#runHandler();
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
#stateFromRunning = value => {
|
|
107
|
+
switch (value) {
|
|
108
|
+
case types.TriggerState.pending:
|
|
109
|
+
this.state = types.TriggerState.runningRetrigger;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
#stateFromRunningRetrigger = value => {
|
|
113
|
+
switch (value) {
|
|
114
|
+
case types.TriggerState.inactive:
|
|
115
|
+
this.state = types.TriggerState.pending;
|
|
116
|
+
break;
|
|
117
|
+
case types.TriggerState.pending:
|
|
118
|
+
this.state = types.TriggerState.runningRetrigger;
|
|
119
|
+
break;
|
|
120
|
+
case types.TriggerState.running:
|
|
121
|
+
throw new Error("Cannot transition from retrigger to running");
|
|
122
|
+
case types.TriggerState.stop:
|
|
123
|
+
this.#runHandler();
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
#stateFromRunningStop = value => {
|
|
127
|
+
switch (value) {
|
|
128
|
+
case types.TriggerState.inactive:
|
|
129
|
+
this.state = types.TriggerState.stop;
|
|
130
|
+
break;
|
|
131
|
+
case types.TriggerState.pending:
|
|
132
|
+
case types.TriggerState.running:
|
|
133
|
+
case types.TriggerState.runningRetrigger:
|
|
134
|
+
case types.TriggerState.runningStop:
|
|
135
|
+
throw new Error("Invalid state transition from runningStop");
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
#stateFromStop = value => {
|
|
139
|
+
switch (value) {
|
|
140
|
+
case types.TriggerState.inactive:
|
|
141
|
+
case types.TriggerState.pending:
|
|
142
|
+
case types.TriggerState.runningRetrigger:
|
|
143
|
+
this.state = types.TriggerState.stop;
|
|
144
|
+
break;
|
|
145
|
+
case types.TriggerState.running:
|
|
146
|
+
this.state = types.TriggerState.runningStop;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
#armTimeout = () => {
|
|
151
|
+
this.#disarmTimeout();
|
|
152
|
+
this.#logger.debug("Arming timeout");
|
|
153
|
+
this.#timeout = setTimeout(this.#runHandler, this.#delay);
|
|
154
|
+
};
|
|
155
|
+
#disarmTimeout = () => {
|
|
156
|
+
if (this.#timeout === null) return;
|
|
157
|
+
this.#logger.debug("Disarming previous timeout");
|
|
158
|
+
clearTimeout(this.#timeout);
|
|
159
|
+
this.#timeout = null;
|
|
160
|
+
};
|
|
161
|
+
#runHandler = () => {
|
|
162
|
+
this.#logger.debug("Running handler");
|
|
163
|
+
this.state = types.TriggerState.running;
|
|
164
|
+
dropPromise(this.#runHandlerPromise, this.#logger);
|
|
165
|
+
};
|
|
166
|
+
#runHandlerPromise = async () => {
|
|
167
|
+
try {
|
|
168
|
+
await this.#handler();
|
|
169
|
+
} finally {
|
|
170
|
+
this.state = types.TriggerState.inactive;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { type Logger } from "@keeex/log";
|
|
17
|
+
import { BaseTrigger } from "./base.js";
|
|
18
|
+
import * as types from "./types.js";
|
|
19
|
+
/**
|
|
20
|
+
* Debouncing trigger.
|
|
21
|
+
*
|
|
22
|
+
* Each time the trigger is triggered, the timer rearms itself, delaying the callback ever more.
|
|
23
|
+
* Once there is no trigger for the duration of the trigger, the callback is finally called.
|
|
24
|
+
*
|
|
25
|
+
* Useful for debouncing.
|
|
26
|
+
*/
|
|
27
|
+
export declare class DebounceTrigger extends BaseTrigger {
|
|
28
|
+
constructor(handler: types.TriggerHandler, delayMs: number, logger?: Logger | string);
|
|
29
|
+
trigger: () => void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { BaseTrigger } from "./base.js";
|
|
17
|
+
import * as types from "./types.js";
|
|
18
|
+
/**
|
|
19
|
+
* Debouncing trigger.
|
|
20
|
+
*
|
|
21
|
+
* Each time the trigger is triggered, the timer rearms itself, delaying the callback ever more.
|
|
22
|
+
* Once there is no trigger for the duration of the trigger, the callback is finally called.
|
|
23
|
+
*
|
|
24
|
+
* Useful for debouncing.
|
|
25
|
+
*/
|
|
26
|
+
export class DebounceTrigger extends BaseTrigger {
|
|
27
|
+
constructor(handler, delayMs, logger = "DebounceTrigger") {
|
|
28
|
+
super(handler, delayMs, logger);
|
|
29
|
+
}
|
|
30
|
+
trigger = () => {
|
|
31
|
+
if (this.state === types.TriggerState.pending) {
|
|
32
|
+
this.state = types.TriggerState.inactive;
|
|
33
|
+
}
|
|
34
|
+
this.state = types.TriggerState.pending;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { type Logger } from "@keeex/log";
|
|
17
|
+
import { BaseTrigger } from "./base.js";
|
|
18
|
+
import * as types from "./types.js";
|
|
19
|
+
/**
|
|
20
|
+
* Trigger that *will* fire its event after the time is elapsed, no matter how many times it is
|
|
21
|
+
* triggered afterward.
|
|
22
|
+
*
|
|
23
|
+
* After a call to `trigger()`, the timer is started.
|
|
24
|
+
* When it runs out, the even function is called.
|
|
25
|
+
* Multiple calls to `trigger()` will not delay the call, and they will not cause additional calls
|
|
26
|
+
* to occur.
|
|
27
|
+
* Calling `trigger()` while the callback is running will reschedule a call *after* the callback
|
|
28
|
+
* completes.
|
|
29
|
+
*/
|
|
30
|
+
export declare class GrenadeTrigger extends BaseTrigger {
|
|
31
|
+
constructor(handler: types.TriggerHandler, delayMs: number, logger?: Logger | string);
|
|
32
|
+
trigger: () => void;
|
|
33
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { BaseTrigger } from "./base.js";
|
|
17
|
+
import * as types from "./types.js";
|
|
18
|
+
/**
|
|
19
|
+
* Trigger that *will* fire its event after the time is elapsed, no matter how many times it is
|
|
20
|
+
* triggered afterward.
|
|
21
|
+
*
|
|
22
|
+
* After a call to `trigger()`, the timer is started.
|
|
23
|
+
* When it runs out, the even function is called.
|
|
24
|
+
* Multiple calls to `trigger()` will not delay the call, and they will not cause additional calls
|
|
25
|
+
* to occur.
|
|
26
|
+
* Calling `trigger()` while the callback is running will reschedule a call *after* the callback
|
|
27
|
+
* completes.
|
|
28
|
+
*/
|
|
29
|
+
export class GrenadeTrigger extends BaseTrigger {
|
|
30
|
+
constructor(handler, delayMs, logger = "GrenadeTrigger") {
|
|
31
|
+
super(handler, delayMs, logger);
|
|
32
|
+
}
|
|
33
|
+
trigger = () => {
|
|
34
|
+
this.logger.debug("Triggered");
|
|
35
|
+
this.state = types.TriggerState.pending;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { type Awaitable } from "../../types/types.js";
|
|
17
|
+
export type TriggerHandler = () => Awaitable<void>;
|
|
18
|
+
export declare enum TriggerState {
|
|
19
|
+
/** Trigger was not triggered */
|
|
20
|
+
inactive = "inactive",
|
|
21
|
+
/** Trigger was triggered, fuse timer is counting down */
|
|
22
|
+
pending = "pending",
|
|
23
|
+
/** Trigger was triggered and timer expired, the handler is running */
|
|
24
|
+
running = "running",
|
|
25
|
+
/** Handler is running, and trigger was called again */
|
|
26
|
+
runningRetrigger = "runningTrigger",
|
|
27
|
+
/** Last run after stop */
|
|
28
|
+
runningStop = "runningStop",
|
|
29
|
+
/** Handler is killed, will never run except for currently triggered call */
|
|
30
|
+
stop = "stop"
|
|
31
|
+
}
|
|
32
|
+
/** Generic interface for delayed triggers */
|
|
33
|
+
export interface Trigger {
|
|
34
|
+
/** Call when the trigger should start (or restart, depending on the implementation) */
|
|
35
|
+
trigger: () => void;
|
|
36
|
+
/** Call when the trigger should be canceled */
|
|
37
|
+
cancel: () => void;
|
|
38
|
+
/**
|
|
39
|
+
* Call when the trigger should stop (it can't be triggered again).
|
|
40
|
+
* If there is an execution pending, it is run immediately.
|
|
41
|
+
*/
|
|
42
|
+
stop: () => void;
|
|
43
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
export var TriggerState;
|
|
17
|
+
(function (TriggerState) {
|
|
18
|
+
/** Trigger was not triggered */
|
|
19
|
+
TriggerState["inactive"] = "inactive";
|
|
20
|
+
/** Trigger was triggered, fuse timer is counting down */
|
|
21
|
+
TriggerState["pending"] = "pending";
|
|
22
|
+
/** Trigger was triggered and timer expired, the handler is running */
|
|
23
|
+
TriggerState["running"] = "running";
|
|
24
|
+
/** Handler is running, and trigger was called again */
|
|
25
|
+
TriggerState["runningRetrigger"] = "runningTrigger";
|
|
26
|
+
/** Last run after stop */
|
|
27
|
+
TriggerState["runningStop"] = "runningStop";
|
|
28
|
+
/** Handler is killed, will never run except for currently triggered call */
|
|
29
|
+
TriggerState["stop"] = "stop";
|
|
30
|
+
})(TriggerState || (TriggerState = {}));
|
package/web/cron.d.ts
CHANGED
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
14
|
*
|
|
15
15
|
*/
|
|
16
|
-
import { Logger } from "@keeex/log";
|
|
16
|
+
import { type Logger } from "@keeex/log";
|
|
17
17
|
import ScheduledTask from "./cron/scheduledtask.js";
|
|
18
|
-
import { TaskFunction, TaskOptions, Overrun, CompleteTaskOptions } from "./cron/types.js";
|
|
18
|
+
import { type TaskFunction, type TaskOptions, Overrun, type CompleteTaskOptions } from "./cron/types.js";
|
|
19
19
|
export { Overrun };
|
|
20
20
|
export type { ScheduledTask, TaskFunction, TaskOptions, CompleteTaskOptions };
|
|
21
21
|
/**
|
|
@@ -23,7 +23,7 @@ export default class Marshaller {
|
|
|
23
23
|
private constructor();
|
|
24
24
|
static readonly start: (magicNumbers?: string) => Marshaller;
|
|
25
25
|
/** End building the buffer and returns the result */
|
|
26
|
-
readonly end: () =>
|
|
26
|
+
readonly end: () => Uint8Array;
|
|
27
27
|
/** Append an utf-8 string */
|
|
28
28
|
readonly str: (value: string) => this;
|
|
29
29
|
/** Append a 32-bit unsigned int */
|