lib/amd/src/local/process_monitor/processqueue.js

  1. // This file is part of Moodle - http://moodle.org/
  2. //
  3. // Moodle is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. //
  8. // Moodle is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  15. import {debounce} from 'core/utils';
  16. import {LoadingProcess} from 'core/local/process_monitor/loadingprocess';
  17. import log from 'core/log';
  18. const TOASTSTIMER = 3000;
  19. /**
  20. * A process queue manager.
  21. *
  22. * Adding process to the queue will guarante process are executed in sequence.
  23. *
  24. * @module core/local/process_monitor/processqueue
  25. * @class ProcessQueue
  26. * @copyright 2022 Ferran Recio <ferran@moodle.com>
  27. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  28. */
  29. export class ProcessQueue {
  30. /** @var {Array} pending the pending queue. */
  31. pending = [];
  32. /** @var {LoadingProcess} current the current uploading process. */
  33. currentProcess = null;
  34. /**
  35. * Class constructor.
  36. * @param {ProcessMonitorManager} manager the monitor manager
  37. */
  38. constructor(manager) {
  39. this.manager = manager;
  40. this.cleanFinishedProcesses = debounce(
  41. () => manager.dispatch('cleanFinishedProcesses'),
  42. TOASTSTIMER
  43. );
  44. }
  45. /**
  46. * Adds a new pending upload to the queue.
  47. * @param {String} processName the process name
  48. * @param {Function} processor the execution function
  49. */
  50. addPending(processName, processor) {
  51. const process = new LoadingProcess(this.manager, {name: processName});
  52. process.setExtraData({
  53. processor,
  54. });
  55. process.onFinish((uploadedFile) => {
  56. if (this.currentProcess?.id !== uploadedFile.id) {
  57. return;
  58. }
  59. this._discardCurrent();
  60. });
  61. this.pending.push(process);
  62. this._continueProcessing();
  63. }
  64. /**
  65. * Adds a new pending upload to the queue.
  66. * @param {String} processName the file info
  67. * @param {String} errorMessage the file processor
  68. */
  69. addError(processName, errorMessage) {
  70. const process = new LoadingProcess(this.manager, {name: processName});
  71. process.setError(errorMessage);
  72. }
  73. /**
  74. * Discard the current process and execute the next one if any.
  75. */
  76. _discardCurrent() {
  77. if (this.currentProcess) {
  78. this.currentProcess = null;
  79. }
  80. this.cleanFinishedProcesses();
  81. this._continueProcessing();
  82. }
  83. /**
  84. * Return the current file uploader.
  85. * @return {FileUploader}
  86. */
  87. _currentProcessor() {
  88. return this.currentProcess.data.processor;
  89. }
  90. /**
  91. * Continue the queue processing if no current process is defined.
  92. */
  93. async _continueProcessing() {
  94. if (this.currentProcess !== null || this.pending.length === 0) {
  95. return;
  96. }
  97. this.currentProcess = this.pending.shift();
  98. try {
  99. const processor = this._currentProcessor();
  100. await processor(this.currentProcess);
  101. } catch (error) {
  102. this.currentProcess.setError(error.message);
  103. log.error(error);
  104. }
  105. }
  106. }