{"version":3,"file":"queue.cjs","names":["Emitter","uname","DefaultLogger"],"sources":["../../../src/common/exec/queue.ts"],"sourcesContent":["// Can learn from here https://github.com/sindresorhus/p-queue\n\nimport type { LoggerInterface, LogLevel } from '../log/log-base'\nimport { DefaultLogger } from '../log/log'\nimport { LogLevelOff } from '../log/log-base'\nimport { Emitter } from '../msg/emitter'\nimport { uname } from '../uuid'\n\ntype TaskResolver = any\n\nexport type TaskFn<T = any> = () => Promise<T>\n\ninterface TaskInfo {\n  name: string\n  task: TaskFn\n  resolve: TaskResolver\n}\n\nexport interface TaskEvents {\n  didUpdate: (max: number, resolved: number) => void\n  didStart: (max: number) => void\n  didCancel: () => void\n  didFinish: () => void\n  // didResolve(value: any): void\n  // didReject(error: any): void\n  // didPause(max: number): void\n}\n\n/** Guarentee serial execution of tasks. Able to wait, pause, resume and cancel all. */\nexport class SerialQueue extends Emitter<TaskEvents> {\n  private queue: TaskInfo[] = []\n  private waitToFinish: TaskResolver[] = []\n  private currentTask?: Promise<any>\n  private log: LoggerInterface\n  private countMax = 0\n  private countResolved = 0\n\n  private paused = false\n\n  name: string\n\n  constructor(opt: { name?: string, logLevel?: LogLevel } = {}) {\n    super()\n    const { name = uname('queue'), logLevel } = opt\n    this.name = name\n    this.log = DefaultLogger(`zeed:queue:${name}`, logLevel ?? LogLevelOff)\n  }\n\n  private async performNext() {\n    this.log('performNext, queue.length =', this.queue.length)\n\n    if (this.currentTask != null) {\n      this.log('performNext => skip while another task is running')\n      return\n    }\n\n    if (this.paused) {\n      this.log('performNext => skip while is paused')\n      return\n    }\n\n    while (this.currentTask == null && !this.paused) {\n      const info = this.queue.shift()\n      this.log(`performNext => ${info?.name}`)\n\n      if (info == null)\n        break\n\n      if (this.countResolved === 0)\n        void this.emit('didStart', this.countMax)\n\n      const { name, task, resolve } = info\n      this.currentTask = task()\n      let result\n      try {\n        this.log.info(`start task ${name}`)\n        result = await this.currentTask\n        this.log(`finished task ${name} with result =`, result)\n      }\n      catch (err) {\n        this.log.warn('Error performing task', err)\n      }\n\n      resolve(result)\n      this.currentTask = undefined\n\n      this.countResolved += 1\n      void this.emit('didUpdate', this.countMax, this.countResolved)\n    }\n\n    if (this.queue.length === 0) {\n      void this.emit('didFinish')\n      this.countMax = 0\n      this.countResolved = 0\n    }\n\n    while (this.waitToFinish.length > 0)\n      this.waitToFinish.shift()()\n  }\n\n  /** Enqueue task to be executed when all other tasks are done. Except `immediate = true`. */\n  async enqueue<T>(\n    task: TaskFn<T>,\n    opt: { immediate?: boolean, name?: string } = {},\n  ): Promise<T> {\n    const { immediate = false, name = uname(this.name) } = opt\n    if (immediate) {\n      this.log.info(`immediate execution ${name}`)\n      return await task()\n    }\n\n    this.log(`enqueue ${name}`)\n    return new Promise((resolve) => {\n      this.queue.push({\n        name,\n        task,\n        resolve,\n      })\n\n      this.countMax += 1\n      void this.emit('didUpdate', this.countMax, this.countResolved)\n\n      void this.performNext()\n    })\n  }\n\n  /** If a task is already performing, execute immediately. Otherwise enqueue as usual. */\n  async enqueueReentrant<T>(\n    task: TaskFn<T>,\n    opt: { name?: string } = {},\n  ): Promise<T> {\n    return this.enqueue(task, {\n      immediate: this.currentTask != null,\n      name: opt.name,\n    })\n  }\n\n  /** Remove all tasks from queue that are not yet executing. */\n  async cancelAll(_unblock = true) {\n    this.log('cancelAll')\n    void this.emit('didCancel')\n    const resolver = this.queue.map(task => task.resolve)\n    this.queue = []\n    resolver.forEach(r => r(undefined))\n    await this.wait()\n  }\n\n  /** Pause execution after current task is finished. */\n  async pause() {\n    this.log('pause')\n    this.paused = true\n    await this.wait()\n  }\n\n  /** Resume paused queue. */\n  resume() {\n    this.log('resume')\n    this.paused = false\n    void this.performNext()\n  }\n\n  /** Wait for all tasks to finish */\n  async wait() {\n    this.log('wait')\n    if (this.currentTask == null && (this.queue.length === 0 || this.paused))\n      return\n\n    return new Promise((resolve) => {\n      this.waitToFinish.push(resolve)\n    })\n  }\n\n  public get isPaused(): boolean {\n    return this.paused\n  }\n\n  public get hasTasks(): boolean {\n    return this.queue.length !== 0\n  }\n}\n"],"mappings":"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"}