All files / json-crdt-server/src/util Mutex.ts

100% Statements 25/25
75% Branches 6/8
66.66% Functions 4/6
100% Lines 22/22

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 437x       1260x 1260x       7x 67x   67x 1260x 1260x 1260x   1167x 1167x   1260x       1260x 1260x 1253x   7x   1260x 1260x 1260x 1260x   93x 93x            
import {Defer} from 'thingies/lib/Defer';
 
class Entry<T> {
  constructor(
    public readonly code: () => Promise<T>,
    public readonly future: Defer<T>,
  ) {}
}
 
export class Mutex {
  protected readonly queue = new Map<string, Entry<unknown>[]>();
 
  public readonly acquire = async <T>(key: string, code: () => Promise<T>): Promise<T> => {
    const queue = this.queue.get(key);
    const entry = new Entry(code, new Defer<T>());
    if (queue instanceof Array) queue.push(entry as Entry<unknown>);
    else {
      this.queue.set(key, []);
      this.run(key, entry).catch(() => {});
    }
    return await entry.future.promise;
  };
 
  protected async run<T>(key: string, entry: Entry<T>): Promise<void> {
    try {
      const result = await entry.code();
      entry.future.resolve(result);
    } catch (error) {
      entry.future.reject(error);
    } finally {
      const queue = this.queue;
      const entries = queue.get(key);
      Eif (entries instanceof Array) {
        if (!entries.length) queue.delete(key);
        else {
          const next = entries.shift();
          Eif (next instanceof Entry) this.run(key, next).catch(() => {});
        }
      }
    }
  }
}