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