You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

109 lines
2.4 KiB

  1. // Copyright (c) 2018-2020, Zpalmtree
  2. //
  3. // Please see the included LICENSE file for more information.
  4. import { LogCategory, logger, LogLevel } from './Logger';
  5. export class Metronome {
  6. /**
  7. * The function to run
  8. */
  9. private readonly func: () => any;
  10. /**
  11. * How often to run the function (in milliseconds)
  12. */
  13. private readonly interval: number;
  14. /**
  15. * Can be either number or NodeJS.Timer depending on env
  16. */
  17. private timer: any;
  18. private shouldStop: boolean = true;
  19. /**
  20. * Is code currently executing
  21. */
  22. private inTick: boolean = false;
  23. private started: boolean = false;
  24. /**
  25. * Function to run when stopping, and tick func has completed
  26. */
  27. private finishedFunc: (() => void) | undefined = undefined;
  28. /**
  29. * @param func The function to run
  30. * @param interval How often to run the function
  31. */
  32. constructor(func: () => any, interval: number) {
  33. this.func = func;
  34. this.interval = interval;
  35. }
  36. /**
  37. * Start running the function
  38. */
  39. public async start(): Promise<void> {
  40. if (this.started) {
  41. return;
  42. }
  43. this.started = true;
  44. this.shouldStop = false;
  45. await this.tick();
  46. }
  47. /**
  48. * Stop running the function
  49. */
  50. public stop(): Promise<void> {
  51. return new Promise((resolve) => {
  52. this.shouldStop = true;
  53. clearTimeout(this.timer);
  54. if (this.inTick) {
  55. this.finishedFunc = () => {
  56. this.started = false;
  57. this.finishedFunc = undefined;
  58. resolve();
  59. };
  60. } else {
  61. this.started = false;
  62. resolve();
  63. }
  64. });
  65. }
  66. /**
  67. * Run the function, then recurse
  68. */
  69. private async tick(): Promise<void> {
  70. this.inTick = true;
  71. try {
  72. await this.func();
  73. } catch (err) {
  74. logger.log(
  75. 'Threw exception processing tick function: ' + err,
  76. LogLevel.ERROR,
  77. LogCategory.SYNC,
  78. );
  79. }
  80. if (!this.shouldStop) {
  81. this.timer = setTimeout(this.tick.bind(this), this.interval);
  82. } else {
  83. if (this.finishedFunc) {
  84. this.finishedFunc();
  85. }
  86. }
  87. this.inTick = false;
  88. }
  89. }