Discord-InterChat/InterChat

View on GitHub
src/services/SchedulerService.ts

Summary

Maintainability
A
0 mins
Test Coverage
export default class Scheduler {
  private tasks: Map<string, { task: () => void; ms: number; timeout: NodeJS.Timeout }>;

  constructor() {
    this.tasks = new Map();
  }

  /**
   * Adds a recurring task to the scheduler.
   * @param taskName - The name of the task to add.
   * @param interval - The interval at which the task should be executed, in milliseconds or as a Date object.
   * @param task - The callback to execute as the task.
   * @throws An error if a task with the same name already exists.
   */
  addRecurringTask(name: string, ms: number, task: () => void): void {
    if (this.tasks.has(name)) {
      throw new Error(`Task with name ${name} already exists.`);
    }

    const intervalId = setInterval(task, ms);
    this.tasks.set(name, { task, ms, timeout: intervalId });
  }

  /**
   * Adds a new task to the scheduler.
   * @param name - The name of the task.
   * @param ms - The number of milliseconds after which the task should be executed, or a Date object representing the time at which the task should be executed.
   * @param callback - The callback to be executed when the task is run.
   * @throws An error if a task with the same name already exists.
   */
  addTask(name: string, _ms: number | Date, callback: () => void): void {
    if (this.tasks.has(name)) {
      throw new Error(`Task with name ${name} already exists.`);
    }

    const ms = _ms instanceof Date ? _ms.getTime() - Date.now() : _ms;

    // do not set big timeouts (usually bigints mean the timeout is as long as 1y)
    // NOTE: do not set loong timeouts throughout the code, only set timeouts that end in like a week or smth!
    if (ms > 2147483647) return;

    const timeout = setTimeout(callback, ms);
    this.tasks.set(name, { task: callback, ms, timeout });
  }

  /**
   * Stop a task by name, can be used for both recurring and timeout tasks
   * @param taskName The name of the task
   * @returns true if task was stopped, undefined if task was not found
   */
  stopTask(taskName: string): boolean {
    const taskInfo = this.tasks.get(taskName);
    if (!taskInfo) return false;

    clearInterval(taskInfo.timeout);
    clearTimeout(taskInfo.timeout);
    return this.tasks.delete(taskName);
  }

  /**
   * Stop all currently running tasks
   */
  stopAllTasks(): void {
    this.tasks.forEach((_, taskName) => this.stopTask(taskName));
  }

  hasTask(taskName: string): boolean {
    return this.tasks.has(taskName);
  }

  /**
   * Returns an array of currently running task names.
   */
  get taskNames(): string[] {
    return Array.from(this.tasks.keys());
  }
}