build: fix import error
[e-mobility-charging-stations-simulator.git] / src / utils / AsyncLock.ts
CommitLineData
b9b617a2
JB
1// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
2
95e03ad1 3import Queue from 'mnemonist/queue.js'
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
95e03ad1 21 // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
66a7748d 22 this.resolveQueue = new Queue<ResolveType>()
1227a6f1
JB
23 }
24
0ebf7c2e 25 public static async runExclusive<T>(type: AsyncLockType, fn: () => T | Promise<T>): Promise<T> {
66a7748d 26 return await AsyncLock.acquire(type)
0ebf7c2e
JB
27 .then(fn)
28 .finally(() => {
66a7748d
JB
29 AsyncLock.release(type).catch(Constants.EMPTY_FUNCTION)
30 })
0ebf7c2e
JB
31 }
32
66a7748d
JB
33 private static async acquire (type: AsyncLockType): Promise<void> {
34 const asyncLock = AsyncLock.getAsyncLock(type)
dd485b56 35 if (!asyncLock.acquired) {
66a7748d
JB
36 asyncLock.acquired = true
37 return
1227a6f1 38 }
66a7748d 39 await new Promise<void>((resolve) => {
95e03ad1 40 // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
66a7748d
JB
41 asyncLock.resolveQueue.enqueue(resolve)
42 })
1227a6f1
JB
43 }
44
66a7748d
JB
45 private static async release (type: AsyncLockType): Promise<void> {
46 const asyncLock = AsyncLock.getAsyncLock(type)
95e03ad1 47 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
4f9327bf 48 if (asyncLock.resolveQueue.size === 0 && asyncLock.acquired) {
66a7748d
JB
49 asyncLock.acquired = false
50 return
1227a6f1 51 }
95e03ad1 52 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
66a7748d
JB
53 const queuedResolve = asyncLock.resolveQueue.dequeue()!
54 await new Promise<void>((resolve) => {
95e03ad1 55 // eslint-disable-next-line @typescript-eslint/no-unsafe-call
66a7748d
JB
56 queuedResolve()
57 resolve()
58 })
1227a6f1 59 }
dd485b56 60
66a7748d 61 private static getAsyncLock (type: AsyncLockType): AsyncLock {
dd485b56 62 if (!AsyncLock.asyncLocks.has(type)) {
66a7748d 63 AsyncLock.asyncLocks.set(type, new AsyncLock())
dd485b56 64 }
66a7748d
JB
65 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
66 return AsyncLock.asyncLocks.get(type)!
dd485b56 67 }
1227a6f1 68}