webservices/node_modules/cronosjs/dist-src/scheduler.js

129 lines
4.1 KiB
JavaScript

const maxTimeout = Math.pow(2, 31) - 1;
const scheduledTasks = [];
let runningTimer = null;
function addTask(task) {
if (task['_timestamp'] !== undefined) {
const insertIndex = scheduledTasks.findIndex(t => t['_timestamp'] < task['_timestamp']);
if (insertIndex >= 0)
scheduledTasks.splice(insertIndex, 0, task);
else
scheduledTasks.push(task);
}
}
function removeTask(task) {
const removeIndex = scheduledTasks.indexOf(task);
if (removeIndex >= 0)
scheduledTasks.splice(removeIndex, 1);
if (scheduledTasks.length === 0 && runningTimer) {
clearTimeout(runningTimer);
runningTimer = null;
}
}
function runScheduledTasks(skipRun = false) {
if (runningTimer)
clearTimeout(runningTimer);
const now = Date.now();
const removeIndex = scheduledTasks.findIndex(task => task['_timestamp'] <= now);
const tasksToRun = removeIndex >= 0 ? scheduledTasks.splice(removeIndex) : [];
for (let task of tasksToRun) {
if (!skipRun)
task['_runTask']();
if (task.isRunning) {
task['_updateTimestamp']();
addTask(task);
}
}
const nextTask = scheduledTasks[scheduledTasks.length - 1];
if (nextTask) {
runningTimer = setTimeout(runScheduledTasks, Math.min(nextTask['_timestamp'] - Date.now(), maxTimeout));
}
else
runningTimer = null;
}
export function refreshSchedulerTimer() {
for (const task of scheduledTasks) {
task['_updateTimestamp']();
if (!task.isRunning)
removeTask(task);
}
scheduledTasks.sort((a, b) => b['_timestamp'] - a['_timestamp']);
runScheduledTasks(true);
}
class DateArraySequence {
constructor(dateLikes) {
this._dates = dateLikes.map(dateLike => {
const date = new Date(dateLike);
if (isNaN(date.getTime()))
throw new Error('Invalid date');
return date;
}).sort((a, b) => a.getTime() - b.getTime());
}
nextDate(afterDate) {
const nextIndex = this._dates.findIndex(d => d > afterDate);
return nextIndex === -1 ? null : this._dates[nextIndex];
}
}
export class CronosTask {
constructor(sequenceOrDates) {
this._listeners = {
'started': new Set(),
'stopped': new Set(),
'run': new Set(),
'ended': new Set(),
};
if (Array.isArray(sequenceOrDates))
this._sequence = new DateArraySequence(sequenceOrDates);
else if (typeof sequenceOrDates === 'string' ||
typeof sequenceOrDates === 'number' ||
sequenceOrDates instanceof Date)
this._sequence = new DateArraySequence([sequenceOrDates]);
else
this._sequence = sequenceOrDates;
}
start() {
if (!this.isRunning) {
this._updateTimestamp();
addTask(this);
runScheduledTasks();
if (this.isRunning)
this._emit('started');
}
return this;
}
stop() {
if (this.isRunning) {
this._timestamp = undefined;
removeTask(this);
this._emit('stopped');
}
return this;
}
get nextRun() {
return this.isRunning ? new Date(this._timestamp) : undefined;
}
get isRunning() {
return this._timestamp !== undefined;
}
_runTask() {
this._emit('run', this._timestamp);
}
_updateTimestamp() {
const nextDate = this._sequence.nextDate(new Date());
this._timestamp = nextDate ? nextDate.getTime() : undefined;
if (!this.isRunning)
this._emit('ended');
}
on(event, listener) {
this._listeners[event].add(listener);
return this;
}
off(event, listener) {
this._listeners[event].delete(listener);
return this;
}
_emit(event, ...args) {
this._listeners[event].forEach((listener) => {
listener.call(this, ...args);
});
}
}