build(deps-dev): apply updates
[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 export enum AsyncLockType {
6 configuration = 'configuration',
7 performance = 'performance',
8 }
9
10 type ResolveType = (value: void | PromiseLike<void>) => void;
11
12 export class AsyncLock {
13 private static readonly asyncLocks = new Map<AsyncLockType, AsyncLock>();
14 private acquired: boolean;
15 private readonly resolveQueue: Queue<ResolveType>;
16
17 private constructor() {
18 this.acquired = false;
19 this.resolveQueue = new Queue<ResolveType>();
20 }
21
22 public static async acquire(type: AsyncLockType): Promise<void> {
23 const asyncLock = AsyncLock.getAsyncLock(type);
24 if (!asyncLock.acquired) {
25 asyncLock.acquired = true;
26 return;
27 }
28 return new Promise((resolve) => {
29 asyncLock.resolveQueue.enqueue(resolve);
30 });
31 }
32
33 public static async release(type: AsyncLockType): Promise<void> {
34 const asyncLock = AsyncLock.getAsyncLock(type);
35 if (asyncLock.resolveQueue.size === 0 && asyncLock.acquired) {
36 asyncLock.acquired = false;
37 return;
38 }
39 const queuedResolve = asyncLock.resolveQueue.dequeue()!;
40 return new Promise((resolve) => {
41 queuedResolve();
42 resolve();
43 });
44 }
45
46 private static getAsyncLock(type: AsyncLockType): AsyncLock {
47 if (!AsyncLock.asyncLocks.has(type)) {
48 AsyncLock.asyncLocks.set(type, new AsyncLock());
49 }
50 return AsyncLock.asyncLocks.get(type)!;
51 }
52 }