build: fix mnemonist bundling as external
[e-mobility-charging-stations-simulator.git] / src / utils / AsyncLock.ts
CommitLineData
b9b617a2
JB
1// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
2
a7d26b50 3import { Queue } from 'mnemonist'
4f9327bf 4
66a7748d 5import { Constants } from './Constants.js'
0ebf7c2e 6
1227a6f1
JB
7export enum AsyncLockType {
8 configuration = 'configuration',
a807045b 9 performance = 'performance',
1227a6f1
JB
10}
11
66a7748d 12type ResolveType = (value: void | PromiseLike<void>) => void
4f9327bf 13
1227a6f1 14export class AsyncLock {
66a7748d
JB
15 private static readonly asyncLocks = new Map<AsyncLockType, AsyncLock>()
16 private acquired: boolean
17 private readonly resolveQueue: Queue<ResolveType>
1227a6f1 18
66a7748d
JB
19 private constructor () {
20 this.acquired = false
21 this.resolveQueue = new Queue<ResolveType>()
1227a6f1
JB
22 }
23
0ebf7c2e 24 public static async runExclusive<T>(type: AsyncLockType, fn: () => T | Promise<T>): Promise<T> {
66a7748d 25 return await AsyncLock.acquire(type)
0ebf7c2e
JB
26 .then(fn)
27 .finally(() => {
66a7748d
JB
28 AsyncLock.release(type).catch(Constants.EMPTY_FUNCTION)
29 })
0ebf7c2e
JB
30 }
31
66a7748d
JB
32 private static async acquire (type: AsyncLockType): Promise<void> {
33 const asyncLock = AsyncLock.getAsyncLock(type)
dd485b56 34 if (!asyncLock.acquired) {
66a7748d
JB
35 asyncLock.acquired = true
36 return
1227a6f1 37 }
66a7748d
JB
38 await new Promise<void>((resolve) => {
39 asyncLock.resolveQueue.enqueue(resolve)
40 })
1227a6f1
JB
41 }
42
66a7748d
JB
43 private static async release (type: AsyncLockType): Promise<void> {
44 const asyncLock = AsyncLock.getAsyncLock(type)
4f9327bf 45 if (asyncLock.resolveQueue.size === 0 && asyncLock.acquired) {
66a7748d
JB
46 asyncLock.acquired = false
47 return
1227a6f1 48 }
a7d26b50 49 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
66a7748d
JB
50 const queuedResolve = asyncLock.resolveQueue.dequeue()!
51 await new Promise<void>((resolve) => {
52 queuedResolve()
53 resolve()
54 })
1227a6f1 55 }
dd485b56 56
66a7748d 57 private static getAsyncLock (type: AsyncLockType): AsyncLock {
dd485b56 58 if (!AsyncLock.asyncLocks.has(type)) {
66a7748d 59 AsyncLock.asyncLocks.set(type, new AsyncLock())
dd485b56 60 }
66a7748d
JB
61 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
62 return AsyncLock.asyncLocks.get(type)!
dd485b56 63 }
1227a6f1 64}