mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-02-01 00:18:14 +01:00
Update:Remove node-cron dependency
This commit is contained in:
parent
26ef275ab4
commit
b7e546f2f5
14
package-lock.json
generated
14
package-lock.json
generated
@ -22,7 +22,6 @@
|
||||
"htmlparser2": "^8.0.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"libgen": "^2.1.0",
|
||||
"node-cron": "^3.0.0",
|
||||
"node-ffprobe": "^3.0.0",
|
||||
"node-stream-zip": "^1.15.0",
|
||||
"proper-lockfile": "^4.1.2",
|
||||
@ -1381,14 +1380,6 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/node-cron": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.1.tgz",
|
||||
"integrity": "sha512-RAWZTNn2M5KDIUV/389UX0EXsqvdFAwc9QwHQceh0Ga56dygqSRthqIjwpgZsoDspHGt2rkHdk9Z4RgfPMdALw==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-ffprobe": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-ffprobe/-/node-ffprobe-3.0.0.tgz",
|
||||
@ -3022,11 +3013,6 @@
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
|
||||
},
|
||||
"node-cron": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.1.tgz",
|
||||
"integrity": "sha512-RAWZTNn2M5KDIUV/389UX0EXsqvdFAwc9QwHQceh0Ga56dygqSRthqIjwpgZsoDspHGt2rkHdk9Z4RgfPMdALw=="
|
||||
},
|
||||
"node-ffprobe": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-ffprobe/-/node-ffprobe-3.0.0.tgz",
|
||||
|
@ -41,7 +41,6 @@
|
||||
"htmlparser2": "^8.0.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"libgen": "^2.1.0",
|
||||
"node-cron": "^3.0.0",
|
||||
"node-ffprobe": "^3.0.0",
|
||||
"node-stream-zip": "^1.15.0",
|
||||
"proper-lockfile": "^4.1.2",
|
||||
|
19
server/libs/nodeCron/background-scheduled-task/daemon.js
Normal file
19
server/libs/nodeCron/background-scheduled-task/daemon.js
Normal file
@ -0,0 +1,19 @@
|
||||
const ScheduledTask = require('../scheduled-task');
|
||||
|
||||
let scheduledTask;
|
||||
|
||||
function register(message){
|
||||
const script = require(message.path);
|
||||
scheduledTask = new ScheduledTask(message.cron, script.task, message.options);
|
||||
scheduledTask.on('task-done', (result) => {
|
||||
process.send({ type: 'task-done', result});
|
||||
});
|
||||
process.send({ type: 'registred' });
|
||||
}
|
||||
|
||||
process.on('message', (message) => {
|
||||
switch(message.type){
|
||||
case 'register':
|
||||
return register(message);
|
||||
}
|
||||
});
|
67
server/libs/nodeCron/background-scheduled-task/index.js
Normal file
67
server/libs/nodeCron/background-scheduled-task/index.js
Normal file
@ -0,0 +1,67 @@
|
||||
const EventEmitter = require('events');
|
||||
const path = require('path');
|
||||
const { fork } = require('child_process');
|
||||
const { getId } = require('../../../utils/index')
|
||||
|
||||
const daemonPath = `${__dirname}/daemon.js`;
|
||||
|
||||
class BackgroundScheduledTask extends EventEmitter {
|
||||
constructor(cronExpression, taskPath, options) {
|
||||
super();
|
||||
if (!options) {
|
||||
options = {
|
||||
scheduled: true,
|
||||
recoverMissedExecutions: false,
|
||||
};
|
||||
}
|
||||
this.cronExpression = cronExpression;
|
||||
this.taskPath = taskPath;
|
||||
this.options = options;
|
||||
this.options.name = this.options.name || getId()
|
||||
|
||||
if (options.scheduled) {
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
|
||||
start() {
|
||||
this.stop();
|
||||
this.forkProcess = fork(daemonPath);
|
||||
|
||||
this.forkProcess.on('message', (message) => {
|
||||
switch (message.type) {
|
||||
case 'task-done':
|
||||
this.emit('task-done', message.result);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
let options = this.options;
|
||||
options.scheduled = true;
|
||||
|
||||
this.forkProcess.send({
|
||||
type: 'register',
|
||||
path: path.resolve(this.taskPath),
|
||||
cron: this.cronExpression,
|
||||
options: options
|
||||
});
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (this.forkProcess) {
|
||||
this.forkProcess.kill();
|
||||
}
|
||||
}
|
||||
|
||||
pid() {
|
||||
if (this.forkProcess) {
|
||||
return this.forkProcess.pid;
|
||||
}
|
||||
}
|
||||
|
||||
isRunning() {
|
||||
return !this.forkProcess.killed;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BackgroundScheduledTask;
|
@ -0,0 +1,21 @@
|
||||
'use strict';
|
||||
module.exports = (() => {
|
||||
function convertAsterisk(expression, replecement){
|
||||
if(expression.indexOf('*') !== -1){
|
||||
return expression.replace('*', replecement);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
function convertAsterisksToRanges(expressions){
|
||||
expressions[0] = convertAsterisk(expressions[0], '0-59');
|
||||
expressions[1] = convertAsterisk(expressions[1], '0-59');
|
||||
expressions[2] = convertAsterisk(expressions[2], '0-23');
|
||||
expressions[3] = convertAsterisk(expressions[3], '1-31');
|
||||
expressions[4] = convertAsterisk(expressions[4], '1-12');
|
||||
expressions[5] = convertAsterisk(expressions[5], '0-6');
|
||||
return expressions;
|
||||
}
|
||||
|
||||
return convertAsterisksToRanges;
|
||||
})();
|
69
server/libs/nodeCron/convert-expression/index.js
Normal file
69
server/libs/nodeCron/convert-expression/index.js
Normal file
@ -0,0 +1,69 @@
|
||||
'use strict';
|
||||
|
||||
// SOURCE: https://github.com/node-cron/node-cron
|
||||
// LICENSE: https://github.com/node-cron/node-cron/blob/master/LICENSE.md
|
||||
|
||||
const monthNamesConversion = require('./month-names-conversion');
|
||||
const weekDayNamesConversion = require('./week-day-names-conversion');
|
||||
const convertAsterisksToRanges = require('./asterisk-to-range-conversion');
|
||||
const convertRanges = require('./range-conversion');
|
||||
const convertSteps = require('./step-values-conversion');
|
||||
|
||||
module.exports = (() => {
|
||||
|
||||
function appendSeccondExpression(expressions) {
|
||||
if (expressions.length === 5) {
|
||||
return ['0'].concat(expressions);
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
function removeSpaces(str) {
|
||||
return str.replace(/\s{2,}/g, ' ').trim();
|
||||
}
|
||||
|
||||
// Function that takes care of normalization.
|
||||
function normalizeIntegers(expressions) {
|
||||
for (let i = 0; i < expressions.length; i++) {
|
||||
const numbers = expressions[i].split(',');
|
||||
for (let j = 0; j < numbers.length; j++) {
|
||||
numbers[j] = parseInt(numbers[j]);
|
||||
}
|
||||
expressions[i] = numbers;
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
/*
|
||||
* The node-cron core allows only numbers (including multiple numbers e.g 1,2).
|
||||
* This module is going to translate the month names, week day names and ranges
|
||||
* to integers relatives.
|
||||
*
|
||||
* Month names example:
|
||||
* - expression 0 1 1 January,Sep *
|
||||
* - Will be translated to 0 1 1 1,9 *
|
||||
*
|
||||
* Week day names example:
|
||||
* - expression 0 1 1 2 Monday,Sat
|
||||
* - Will be translated to 0 1 1 1,5 *
|
||||
*
|
||||
* Ranges example:
|
||||
* - expression 1-5 * * * *
|
||||
* - Will be translated to 1,2,3,4,5 * * * *
|
||||
*/
|
||||
function interprete(expression) {
|
||||
let expressions = removeSpaces(expression).split(' ');
|
||||
expressions = appendSeccondExpression(expressions);
|
||||
expressions[4] = monthNamesConversion(expressions[4]);
|
||||
expressions[5] = weekDayNamesConversion(expressions[5]);
|
||||
expressions = convertAsterisksToRanges(expressions);
|
||||
expressions = convertRanges(expressions);
|
||||
expressions = convertSteps(expressions);
|
||||
|
||||
expressions = normalizeIntegers(expressions);
|
||||
|
||||
return expressions.join(' ');
|
||||
}
|
||||
|
||||
return interprete;
|
||||
})();
|
@ -0,0 +1,22 @@
|
||||
'use strict';
|
||||
module.exports = (() => {
|
||||
const months = ['january','february','march','april','may','june','july',
|
||||
'august','september','october','november','december'];
|
||||
const shortMonths = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug',
|
||||
'sep', 'oct', 'nov', 'dec'];
|
||||
|
||||
function convertMonthName(expression, items){
|
||||
for(let i = 0; i < items.length; i++){
|
||||
expression = expression.replace(new RegExp(items[i], 'gi'), parseInt(i, 10) + 1);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
function interprete(monthExpression){
|
||||
monthExpression = convertMonthName(monthExpression, months);
|
||||
monthExpression = convertMonthName(monthExpression, shortMonths);
|
||||
return monthExpression;
|
||||
}
|
||||
|
||||
return interprete;
|
||||
})();
|
39
server/libs/nodeCron/convert-expression/range-conversion.js
Normal file
39
server/libs/nodeCron/convert-expression/range-conversion.js
Normal file
@ -0,0 +1,39 @@
|
||||
'use strict';
|
||||
module.exports = ( () => {
|
||||
function replaceWithRange(expression, text, init, end) {
|
||||
|
||||
const numbers = [];
|
||||
let last = parseInt(end);
|
||||
let first = parseInt(init);
|
||||
|
||||
if(first > last){
|
||||
last = parseInt(init);
|
||||
first = parseInt(end);
|
||||
}
|
||||
|
||||
for(let i = first; i <= last; i++) {
|
||||
numbers.push(i);
|
||||
}
|
||||
|
||||
return expression.replace(new RegExp(text, 'i'), numbers.join());
|
||||
}
|
||||
|
||||
function convertRange(expression){
|
||||
const rangeRegEx = /(\d+)-(\d+)/;
|
||||
let match = rangeRegEx.exec(expression);
|
||||
while(match !== null && match.length > 0){
|
||||
expression = replaceWithRange(expression, match[0], match[1], match[2]);
|
||||
match = rangeRegEx.exec(expression);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
function convertAllRanges(expressions){
|
||||
for(let i = 0; i < expressions.length; i++){
|
||||
expressions[i] = convertRange(expressions[i]);
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
return convertAllRanges;
|
||||
})();
|
@ -0,0 +1,30 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = (() => {
|
||||
function convertSteps(expressions){
|
||||
var stepValuePattern = /^(.+)\/(\w+)$/;
|
||||
for(var i = 0; i < expressions.length; i++){
|
||||
var match = stepValuePattern.exec(expressions[i]);
|
||||
var isStepValue = match !== null && match.length > 0;
|
||||
if(isStepValue){
|
||||
var baseDivider = match[2];
|
||||
if(isNaN(baseDivider)){
|
||||
throw baseDivider + ' is not a valid step value';
|
||||
}
|
||||
var values = match[1].split(',');
|
||||
var stepValues = [];
|
||||
var divider = parseInt(baseDivider, 10);
|
||||
for(var j = 0; j <= values.length; j++){
|
||||
var value = parseInt(values[j], 10);
|
||||
if(value % divider === 0){
|
||||
stepValues.push(value);
|
||||
}
|
||||
}
|
||||
expressions[i] = stepValues.join(',');
|
||||
}
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
return convertSteps;
|
||||
})();
|
@ -0,0 +1,21 @@
|
||||
'use strict';
|
||||
module.exports = (() => {
|
||||
const weekDays = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday',
|
||||
'friday', 'saturday'];
|
||||
const shortWeekDays = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
|
||||
|
||||
function convertWeekDayName(expression, items){
|
||||
for(let i = 0; i < items.length; i++){
|
||||
expression = expression.replace(new RegExp(items[i], 'gi'), parseInt(i, 10));
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
function convertWeekDays(expression){
|
||||
expression = expression.replace('7', '0');
|
||||
expression = convertWeekDayName(expression, weekDays);
|
||||
return convertWeekDayName(expression, shortWeekDays);
|
||||
}
|
||||
|
||||
return convertWeekDays;
|
||||
})();
|
64
server/libs/nodeCron/index.js
Normal file
64
server/libs/nodeCron/index.js
Normal file
@ -0,0 +1,64 @@
|
||||
'use strict';
|
||||
|
||||
const ScheduledTask = require('./scheduled-task');
|
||||
const BackgroundScheduledTask = require('./background-scheduled-task');
|
||||
const validation = require('./pattern-validation');
|
||||
const storage = require('./storage');
|
||||
|
||||
/**
|
||||
* @typedef {Object} CronScheduleOptions
|
||||
* @prop {boolean} [scheduled] if a scheduled task is ready and running to be
|
||||
* performed when the time matches the cron expression.
|
||||
* @prop {string} [timezone] the timezone to execute the task in.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new task to execute the given function when the cron
|
||||
* expression ticks.
|
||||
*
|
||||
* @param {string} expression The cron expression.
|
||||
* @param {Function} func The task to be executed.
|
||||
* @param {CronScheduleOptions} [options] A set of options for the scheduled task.
|
||||
* @returns {ScheduledTask} The scheduled task.
|
||||
*/
|
||||
function schedule(expression, func, options) {
|
||||
const task = createTask(expression, func, options);
|
||||
|
||||
storage.save(task);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
function createTask(expression, func, options) {
|
||||
if (typeof func === 'string')
|
||||
return new BackgroundScheduledTask(expression, func, options);
|
||||
|
||||
return new ScheduledTask(expression, func, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a cron expression is valid.
|
||||
*
|
||||
* @param {string} expression The cron expression.
|
||||
* @returns {boolean} Whether the expression is valid or not.
|
||||
*/
|
||||
function validate(expression) {
|
||||
try {
|
||||
validation(expression);
|
||||
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scheduled tasks.
|
||||
*
|
||||
* @returns {ScheduledTask[]} The scheduled tasks.
|
||||
*/
|
||||
function getTasks() {
|
||||
return storage.getTasks();
|
||||
}
|
||||
|
||||
module.exports = { schedule, validate, getTasks };
|
124
server/libs/nodeCron/pattern-validation.js
Normal file
124
server/libs/nodeCron/pattern-validation.js
Normal file
@ -0,0 +1,124 @@
|
||||
'use strict';
|
||||
|
||||
const convertExpression = require('./convert-expression');
|
||||
|
||||
const validationRegex = /^(?:\d+|\*|\*\/\d+)$/;
|
||||
|
||||
/**
|
||||
* @param {string} expression The Cron-Job expression.
|
||||
* @param {number} min The minimum value.
|
||||
* @param {number} max The maximum value.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isValidExpression(expression, min, max) {
|
||||
const options = expression.split(',');
|
||||
|
||||
for (const option of options) {
|
||||
const optionAsInt = parseInt(option, 10);
|
||||
|
||||
if (
|
||||
(!Number.isNaN(optionAsInt) &&
|
||||
(optionAsInt < min || optionAsInt > max)) ||
|
||||
!validationRegex.test(option)
|
||||
)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} expression The Cron-Job expression.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isInvalidSecond(expression) {
|
||||
return !isValidExpression(expression, 0, 59);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} expression The Cron-Job expression.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isInvalidMinute(expression) {
|
||||
return !isValidExpression(expression, 0, 59);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} expression The Cron-Job expression.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isInvalidHour(expression) {
|
||||
return !isValidExpression(expression, 0, 23);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} expression The Cron-Job expression.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isInvalidDayOfMonth(expression) {
|
||||
return !isValidExpression(expression, 1, 31);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} expression The Cron-Job expression.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isInvalidMonth(expression) {
|
||||
return !isValidExpression(expression, 1, 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} expression The Cron-Job expression.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isInvalidWeekDay(expression) {
|
||||
return !isValidExpression(expression, 0, 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} patterns The Cron-Job expression patterns.
|
||||
* @param {string[]} executablePatterns The executable Cron-Job expression
|
||||
* patterns.
|
||||
* @returns {void}
|
||||
*/
|
||||
function validateFields(patterns, executablePatterns) {
|
||||
if (isInvalidSecond(executablePatterns[0]))
|
||||
throw new Error(`${patterns[0]} is a invalid expression for second`);
|
||||
|
||||
if (isInvalidMinute(executablePatterns[1]))
|
||||
throw new Error(`${patterns[1]} is a invalid expression for minute`);
|
||||
|
||||
if (isInvalidHour(executablePatterns[2]))
|
||||
throw new Error(`${patterns[2]} is a invalid expression for hour`);
|
||||
|
||||
if (isInvalidDayOfMonth(executablePatterns[3]))
|
||||
throw new Error(
|
||||
`${patterns[3]} is a invalid expression for day of month`
|
||||
);
|
||||
|
||||
if (isInvalidMonth(executablePatterns[4]))
|
||||
throw new Error(`${patterns[4]} is a invalid expression for month`);
|
||||
|
||||
if (isInvalidWeekDay(executablePatterns[5]))
|
||||
throw new Error(`${patterns[5]} is a invalid expression for week day`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a Cron-Job expression pattern.
|
||||
*
|
||||
* @param {string} pattern The Cron-Job expression pattern.
|
||||
* @returns {void}
|
||||
*/
|
||||
function validate(pattern) {
|
||||
if (typeof pattern !== 'string')
|
||||
throw new TypeError('pattern must be a string!');
|
||||
|
||||
const patterns = pattern.split(' ');
|
||||
const executablePatterns = convertExpression(pattern).split(' ');
|
||||
|
||||
if (patterns.length === 5) patterns.unshift('0');
|
||||
|
||||
validateFields(patterns, executablePatterns);
|
||||
}
|
||||
|
||||
module.exports = validate;
|
51
server/libs/nodeCron/scheduled-task.js
Normal file
51
server/libs/nodeCron/scheduled-task.js
Normal file
@ -0,0 +1,51 @@
|
||||
'use strict';
|
||||
|
||||
const EventEmitter = require('events');
|
||||
const Task = require('./task');
|
||||
const Scheduler = require('./scheduler');
|
||||
const { getId } = require('../../utils/index')
|
||||
|
||||
class ScheduledTask extends EventEmitter {
|
||||
constructor(cronExpression, func, options) {
|
||||
super();
|
||||
if (!options) {
|
||||
options = {
|
||||
scheduled: true,
|
||||
recoverMissedExecutions: false
|
||||
};
|
||||
}
|
||||
|
||||
this.options = options;
|
||||
this.options.name = this.options.name || getId()
|
||||
|
||||
this._task = new Task(func);
|
||||
this._scheduler = new Scheduler(cronExpression, options.timezone, options.recoverMissedExecutions);
|
||||
|
||||
this._scheduler.on('scheduled-time-matched', (now) => {
|
||||
this.now(now);
|
||||
});
|
||||
|
||||
if (options.scheduled !== false) {
|
||||
this._scheduler.start();
|
||||
}
|
||||
|
||||
if (options.runOnInit === true) {
|
||||
this.now('init');
|
||||
}
|
||||
}
|
||||
|
||||
now(now = 'manual') {
|
||||
let result = this._task.execute(now);
|
||||
this.emit('task-done', result);
|
||||
}
|
||||
|
||||
start() {
|
||||
this._scheduler.start();
|
||||
}
|
||||
|
||||
stop() {
|
||||
this._scheduler.stop();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ScheduledTask;
|
49
server/libs/nodeCron/scheduler.js
Normal file
49
server/libs/nodeCron/scheduler.js
Normal file
@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
const EventEmitter = require('events');
|
||||
const TimeMatcher = require('./time-matcher');
|
||||
|
||||
class Scheduler extends EventEmitter{
|
||||
constructor(pattern, timezone, autorecover){
|
||||
super();
|
||||
this.timeMatcher = new TimeMatcher(pattern, timezone);
|
||||
this.autorecover = autorecover;
|
||||
}
|
||||
|
||||
start(){
|
||||
// clear timeout if exists
|
||||
this.stop();
|
||||
|
||||
let lastCheck = process.hrtime();
|
||||
let lastExecution = this.timeMatcher.apply(new Date());
|
||||
|
||||
const matchTime = () => {
|
||||
const delay = 1000;
|
||||
const elapsedTime = process.hrtime(lastCheck);
|
||||
const elapsedMs = (elapsedTime[0] * 1e9 + elapsedTime[1]) / 1e6;
|
||||
const missedExecutions = Math.floor(elapsedMs / 1000);
|
||||
|
||||
for(let i = missedExecutions; i >= 0; i--){
|
||||
const date = new Date(new Date().getTime() - i * 1000);
|
||||
let date_tmp = this.timeMatcher.apply(date);
|
||||
if(lastExecution.getTime() < date_tmp.getTime() && (i === 0 || this.autorecover) && this.timeMatcher.match(date)){
|
||||
this.emit('scheduled-time-matched', date_tmp);
|
||||
date_tmp.setMilliseconds(0);
|
||||
lastExecution = date_tmp;
|
||||
}
|
||||
}
|
||||
lastCheck = process.hrtime();
|
||||
this.timeout = setTimeout(matchTime, delay);
|
||||
};
|
||||
matchTime();
|
||||
}
|
||||
|
||||
stop(){
|
||||
if(this.timeout){
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
this.timeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Scheduler;
|
19
server/libs/nodeCron/storage.js
Normal file
19
server/libs/nodeCron/storage.js
Normal file
@ -0,0 +1,19 @@
|
||||
module.exports = (() => {
|
||||
if(!global.scheduledTasks){
|
||||
global.scheduledTasks = new Map();
|
||||
}
|
||||
|
||||
return {
|
||||
save: (task) => {
|
||||
if(!task.options){
|
||||
const uuid = require('uuid');
|
||||
task.options = {};
|
||||
task.options.name = uuid.v4();
|
||||
}
|
||||
global.scheduledTasks.set(task.options.name, task);
|
||||
},
|
||||
getTasks: () => {
|
||||
return global.scheduledTasks;
|
||||
}
|
||||
};
|
||||
})();
|
34
server/libs/nodeCron/task.js
Normal file
34
server/libs/nodeCron/task.js
Normal file
@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
const EventEmitter = require('events');
|
||||
|
||||
class Task extends EventEmitter{
|
||||
constructor(execution){
|
||||
super();
|
||||
if(typeof execution !== 'function') {
|
||||
throw 'execution must be a function';
|
||||
}
|
||||
this._execution = execution;
|
||||
}
|
||||
|
||||
execute(now) {
|
||||
let exec;
|
||||
try {
|
||||
exec = this._execution(now);
|
||||
} catch (error) {
|
||||
return this.emit('task-failed', error);
|
||||
}
|
||||
|
||||
if (exec instanceof Promise) {
|
||||
return exec
|
||||
.then(() => this.emit('task-finished'))
|
||||
.catch((error) => this.emit('task-failed', error));
|
||||
} else {
|
||||
this.emit('task-finished');
|
||||
return exec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Task;
|
||||
|
54
server/libs/nodeCron/time-matcher.js
Normal file
54
server/libs/nodeCron/time-matcher.js
Normal file
@ -0,0 +1,54 @@
|
||||
const validatePattern = require('./pattern-validation');
|
||||
const convertExpression = require('./convert-expression');
|
||||
|
||||
function matchPattern(pattern, value){
|
||||
if( pattern.indexOf(',') !== -1 ){
|
||||
const patterns = pattern.split(',');
|
||||
return patterns.indexOf(value.toString()) !== -1;
|
||||
}
|
||||
return pattern === value.toString();
|
||||
}
|
||||
|
||||
class TimeMatcher{
|
||||
constructor(pattern, timezone){
|
||||
validatePattern(pattern);
|
||||
this.pattern = convertExpression(pattern);
|
||||
this.timezone = timezone;
|
||||
this.expressions = this.pattern.split(' ');
|
||||
}
|
||||
|
||||
match(date){
|
||||
date = this.apply(date);
|
||||
|
||||
const runOnSecond = matchPattern(this.expressions[0], date.getSeconds());
|
||||
const runOnMinute = matchPattern(this.expressions[1], date.getMinutes());
|
||||
const runOnHour = matchPattern(this.expressions[2], date.getHours());
|
||||
const runOnDay = matchPattern(this.expressions[3], date.getDate());
|
||||
const runOnMonth = matchPattern(this.expressions[4], date.getMonth() + 1);
|
||||
const runOnWeekDay = matchPattern(this.expressions[5], date.getDay());
|
||||
|
||||
return runOnSecond && runOnMinute && runOnHour && runOnDay && runOnMonth && runOnWeekDay;
|
||||
}
|
||||
|
||||
apply(date){
|
||||
if(this.timezone){
|
||||
const dtf = new Intl.DateTimeFormat('en-US', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hourCycle: 'h23',
|
||||
fractionalSecondDigits: 3,
|
||||
timeZone: this.timezone
|
||||
});
|
||||
|
||||
return new Date(dtf.format(date));
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TimeMatcher;
|
@ -1,6 +1,6 @@
|
||||
const Path = require('path')
|
||||
|
||||
const cron = require('node-cron')
|
||||
const cron = require('../libs/nodeCron')
|
||||
const fs = require('fs-extra')
|
||||
const archiver = require('archiver')
|
||||
const StreamZip = require('node-stream-zip')
|
||||
@ -276,7 +276,7 @@ class BackupManager {
|
||||
reject(err)
|
||||
})
|
||||
archive.on('progress', ({ fs: fsobj }) => {
|
||||
const maxBackupSizeInBytes = this.serverSettings.maxBackupSize * 1000 * 1000 * 1000
|
||||
const maxBackupSizeInBytes = this.serverSettings.maxBackupSize * 1000 * 1000 * 1000
|
||||
if (fsobj.processedBytes > maxBackupSizeInBytes) {
|
||||
Logger.error(`[BackupManager] Archiver is too large - aborting to prevent endless loop, Bytes Processed: ${fsobj.processedBytes}`)
|
||||
archive.abort()
|
||||
|
@ -1,5 +1,5 @@
|
||||
const fs = require('fs-extra')
|
||||
const cron = require('node-cron')
|
||||
const cron = require('../libs/nodeCron')
|
||||
const axios = require('axios')
|
||||
|
||||
const { parsePodcastRssFeedXml } = require('../utils/podcastUtils')
|
||||
|
Loading…
Reference in New Issue
Block a user