diff options
author | Kristóf Marussy <kristof@marussy.com> | 2022-08-25 01:25:40 +0200 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2022-08-25 16:44:01 +0200 |
commit | f6de69943df6c669c81b10279bbfaf3158f1fd61 (patch) | |
tree | e19465fd9ae4dc6905ad1aa1f8dbbc92ae43ea62 /subprojects/frontend/src/utils | |
parent | refactor(frontend): xtext update improvements (diff) | |
download | refinery-f6de69943df6c669c81b10279bbfaf3158f1fd61.tar.gz refinery-f6de69943df6c669c81b10279bbfaf3158f1fd61.tar.zst refinery-f6de69943df6c669c81b10279bbfaf3158f1fd61.zip |
fix(frontend): UpdateService synchronization
Also bumps frontend dependencies
Diffstat (limited to 'subprojects/frontend/src/utils')
-rw-r--r-- | subprojects/frontend/src/utils/ConditionVariable.ts | 64 | ||||
-rw-r--r-- | subprojects/frontend/src/utils/PendingTask.ts | 20 |
2 files changed, 9 insertions, 75 deletions
diff --git a/subprojects/frontend/src/utils/ConditionVariable.ts b/subprojects/frontend/src/utils/ConditionVariable.ts deleted file mode 100644 index 1d3431f7..00000000 --- a/subprojects/frontend/src/utils/ConditionVariable.ts +++ /dev/null | |||
@@ -1,64 +0,0 @@ | |||
1 | import PendingTask from './PendingTask'; | ||
2 | import getLogger from './getLogger'; | ||
3 | |||
4 | const log = getLogger('utils.ConditionVariable'); | ||
5 | |||
6 | export type Condition = () => boolean; | ||
7 | |||
8 | export default class ConditionVariable { | ||
9 | private readonly condition: Condition; | ||
10 | |||
11 | private readonly defaultTimeout: number; | ||
12 | |||
13 | private listeners: PendingTask<void>[] = []; | ||
14 | |||
15 | constructor(condition: Condition, defaultTimeout = 0) { | ||
16 | this.condition = condition; | ||
17 | this.defaultTimeout = defaultTimeout; | ||
18 | } | ||
19 | |||
20 | async waitFor(timeoutMs?: number | undefined): Promise<void> { | ||
21 | if (this.condition()) { | ||
22 | return; | ||
23 | } | ||
24 | const timeoutOrDefault = timeoutMs ?? this.defaultTimeout; | ||
25 | let nowMs = Date.now(); | ||
26 | const endMs = nowMs + timeoutOrDefault; | ||
27 | while (!this.condition() && nowMs < endMs) { | ||
28 | const remainingMs = endMs - nowMs; | ||
29 | const promise = new Promise<void>((resolve, reject) => { | ||
30 | if (this.condition()) { | ||
31 | resolve(); | ||
32 | return; | ||
33 | } | ||
34 | const task = new PendingTask(resolve, reject, remainingMs); | ||
35 | this.listeners.push(task); | ||
36 | }); | ||
37 | // We must keep waiting until the update has completed, | ||
38 | // so the tasks can't be started in parallel. | ||
39 | // eslint-disable-next-line no-await-in-loop | ||
40 | await promise; | ||
41 | nowMs = Date.now(); | ||
42 | } | ||
43 | if (!this.condition()) { | ||
44 | log.error('Condition still does not hold after', timeoutOrDefault, 'ms'); | ||
45 | throw new Error('Failed to wait for condition'); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | notifyAll(): void { | ||
50 | this.clearListenersWith((listener) => listener.resolve()); | ||
51 | } | ||
52 | |||
53 | rejectAll(error: unknown): void { | ||
54 | this.clearListenersWith((listener) => listener.reject(error)); | ||
55 | } | ||
56 | |||
57 | private clearListenersWith(callback: (listener: PendingTask<void>) => void) { | ||
58 | // Copy `listeners` so that we don't get into a race condition | ||
59 | // if one of the listeners adds another listener. | ||
60 | const { listeners } = this; | ||
61 | this.listeners = []; | ||
62 | listeners.forEach(callback); | ||
63 | } | ||
64 | } | ||
diff --git a/subprojects/frontend/src/utils/PendingTask.ts b/subprojects/frontend/src/utils/PendingTask.ts index 3976bdf9..205c8452 100644 --- a/subprojects/frontend/src/utils/PendingTask.ts +++ b/subprojects/frontend/src/utils/PendingTask.ts | |||
@@ -14,21 +14,19 @@ export default class PendingTask<T> { | |||
14 | constructor( | 14 | constructor( |
15 | resolveCallback: (value: T) => void, | 15 | resolveCallback: (value: T) => void, |
16 | rejectCallback: (reason?: unknown) => void, | 16 | rejectCallback: (reason?: unknown) => void, |
17 | timeoutMs?: number | undefined, | 17 | timeoutMs: number | undefined, |
18 | timeoutCallback?: () => void | undefined, | 18 | timeoutCallback: () => void | undefined, |
19 | ) { | 19 | ) { |
20 | this.resolveCallback = resolveCallback; | 20 | this.resolveCallback = resolveCallback; |
21 | this.rejectCallback = rejectCallback; | 21 | this.rejectCallback = rejectCallback; |
22 | if (timeoutMs) { | 22 | this.timeout = setTimeout(() => { |
23 | this.timeout = setTimeout(() => { | 23 | if (!this.resolved) { |
24 | if (!this.resolved) { | 24 | this.reject(new Error('Request timed out')); |
25 | this.reject(new Error('Request timed out')); | 25 | if (timeoutCallback) { |
26 | if (timeoutCallback) { | 26 | timeoutCallback(); |
27 | timeoutCallback(); | ||
28 | } | ||
29 | } | 27 | } |
30 | }, timeoutMs); | 28 | } |
31 | } | 29 | }, timeoutMs); |
32 | } | 30 | } |
33 | 31 | ||
34 | resolve(value: T): void { | 32 | resolve(value: T): void { |