bhaskar 2 years ago
commit f7101cf39a

11
node_modules/.package-lock.json generated vendored

@ -7511,6 +7511,17 @@
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz",
"integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA=="
}, },
"node_modules/node-cron": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz",
"integrity": "sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ==",
"dependencies": {
"uuid": "8.3.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/node-fetch": { "node_modules/node-fetch": {
"version": "2.6.7", "version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",

@ -0,0 +1,17 @@
version: 2.1
jobs:
test:
docker:
- image: cimg/node:17.4
environment:
TZ: "America/Sao_Paulo"
steps:
- checkout
- run: npm install
- run: COVERALLS_GIT_BRANCH=$CIRCLE_BRANCH npm run check
workflows:
build:
jobs:
- test

@ -0,0 +1 @@
/node_modules/

@ -0,0 +1,20 @@
env:
es6: true
node: true
mocha: true
extends: 'eslint:recommended'
parserOptions:
ecmaVersion: 2018
rules:
indent:
- error
- 4
linebreak-style:
- error
- unix
quotes:
- error
- single
semi:
- error
- always

@ -0,0 +1,17 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
# Label to use when marking an issue as stale
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

@ -0,0 +1,7 @@
## ISC License
Copyright (c) 2016, Lucas Merencia \<lucas.merencia@gmail.com\>
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

247
node_modules/node-cron/README.md generated vendored

@ -0,0 +1,247 @@
# Node Cron
[![npm](https://img.shields.io/npm/l/node-cron.svg)](https://github.com/merencia/node-cron/blob/master/LICENSE.md)
[![npm](https://img.shields.io/npm/v/node-cron.svg)](https://img.shields.io/npm/v/node-cron.svg)
[![Coverage Status](https://coveralls.io/repos/github/node-cron/node-cron/badge.svg?branch=master)](https://coveralls.io/github/node-cron/node-cron?branch=master)
[![Code Climate](https://codeclimate.com/github/node-cron/node-cron/badges/gpa.svg)](https://codeclimate.com/github/merencia/node-cron)
[![Build Status](https://travis-ci.org/node-cron/node-cron.svg?branch=master)](https://travis-ci.org/merencia/node-cron)
[![Dependency Status](https://david-dm.org/node-cron/node-cron.svg)](https://david-dm.org/merencia/node-cron)
[![devDependency Status](https://david-dm.org/node-cron/node-cron/dev-status.svg)](https://david-dm.org/merencia/node-cron#info=devDependencies)
[![Backers on Open Collective](https://opencollective.com/node-cron/backers/badge.svg)](#backers)
[![Sponsors on Open Collective](https://opencollective.com/node-cron/sponsors/badge.svg)](#sponsors)
The node-cron module is tiny task scheduler in pure JavaScript for node.js based on [GNU crontab](https://www.gnu.org/software/mcron/manual/html_node/Crontab-file.html). This module allows you to schedule task in node.js using full crontab syntax.
**Need a job scheduler with support for worker threads and cron syntax?** Try out the [Bree](https://github.com/breejs/bree) job scheduler!
[![NPM](https://nodei.co/npm/node-cron.png?downloads=true&downloadRank=true&stars=false)](https://nodei.co/npm/node-cron/)
## Getting Started
Install node-cron using npm:
```console
npm install --save node-cron
```
Import node-cron and schedule a task:
```javascript
var cron = require('node-cron');
cron.schedule('* * * * *', () => {
console.log('running a task every minute');
});
```
## Cron Syntax
This is a quick reference to cron syntax and also shows the options supported by node-cron.
### Allowed fields
```
# ┌────────────── second (optional)
# │ ┌──────────── minute
# │ │ ┌────────── hour
# │ │ │ ┌──────── day of month
# │ │ │ │ ┌────── month
# │ │ │ │ │ ┌──── day of week
# │ │ │ │ │ │
# │ │ │ │ │ │
# * * * * * *
```
### Allowed values
| field | value |
|--------------|---------------------|
| second | 0-59 |
| minute | 0-59 |
| hour | 0-23 |
| day of month | 1-31 |
| month | 1-12 (or names) |
| day of week | 0-7 (or names, 0 or 7 are sunday) |
#### Using multiples values
You may use multiples values separated by comma:
```javascript
var cron = require('node-cron');
cron.schedule('1,2,4,5 * * * *', () => {
console.log('running every minute 1, 2, 4 and 5');
});
```
#### Using ranges
You may also define a range of values:
```javascript
var cron = require('node-cron');
cron.schedule('1-5 * * * *', () => {
console.log('running every minute to 1 from 5');
});
```
#### Using step values
Step values can be used in conjunction with ranges, following a range with '/' and a number. e.g: `1-10/2` that is the same as `2,4,6,8,10`. Steps are also permitted after an asterisk, so if you want to say “every two minutes”, just use `*/2`.
```javascript
var cron = require('node-cron');
cron.schedule('*/2 * * * *', () => {
console.log('running a task every two minutes');
});
```
#### Using names
For month and week day you also may use names or short names. e.g:
```javascript
var cron = require('node-cron');
cron.schedule('* * * January,September Sunday', () => {
console.log('running on Sundays of January and September');
});
```
Or with short names:
```javascript
var cron = require('node-cron');
cron.schedule('* * * Jan,Sep Sun', () => {
console.log('running on Sundays of January and September');
});
```
## Cron methods
### Schedule
Schedules given task to be executed whenever the cron expression ticks.
Arguments:
- **expression** `string`: Cron expression
- **function** `Function`: Task to be executed
- **options** `Object`: Optional configuration for job scheduling.
#### Options
- **scheduled**: A `boolean` to set if the created task is scheduled. Default `true`;
- **timezone**: The timezone that is used for job scheduling. See [IANA time zone database](https://www.iana.org/time-zones) for valid values, such as `Asia/Shanghai`, `Asia/Kolkata`, `America/Sao_Paulo`.
**Example**:
```js
var cron = require('node-cron');
cron.schedule('0 1 * * *', () => {
console.log('Running a job at 01:00 at America/Sao_Paulo timezone');
}, {
scheduled: true,
timezone: "America/Sao_Paulo"
});
```
## ScheduledTask methods
### Start
Starts the scheduled task.
```javascript
var cron = require('node-cron');
var task = cron.schedule('* * * * *', () => {
console.log('stopped task');
}, {
scheduled: false
});
task.start();
```
### Stop
The task won't be executed unless re-started.
```javascript
var cron = require('node-cron');
var task = cron.schedule('* * * * *', () => {
console.log('will execute every minute until stopped');
});
task.stop();
```
### Validate
Validate that the given string is a valid cron expression.
```javascript
var cron = require('node-cron');
var valid = cron.validate('59 * * * *');
var invalid = cron.validate('60 * * * *');
```
## Issues
Feel free to submit issues and enhancement requests [here](https://github.com/merencia/node-cron/issues).
## Contributing
In general, we follow the "fork-and-pull" Git workflow.
- Fork the repo on GitHub;
- Commit changes to a branch in your fork;
- Pull request "upstream" with your changes;
NOTE: Be sure to merge the latest from "upstream" before making a pull request!
Please do not contribute code you did not write yourself, unless you are certain you have the legal ability to do so. Also ensure all contributed code can be distributed under the ISC License.
## Contributors
This project exists thanks to all the people who contribute.
<a href="https://github.com/node-cron/node-cron/graphs/contributors"><img src="https://opencollective.com/node-cron/contributors.svg?width=890&button=false" /></a>
## Backers
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/node-cron#backer)]
<a href="https://opencollective.com/node-cron#backers" target="_blank"><img src="https://opencollective.com/node-cron/backers.svg?width=890"></a>
## Sponsors
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/node-cron#sponsor)]
<a href="https://opencollective.com/node-cron/sponsor/0/website" target="_blank"><img src="https://opencollective.com/node-cron/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/node-cron/sponsor/1/website" target="_blank"><img src="https://opencollective.com/node-cron/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/node-cron/sponsor/2/website" target="_blank"><img src="https://opencollective.com/node-cron/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/node-cron/sponsor/3/website" target="_blank"><img src="https://opencollective.com/node-cron/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/node-cron/sponsor/4/website" target="_blank"><img src="https://opencollective.com/node-cron/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/node-cron/sponsor/5/website" target="_blank"><img src="https://opencollective.com/node-cron/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/node-cron/sponsor/6/website" target="_blank"><img src="https://opencollective.com/node-cron/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/node-cron/sponsor/7/website" target="_blank"><img src="https://opencollective.com/node-cron/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/node-cron/sponsor/8/website" target="_blank"><img src="https://opencollective.com/node-cron/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/node-cron/sponsor/9/website" target="_blank"><img src="https://opencollective.com/node-cron/sponsor/9/avatar.svg"></a>
## License
node-cron is under [ISC License](https://github.com/merencia/node-cron/blob/master/LICENSE.md).

@ -0,0 +1,43 @@
{
"name": "node-cron",
"version": "3.0.2",
"description": "A simple cron-like task scheduler for Node.js",
"author": "Lucas Merencia",
"license": "ISC",
"homepage": "https://github.com/merencia/node-cron",
"main": "src/node-cron.js",
"scripts": {
"test": "nyc --reporter=html --reporter=text mocha --recursive",
"lint": "./node_modules/.bin/eslint ./src ./test",
"check": "npm run lint && npm test"
},
"engines": {
"node": ">=6.0.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/merencia/node-cron.git"
},
"keywords": [
"cron",
"scheduler",
"schedule",
"task",
"job"
],
"bugs": {
"url": "https://github.com/merencia/node-cron/issues"
},
"dependencies": {
"uuid": "8.3.2"
},
"devDependencies": {
"chai": "^4.2.0",
"eslint": "^5.7.0",
"istanbul": "^0.4.2",
"mocha": "^6.1.4",
"moment-timezone": "^0.5.33",
"nyc": "^14.0.0",
"sinon": "^7.3.2"
}
}

@ -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);
}
});

@ -0,0 +1,67 @@
const EventEmitter = require('events');
const path = require('path');
const { fork } = require('child_process');
const uuid = require('uuid');
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 || uuid.v4();
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;
})();

@ -0,0 +1,66 @@
'use strict';
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;
})();

@ -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;
})();

@ -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 };

@ -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;

@ -0,0 +1,51 @@
'use strict';
const EventEmitter = require('events');
const Task = require('./task');
const Scheduler = require('./scheduler');
const uuid = require('uuid');
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 || uuid.v4();
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;

@ -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;

@ -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;
}
};
})();

@ -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;

@ -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;

@ -0,0 +1,3 @@
exports.task = () => {
return 'dummy task';
};

@ -0,0 +1,47 @@
const { assert } = require('chai');
const BackgroundScheduledTask = require('../src/background-scheduled-task');
describe('BackgroundScheduledTask', () => {
it('should start a task by default', (done) => {
let task = new BackgroundScheduledTask('* * * * * *', './test/assets/dummy-task.js');
task.on('task-done', (result) => {
assert.equal('dummy task', result);
task.stop();
done();
});
});
it('should create a task stoped', () => {
let task = new BackgroundScheduledTask('* * * * * *', './test/assets/dummy-task.js', {
scheduled: false
});
assert.isUndefined(task.pid());
});
it('should start a task', (done) => {
let task = new BackgroundScheduledTask('* * * * * *', './test/assets/dummy-task.js', {
scheduled: false
});
assert.isUndefined(task.pid());
task.on('task-done', (result) => {
assert.equal('dummy task', result);
task.stop();
done();
});
task.start();
assert.isNotNull(task.pid());
});
it('should stop a task', () => {
let task = new BackgroundScheduledTask('* * * * * *', './test/assets/dummy-task.js', {
scheduled: true
});
assert.isNotNull(task.pid());
assert.isTrue(task.isRunning());
task.stop();
assert.isFalse(task.isRunning());
});
});

@ -0,0 +1,12 @@
'use strict';
const { expect } = require('chai');
const conversion = require('../../src/convert-expression/asterisk-to-range-conversion');
describe('asterisk-to-range-conversion.js', () => {
it('shuld convert * to ranges', () => {
const expressions = '* * * * * *'.split(' ');
const expression = conversion(expressions).join(' ');
expect(expression).to.equal('0-59 0-59 0-23 1-31 1-12 0-6');
});
});

@ -0,0 +1,18 @@
'use strict';
const { expect } = require('chai');
const conversion = require('../../src/convert-expression');
describe('month-names-conversion.js', () => {
it('shuld convert month names', () => {
const expression = conversion('* * * * January,February *');
const expressions = expression.split(' ');
expect(expressions[4]).to.equal('1,2');
});
it('shuld convert week day names', () => {
const expression = conversion('* * * * * Mon,Sun');
const expressions = expression.split(' ');
expect(expressions[5]).to.equal('1,0');
});
});

@ -0,0 +1,16 @@
'use strict';
const { expect } = require('chai');
const conversion = require('../../src/convert-expression/month-names-conversion');
describe('month-names-conversion.js', () => {
it('shuld convert month names', () => {
const months = conversion('January,February,March,April,May,June,July,August,September,October,November,December');
expect(months).to.equal('1,2,3,4,5,6,7,8,9,10,11,12');
});
it('shuld convert month names', () => {
const months = conversion('Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec');
expect(months).to.equal('1,2,3,4,5,6,7,8,9,10,11,12');
});
});

@ -0,0 +1,24 @@
'use strict';
const { expect } = require('chai');
const conversion = require('../../src/convert-expression/range-conversion');
describe('range-conversion.js', () => {
it('shuld convert ranges to numbers', () => {
const expressions = '0-3 0-3 0-2 1-3 1-2 0-3'.split(' ');
const expression = conversion(expressions).join(' ');
expect(expression).to.equal('0,1,2,3 0,1,2,3 0,1,2 1,2,3 1,2 0,1,2,3');
});
it('shuld convert ranges to numbers', () => {
const expressions = '0-3 0-3 8-10 1-3 1-2 0-3'.split(' ');
const expression = conversion(expressions).join(' ');
expect(expression).to.equal('0,1,2,3 0,1,2,3 8,9,10 1,2,3 1,2 0,1,2,3');
});
it('should convert comma delimited ranges to numbers', () => {
var expressions = '0-2,10-23'.split(' ');
var expression = conversion(expressions).join(' ');
expect(expression).to.equal('0,1,2,10,11,12,13,14,15,16,17,18,19,20,21,22,23');
});
});

@ -0,0 +1,19 @@
'use strict';
const { expect } = require('chai');
const conversion = require('../../src/convert-expression/step-values-conversion');
describe('step-values-conversion.js', () => {
it('should convert step values', () => {
var expressions = '1,2,3,4,5,6,7,8,9,10/2 0,1,2,3,4,5,6,7,8,9/5 * * * *'.split(' ');
expressions = conversion(expressions);
expect(expressions[0]).to.equal('2,4,6,8,10');
expect(expressions[1]).to.equal('0,5');
});
it('should throw an error if step value is not a number', () => {
var expressions = '1,2,3,4,5,6,7,8,9,10/someString 0,1,2,3,4,5,6,7,8,9/5 * * * *'.split(' ');
expect(() => conversion(expressions)).to.throw('someString is not a valid step value');
});
});

@ -0,0 +1,21 @@
'use strict';
const { expect } = require('chai');
const conversion = require('../../src/convert-expression/week-day-names-conversion');
describe('week-day-names-conversion.js', () => {
it('shuld convert week day names names', () => {
const weekDays = conversion('Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday');
expect(weekDays).to.equal('1,2,3,4,5,6,0');
});
it('shuld convert short week day names names', () => {
const weekDays = conversion('Mon,Tue,Wed,Thu,Fri,Sat,Sun');
expect(weekDays).to.equal('1,2,3,4,5,6,0');
});
it('shuld convert 7 to 0', () => {
const weekDays = conversion('7');
expect(weekDays).to.equal('0');
});
});

@ -0,0 +1,138 @@
const { assert } = require('chai');
const sinon = require('sinon');
const cron = require('../src/node-cron');
describe('node-cron', () => {
beforeEach(() => {
this.clock = sinon.useFakeTimers(new Date(2018, 0, 1, 0, 0, 0, 0));
});
afterEach(() => {
this.clock.restore();
});
describe('schedule', () => {
it('should schedule a task', () => {
let executed = 0;
cron.schedule('* * * * * *', () => {
executed += 1;
});
this.clock.tick(2000);
assert.equal(2, executed);
});
it('should schedule a task with America/Sao_Paulo timezone', (done) => {
let startDate = new Date('Thu, 20 Sep 2018 00:00:00.000Z');
this.clock.restore();
this.clock = sinon.useFakeTimers(startDate);
cron.schedule('* * * * * *', (date) => {
assert.equal(19, date.getDate());
assert.equal(8, date.getMonth());
assert.equal(2018, date.getFullYear());
assert.equal(21, date.getHours());
assert.equal(0, date.getMinutes());
assert.equal(1, date.getSeconds());
done();
}, {
timezone: 'America/Sao_Paulo'
});
this.clock.tick(1000);
});
it('should schedule a task with Europe/Rome timezone', (done) => {
let startDate = new Date('Thu, 20 Sep 2018 00:00:00.000Z');
this.clock.restore();
this.clock = sinon.useFakeTimers(startDate);
cron.schedule('* * * * * *', (date) => {
assert.equal(20, date.getDate());
assert.equal(8, date.getMonth());
assert.equal(2018, date.getFullYear());
assert.equal(2, date.getHours());
assert.equal(0, date.getMinutes());
assert.equal(1, date.getSeconds());
done();
}, {
timezone: 'Europe/Rome'
});
this.clock.tick(1000);
});
it('should schedule a task stoped', () => {
let executed = 0;
cron.schedule('* * * * * *', () => {
executed += 1;
}, { scheduled: false });
this.clock.tick(2000);
assert.equal(0, executed);
});
it('should start a stoped task', () => {
let executed = 0;
let scheduledTask = cron.schedule('* * * * * *', () => {
executed += 1;
}, { scheduled: false });
this.clock.tick(2000);
assert.equal(0, executed);
scheduledTask.start();
this.clock.tick(2000);
assert.equal(2, executed);
});
it('should recover missed executions', (done) => {
let executed = 0;
this.clock.restore();
let scheduledTask = cron.schedule('* * * * * *', () => {
executed += 1;
}, { recoverMissedExecutions: true });
let wait = true;
let startedAt = new Date();
while(wait){
if((new Date().getTime() - startedAt.getTime()) > 1000){
wait = false;
}
}
setTimeout(() => {
scheduledTask.stop();
assert.equal(2, executed);
done();
}, 1000);
}).timeout(4000);
it('should schedule a background task', () => {
let task = cron.schedule('* * * * * *', './test/assets/dummy-task.js');
assert.isNotNull(task);
assert.isDefined(task);
assert.isTrue(task.isRunning());
task.stop();
});
});
describe('validate', () => {
it('should validate a pattern', () => {
assert.isTrue(cron.validate('* * * * * *'));
});
it('should fail with a invalid pattern', () => {
assert.isFalse(cron.validate('62 * * * * *'));
});
});
describe('getTasks', () => {
beforeEach(() => {
global.scheduledTasks = new Map();
});
it('should store a task', () => {
cron.schedule('* * * * *', () => {});
assert.lengthOf(cron.getTasks(), 1);
});
});
});

@ -0,0 +1,32 @@
'use strict';
const { expect } = require('chai');
const validate = require('../../src/pattern-validation');
describe('pattern-validation.js', () => {
describe('validate day of month', () => {
it('should fail with invalid day of month', () => {
expect(() => {
validate('* * 32 * *');
}).to.throw('32 is a invalid expression for day of month');
});
it('should not fail with valid day of month', () => {
expect(() => {
validate('0 * * 15 * *');
}).to.not.throw();
});
it('should not fail with * for day of month', () => {
expect(() => {
validate('* * * * * *');
}).to.not.throw();
});
it('should not fail with */2 for day of month', () => {
expect(() => {
validate('* * */2 * *');
}).to.not.throw();
});
});
});

@ -0,0 +1,38 @@
'use strict';
const { expect } = require('chai');
const validate = require('../../src/pattern-validation');
describe('pattern-validation.js', () => {
describe('validate hour', () => {
it('should fail with invalid hour', () => {
expect(() => {
validate('* 25 * * *');
}).to.throw('25 is a invalid expression for hour');
});
it('should not fail with valid hour', () => {
expect(() => {
validate('* 12 * * *');
}).to.not.throw();
});
it('should not fail with * for hour', () => {
expect(() => {
validate('* * * * * *');
}).to.not.throw();
});
it('should not fail with */2 for hour', () => {
expect(() => {
validate('* */2 * * *');
}).to.not.throw();
});
it('should accept range for hours', () => {
expect(() => {
validate('* 3-20 * * *');
}).to.not.throw();
});
});
});

@ -0,0 +1,32 @@
'use strict';
const { expect } = require('chai');
const validate = require('../../src/pattern-validation');
describe('pattern-validation.js', () => {
describe('validate minutes', () => {
it('should fail with invalid minute', () => {
expect(() => {
validate('63 * * * *');
}).to.throw('63 is a invalid expression for minute');
});
it('should not fail with valid minute', () => {
expect(() => {
validate('30 * * * *');
}).to.not.throw();
});
it('should not fail with *', () => {
expect(() => {
validate('* * * * *');
}).to.not.throw();
});
it('should not fail with */2', () => {
expect(() => {
validate('*/2 * * * *');
}).to.not.throw();
});
});
});

@ -0,0 +1,44 @@
'use strict';
const { expect } = require('chai');
const validate = require('../../src/pattern-validation');
describe('pattern-validation.js', () => {
describe('validate month', () => {
it('should fail with invalid month', () => {
expect( () => {
validate('* * * 13 *');
}).to.throw('13 is a invalid expression for month');
});
it('should fail with invalid month name', () => {
expect( () => {
validate('* * * foo *');
}).to.throw('foo is a invalid expression for month');
});
it('should not fail with valid month', () => {
expect( () => {
validate('* * * 10 *');
}).to.not.throw();
});
it('should not fail with valid month name', () => {
expect( () => {
validate('* * * September *');
}).to.not.throw();
});
it('should not fail with * for month', () => {
expect( () => {
validate('* * * * *');
}).to.not.throw();
});
it('should not fail with */2 for month', () => {
expect( () => {
validate('* * * */2 *');
}).to.not.throw();
});
});
});

@ -0,0 +1,19 @@
'use strict';
const { expect } = require('chai');
const Task = require('../../src/task');
describe('Task', () => {
it('should accept a function', () => {
expect(() => {
new Task(() => {});
}).to.not.throw();
});
it('should fail without a function', () => {
expect(() => {
new Task([]);
}).to.throw('execution must be a function');
});
});

@ -0,0 +1,32 @@
'use strict';
const { expect } = require('chai');
const validate = require('../../src/pattern-validation');
describe('pattern-validation.js', () => {
describe('validate seconds', () => {
it('should fail with invalid second', () => {
expect(() => {
validate('63 * * * * *');
}).to.throw('63 is a invalid expression for second');
});
it('should not fail with valid second', () => {
expect(() => {
validate('30 * * * * *');
}).to.not.throw();
});
it('should not fail with * for second', () => {
expect(() => {
validate('* * * * * *');
}).to.not.throw();
});
it('should not fail with */2 for second', () => {
expect(() => {
validate('*/2 * * * * *');
}).to.not.throw();
});
});
});

@ -0,0 +1,24 @@
'use strict';
const { expect } = require('chai');
const validate = require('../../src/pattern-validation');
describe('pattern-validation', () => {
it('should succeed with a valid expression', () => {
expect(() => {
validate('59 * * * *');
}).to.not.throw();
});
it('should fail with an invalid expression', () => {
expect(() => {
validate('60 * * * *');
}).to.throw('60 is a invalid expression for minute');
});
it('should fail without a string', () => {
expect(() => {
validate(50);
}).to.throw('pattern must be a string!');
});
});

@ -0,0 +1,56 @@
'use strict';
const { expect } = require('chai');
const validate = require('../../src/pattern-validation');
describe('pattern-validation.js', () => {
describe('validate week day', () => {
it('should fail with invalid week day', () => {
expect(() => {
validate('* * * * 9');
}).to.throw('9 is a invalid expression for week day');
});
it('should fail with invalid week day name', () => {
expect(() => {
validate('* * * * foo');
}).to.throw('foo is a invalid expression for week day');
});
it('should not fail with valid week day', () => {
expect(() => {
validate('* * * * 5');
}).to.not.throw();
});
it('should not fail with valid week day name', () => {
expect(() => {
validate('* * * * Friday');
}).to.not.throw();
});
it('should not fail with * for week day', () => {
expect(() => {
validate('* * * * *');
}).to.not.throw();
});
it('should not fail with */2 for week day', () => {
expect(() => {
validate('* * * */2 *');
}).to.not.throw();
});
it('should not fail with Monday-Sunday for week day', () => {
expect(() => {
validate('* * * * Monday-Sunday');
}).to.not.throw();
});
it('should not fail with 1-7 for week day', () => {
expect(() => {
validate('0 0 1 1 1-7');
}).to.not.throw();
});
});
});

@ -0,0 +1,91 @@
const { assert } = require('chai');
const sinon = require('sinon');
const ScheduledTask = require('../src/scheduled-task');
describe('ScheduledTask', () => {
beforeEach(() => {
this.clock = sinon.useFakeTimers(new Date(2018, 0, 1, 0, 0, 0, 0));
});
afterEach(() => {
this.clock.restore();
});
it('should start a task by default', (done) => {
let executed = 0;
let scheduledTask = new ScheduledTask('* * * * * *', () => {
executed += 1;
});
this.clock.tick(3000);
assert.equal(3, executed);
scheduledTask.stop();
done();
});
it('should create a task stoped', (done) => {
let executed = 0;
let scheduledTask = new ScheduledTask('* * * * * *', () => {
executed += 1;
}, { scheduled: false });
this.clock.tick(3000);
assert.equal(0, executed);
scheduledTask.stop();
done();
});
it('should start a task', (done) => {
let executed = 0;
let scheduledTask = new ScheduledTask('* * * * * *', () => {
executed += 1;
}, { scheduled: false });
this.clock.tick(3000);
assert.equal(0, executed);
scheduledTask.start();
this.clock.tick(3000);
assert.equal(3, executed);
scheduledTask.stop();
done();
});
it('should stop a task', () => {
let executed = 0;
let scheduledTask = new ScheduledTask('* * * * * *', () => {
executed += 1;
}, { scheduled: true });
this.clock.tick(3000);
assert.equal(3, executed);
scheduledTask.stop();
this.clock.tick(3000);
assert.equal(3, executed);
});
it('should create a task stopped and run it once created', () => {
let executed = 0;
new ScheduledTask('* * * * * *', () => {
executed += 1;
}, { scheduled: false, runOnInit: true });
this.clock.tick(3000);
assert.equal(1, executed);
});
it('should create a task stopped and run it once manually', () => {
let executed = 0;
let scheduledTask = new ScheduledTask('* * * * * *', () => {
executed += 1;
}, { scheduled: false });
this.clock.tick(3000);
assert.equal(0, executed);
scheduledTask.now();
assert.equal(1, executed);
});
it('should emit event every minute', () => {
let executed = 0;
let scheduledTask = new ScheduledTask('0 * * * * *', () => {
executed += 1;
}, { scheduled: true });
this.clock.tick(60000 * 3);
assert.equal(3, executed);
scheduledTask.stop();
});
});

@ -0,0 +1,91 @@
const { assert } = require('chai');
const sinon = require('sinon');
const Scheduler = require('../src/scheduler');
describe('Scheduler', () => {
beforeEach(() => {
this.clock = sinon.useFakeTimers();
});
afterEach(() => {
this.clock.restore();
});
it('should emit an event on matched time', (done) => {
let scheduler = new Scheduler('* * * * * *');
scheduler.on('scheduled-time-matched', (date) => {
assert.isNotNull(date);
assert.instanceOf(date, Date);
scheduler.stop();
done();
});
scheduler.start();
this.clock.tick(1000);
});
it('should emit an event every second', (done) => {
let scheduler = new Scheduler('* * * * * *');
let emited = 0;
scheduler.on('scheduled-time-matched', (date) => {
emited += 1;
assert.isNotNull(date);
assert.instanceOf(date, Date);
if(emited === 5){
scheduler.stop();
done();
}
});
scheduler.start();
this.clock.tick(5000);
});
it('should recover missed executions', (done) => {
this.clock.restore();
let scheduler = new Scheduler('* * * * * *', null, true);
let emited = 0;
scheduler.on('scheduled-time-matched', () => {
emited += 1;
});
scheduler.start();
let wait = true;
let startedAt = new Date();
while(wait){
if((new Date().getTime() - startedAt.getTime()) > 1000){
wait = false;
}
}
setTimeout(() => {
scheduler.stop();
assert.equal(2, emited);
done();
}, 1000);
}).timeout(3000);
it('should ignore missed executions', (done) => {
this.clock.restore();
let scheduler = new Scheduler('* * * * * *', null, false);
let emited = 0;
scheduler.on('scheduled-time-matched', () => {
emited += 1;
});
scheduler.start();
let wait = true;
let startedAt = new Date();
while(wait){
if((new Date().getTime() - startedAt.getTime()) > 1000){
wait = false;
}
}
setTimeout(() => {
scheduler.stop();
assert.equal(1, emited);
done();
}, 1000);
}).timeout(3000);
});

@ -0,0 +1,26 @@
const { assert } = require('chai');
const storage = require('../src/storage');
describe('storage', () => {
it('should store a task', () => {
global.scheduledTasks = new Map();
storage.save({});
assert.lengthOf(global.scheduledTasks, 1);
});
it('should get all tasks', () => {
global.scheduledTasks = new Map();
global.scheduledTasks.set(0, {});
assert.lengthOf(storage.getTasks(), 1);
});
describe('on import', () => {
it('should keep stored items across imports', () => {
delete require.cache[require.resolve('../src/storage')];
global.scheduledTasks = new Map();
storage.save({});
let storage2 = require('../src/storage');
assert.lengthOf(storage2.getTasks(), 1);
});
});
});

@ -0,0 +1,49 @@
const { assert } = require('chai');
const sinon = require('sinon');
const Task = require('../src/task');
describe('Task', () => {
beforeEach(() => {
this.clock = sinon.useFakeTimers(new Date(2018, 0, 1, 0, 0, 0, 0));
});
afterEach(() => {
this.clock.restore();
});
it('should emit event on finish a task', async () => {
let finished = false;
let task = new Task(() => 'ok');
task.on('task-finished', () => finished = true);
await task.execute();
assert.equal(true, finished);
});
it('should emit event on error a task', async () => {
let error;
let task = new Task(() => {
throw Error('execution error');
});
task.on('task-failed', (err) => error = err.message);
await task.execute();
assert.equal('execution error', error);
});
it('should emit event on finish a promise task', async () => {
let finished = false;
const promise = () => new Promise((resolve) => resolve('ok'));
let task = new Task(promise);
task.on('task-finished', () => finished = true);
await task.execute();
assert.equal(true, finished);
});
it('should emit event on error a promise task', async () => {
let failed = false;
const promise = () => new Promise((resolve, reject) => reject('errou'));
const task = new Task(promise);
task.on('task-failed', (error) => failed = error);
await task.execute();
assert.equal('errou', failed);
});
});

@ -0,0 +1,244 @@
const { assert } = require('chai');
const TimeMatcher = require('../src/time-matcher');
const moment = require('moment-timezone');
describe('TimeMatcher', () => {
describe('wildcard', () => {
it('should accept wildcard for second', () => {
let matcher = new TimeMatcher('* * * * * *');
assert.isTrue(matcher.match(new Date()));
});
it('should accept wildcard for minute', () => {
let matcher = new TimeMatcher('0 * * * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 10, 20, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 10, 20, 1)));
});
it('should accept wildcard for hour', () => {
let matcher = new TimeMatcher('0 0 * * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 10, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 10, 1, 0)));
});
it('should accept wildcard for day', () => {
let matcher = new TimeMatcher('0 0 0 * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 1, 0, 0)));
});
it('should accept wildcard for month', () => {
let matcher = new TimeMatcher('0 0 0 1 * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 2, 0, 0, 0)));
});
it('should accept wildcard for week day', () => {
let matcher = new TimeMatcher('0 0 0 1 4 *');
assert.isTrue(matcher.match(new Date(2018, 3, 1, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 3, 2, 0, 0, 0)));
});
});
describe('single value', () => {
it('should accept single value for second', () => {
let matcher = new TimeMatcher('5 * * * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 0, 5)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 0, 0, 6)));
});
it('should accept single value for minute', () => {
let matcher = new TimeMatcher('0 5 * * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 5, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 0, 6, 0)));
});
it('should accept single value for hour', () => {
let matcher = new TimeMatcher('0 0 5 * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 5, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 6, 0, 0)));
});
it('should accept single value for day', () => {
let matcher = new TimeMatcher('0 0 0 5 * *');
assert.isTrue(matcher.match(new Date(2018, 0, 5, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 6, 0, 0, 0)));
});
it('should accept single value for month', () => {
let matcher = new TimeMatcher('0 0 0 1 5 *');
assert.isTrue(matcher.match(new Date(2018, 4, 1, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 5, 1, 0, 0, 0)));
});
it('should accept single value for week day', () => {
let matcher = new TimeMatcher('0 0 0 * * monday');
assert.isTrue(matcher.match(new Date(2018, 4, 7, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 4, 8, 0, 0, 0)));
});
});
describe('multiple values', () => {
it('should accept multiple values for second', () => {
let matcher = new TimeMatcher('5,6 * * * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 0, 5)));
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 0, 6)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 0, 0, 7)));
});
it('should accept multiple values for minute', () => {
let matcher = new TimeMatcher('0 5,6 * * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 5, 0)));
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 6, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 0, 7, 0)));
});
it('should accept multiple values for hour', () => {
let matcher = new TimeMatcher('0 0 5,6 * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 5, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 0, 1, 6, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 7, 0, 0)));
});
it('should accept multiple values for day', () => {
let matcher = new TimeMatcher('0 0 0 5,6 * *');
assert.isTrue(matcher.match(new Date(2018, 0, 5, 0, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 0, 6, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 7, 0, 0, 0)));
});
it('should accept multiple values for month', () => {
let matcher = new TimeMatcher('0 0 0 1 may,june *');
assert.isTrue(matcher.match(new Date(2018, 4, 1, 0, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 5, 1, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 6, 1, 0, 0, 0)));
});
it('should accept multiple values for week day', () => {
let matcher = new TimeMatcher('0 0 0 * * monday,tue');
assert.isTrue(matcher.match(new Date(2018, 4, 7, 0, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 4, 8, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 4, 9, 0, 0, 0)));
});
});
describe('range', () => {
it('should accept range for second', () => {
let matcher = new TimeMatcher('5-7 * * * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 0, 5)));
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 0, 6)));
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 0, 7)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 0, 0, 8)));
});
it('should accept range for minute', () => {
let matcher = new TimeMatcher('0 5-7 * * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 5, 0)));
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 6, 0)));
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 7, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 0, 8, 0)));
});
it('should accept range for hour', () => {
let matcher = new TimeMatcher('0 0 5-7 * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 5, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 0, 1, 6, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 0, 1, 7, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 8, 0, 0)));
});
it('should accept range for day', () => {
let matcher = new TimeMatcher('0 0 0 5-7 * *');
assert.isTrue(matcher.match(new Date(2018, 0, 5, 0, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 0, 6, 0, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 0, 7, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 8, 0, 0, 0)));
});
it('should accept range for month', () => {
let matcher = new TimeMatcher('0 0 0 1 may-july *');
assert.isTrue(matcher.match(new Date(2018, 4, 1, 0, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 5, 1, 0, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 6, 1, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 7, 1, 0, 0, 0)));
});
it('should accept range for week day', () => {
let matcher = new TimeMatcher('0 0 0 * * monday-wed');
assert.isTrue(matcher.match(new Date(2018, 4, 7, 0, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 4, 8, 0, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 4, 9, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 4, 10, 0, 0, 0)));
});
});
describe('step values', () => {
it('should accept step values for second', () => {
let matcher = new TimeMatcher('*/2 * * * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 0, 2)));
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 0, 6)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 0, 0, 7)));
});
it('should accept step values for minute', () => {
let matcher = new TimeMatcher('0 */2 * * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 2, 0)));
assert.isTrue(matcher.match(new Date(2018, 0, 1, 0, 6, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 0, 7, 0)));
});
it('should accept step values for hour', () => {
let matcher = new TimeMatcher('0 0 */2 * * *');
assert.isTrue(matcher.match(new Date(2018, 0, 1, 2, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 0, 1, 6, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 1, 7, 0, 0)));
});
it('should accept step values for day', () => {
let matcher = new TimeMatcher('0 0 0 */2 * *');
assert.isTrue(matcher.match(new Date(2018, 0, 2, 0, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 0, 6, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 0, 7, 0, 0, 0)));
});
it('should accept step values for month', () => {
let matcher = new TimeMatcher('0 0 0 1 */2 *');
assert.isTrue(matcher.match(new Date(2018, 1, 1, 0, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 5, 1, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 6, 1, 0, 0, 0)));
});
it('should accept step values for week day', () => {
let matcher = new TimeMatcher('0 0 0 * * */2');
assert.isTrue(matcher.match(new Date(2018, 4, 6, 0, 0, 0)));
assert.isTrue(matcher.match(new Date(2018, 4, 8, 0, 0, 0)));
assert.isFalse(matcher.match(new Date(2018, 4, 9, 0, 0, 0)));
});
});
describe('timezone', ()=>{
it('should match with timezone America/Sao_Paulo', () => {
let matcher = new TimeMatcher('0 0 0 * * *', 'America/Sao_Paulo');
let utcTime = new Date('Thu Oct 11 2018 03:00:00Z');
assert.isTrue(matcher.match(utcTime));
});
it('should match with timezone Europe/Rome', () => {
let matcher = new TimeMatcher('0 0 0 * * *', 'Europe/Rome');
let utcTime = new Date('Thu Oct 11 2018 22:00:00Z');
assert.isTrue(matcher.match(utcTime));
});
it('should match with all available timezone of moment-timezone', () => {
const allTimeZone = moment.tz.names();
for (let zone in allTimeZone) {
const tmp = moment();
const expected = moment.tz(tmp,allTimeZone[zone]);
const pattern = expected.second() + ' ' + expected.minute() + ' ' + expected.hour() + ' ' + expected.date() + ' ' + (expected.month()+1) + ' ' + expected.day();
const matcher = new TimeMatcher(pattern, allTimeZone[zone]);
const utcTime = new Date(tmp.year(), tmp.month(), tmp.date(), tmp.hour(), tmp.minute(), tmp.second(), tmp.millisecond());
assert.isTrue(matcher.match(utcTime));
}
});
});
});

20
package-lock.json generated

@ -45,6 +45,7 @@
"mongodb": "^5.0.1", "mongodb": "^5.0.1",
"mongoose": "^5.11.8", "mongoose": "^5.11.8",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"node-cron": "^3.0.2",
"node-schedule": "^2.1.1", "node-schedule": "^2.1.1",
"nodemon": "^2.0.20", "nodemon": "^2.0.20",
"nunjucks": "^3.2.3", "nunjucks": "^3.2.3",
@ -7578,6 +7579,17 @@
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz",
"integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA=="
}, },
"node_modules/node-cron": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz",
"integrity": "sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ==",
"dependencies": {
"uuid": "8.3.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/node-fetch": { "node_modules/node-fetch": {
"version": "2.6.7", "version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
@ -16537,6 +16549,14 @@
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz",
"integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA=="
}, },
"node-cron": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz",
"integrity": "sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ==",
"requires": {
"uuid": "8.3.2"
}
},
"node-fetch": { "node-fetch": {
"version": "2.6.7", "version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",

@ -46,6 +46,7 @@
"mongodb": "^5.0.1", "mongodb": "^5.0.1",
"mongoose": "^5.11.8", "mongoose": "^5.11.8",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"node-cron": "^3.0.2",
"node-schedule": "^2.1.1", "node-schedule": "^2.1.1",
"nodemon": "^2.0.20", "nodemon": "^2.0.20",
"nunjucks": "^3.2.3", "nunjucks": "^3.2.3",

@ -7,7 +7,7 @@ const fastify = require("fastify")({
logger: true, logger: true,
}); });
// const tanksController = require("./tanksController") // const tanksController = require("./tanksController")
const cron = require('node-cron');
const moment = require('moment'); const moment = require('moment');
@ -187,7 +187,7 @@ exports.updateTanklevels = async (req, reply) => {
// waterLevel = newWaterLevel; // waterLevel = newWaterLevel;
}, 2000); }, 5000);
intervals[tankId] = intervalId; intervals[tankId] = intervalId;
} }
@ -250,13 +250,11 @@ exports.getTanklevels = async (req, reply) => {
}; };
const intervals = {}; const intervals = {};
let sum_oh_count = 0
let bore_sump_count = 0
let sump_sump_count = 0
exports.motorAction = async (req, reply) => { exports.motorAction = async (req, reply) => {
try { try {
//let start_time,stop_time let start_time,stop_time
const customerId = req.params.customerId; const customerId = req.params.customerId;
const action = req.body.action const action = req.body.action
@ -272,7 +270,7 @@ exports.motorAction = async (req, reply) => {
const interval_variable = supplier_tank+receiver_tank const interval_variable = supplier_tank+receiver_tank
if(action === "start"){ if(action === "start"){
const start_time = new Date().toLocaleString('en-US', {timeZone: 'Asia/Kolkata'}) start_time = new Date().toLocaleString('en-US', {timeZone: 'Asia/Kolkata'})
// const stop_at = req.body.stop_at // const stop_at = req.body.stop_at
@ -294,9 +292,7 @@ exports.motorAction = async (req, reply) => {
await overheadTank.save(); await overheadTank.save();
} }
sum_oh_count++;
console.log(sum_oh_count)
// await changingfrom_tankwaterlevel(customerId,initial_update,supplier_tank_info); // await changingfrom_tankwaterlevel(customerId,initial_update,supplier_tank_info);
// let supplier_waterlevel = parseInt(supplier_tank_info.waterlevel.replace(/,/g, ''), 10) // let supplier_waterlevel = parseInt(supplier_tank_info.waterlevel.replace(/,/g, ''), 10)
@ -310,19 +306,15 @@ exports.motorAction = async (req, reply) => {
let supplier_waterlevel = parseInt(supplier_tank_info2.waterlevel.replace(/,/g, ''), 10) let supplier_waterlevel = parseInt(supplier_tank_info2.waterlevel.replace(/,/g, ''), 10)
const newWaterLevel = receiver_waterlevel + 250//Math.floor(supplier_waterlevel * 0.1); const newWaterLevel = receiver_waterlevel + 250//Math.floor(supplier_waterlevel * 0.1);
const newSupplierWaterLevel = supplier_waterlevel//Math.floor(supplier_waterlevel * 0.1); const newSupplierWaterLevel = supplier_waterlevel-250//Math.floor(supplier_waterlevel * 0.1);
const supplier_capacity = parseInt(supplier_tank_info.capacity.replace(/,/g, ''), 10) const supplier_capacity = parseInt(supplier_tank_info.capacity.replace(/,/g, ''), 10)
console.log((newSupplierWaterLevel/supplier_capacity)*100) console.log((newSupplierWaterLevel/supplier_capacity)*100)
// Check if updating should stop // Check if updating should stop
if ((newSupplierWaterLevel/supplier_capacity)*100 <= 5 || (newWaterLevel/receiver_capacity)*100 >= 95 || (newWaterLevel/receiver_capacity)*100 >= desired_water_percentage || rcvr_info.motor_status === "0") { if ((newSupplierWaterLevel/supplier_capacity)*100 <= 5 || (newWaterLevel/receiver_capacity)*100 >= 95 || (newWaterLevel/receiver_capacity)*100 >= desired_water_percentage || rcvr_info.motor_status === "0") {
console.log((newSupplierWaterLevel/supplier_capacity)*100,(newWaterLevel/receiver_capacity)*100,(newWaterLevel/receiver_capacity)*100,)
clearInterval(intervals[interval_variable]); // Clear the interval for this tank clearInterval(intervals[interval_variable]); // Clear the interval for this tank
delete intervals[interval_variable]; delete intervals[interval_variable];
sum_oh_count--;
if (sum_oh_count===0){
await Tank.findOneAndUpdate({customerId, tankName: receiver_tank,tankLocation:receiver_type}, { $set: { motor_status: "0" } });
}
const overheadTank = await Tank.findOne({ customerId, tankName: receiver_tank, tankLocation: receiver_type }); const overheadTank = await Tank.findOne({ customerId, tankName: receiver_tank, tankLocation: receiver_type });
const connection = overheadTank.connections.inputConnections.find((conn) => conn.inputConnections === supplier_tank); const connection = overheadTank.connections.inputConnections.find((conn) => conn.inputConnections === supplier_tank);
@ -330,6 +322,21 @@ exports.motorAction = async (req, reply) => {
connection.motor_status = "0"; connection.motor_status = "0";
await overheadTank.save(); await overheadTank.save();
} }
// Find the tank based on customerId, tankName, and tankLocation
const tankToUpdate = await Tank.findOne({ customerId, tankName: receiver_tank, tankLocation: receiver_type });
// Check if all objects in inputConnections have motor_status === "0"
const allMotorStatusZero = tankToUpdate.connections.inputConnections.every(connection => connection.motor_status === "0");
if (allMotorStatusZero) {
// Update the motor_status field to "0" for the tank
await Tank.findOneAndUpdate(
{ customerId, tankName: receiver_tank, tankLocation: receiver_type },
{ $set: { motor_status: "0" } }
);
}
console.log("end for"+receiver_tank); console.log("end for"+receiver_tank);
} else { } else {
@ -338,12 +345,14 @@ exports.motorAction = async (req, reply) => {
// receiver_waterlevel = newWaterLevel; // receiver_waterlevel = newWaterLevel;
console.log((newSupplierWaterLevel/supplier_capacity)*100) console.log((newSupplierWaterLevel/supplier_capacity)*100)
// console.log((newWaterLevel/receiver_capacity)*100) // console.log((newWaterLevel/receiver_capacity)*100)
console.log(receiver_tank+""+newWaterLevel+""+"bore to sump") console.log(newWaterLevel+""+receiver_type)
console.log(newSupplierWaterLevel+""+supplier_tank)
await Tank.findOneAndUpdate({customerId, tankName: receiver_tank,tankLocation:receiver_type}, { $set: { waterlevel: newWaterLevel } }) await Tank.findOneAndUpdate({customerId, tankName: receiver_tank,tankLocation:receiver_type}, { $set: { waterlevel: newWaterLevel } })
await Tank.findOneAndUpdate({customerId, tankName: supplier_tank,tankLocation:supplier_tank_type}, { $set: { waterlevel: newSupplierWaterLevel } })
//if (supplier_tank_info2.motor_status==="0"){ //if (supplier_tank_info2.motor_status==="0"){
supplier_waterlevel = parseInt(supplier_tank_info2.waterlevel.replace(/,/g, ''), 10)-250 // await Tank.findOneAndUpdate({customerId, tankName: supplier_tank,tankLocation:supplier_tank_type}, { $set: { waterlevel: supplier_waterlevel } })
console.log(supplier_tank+""+newSupplierWaterLevel+""+"s to oh")
await Tank.findOneAndUpdate({customerId, tankName: supplier_tank,tankLocation:supplier_tank_type}, { $set: { waterlevel: supplier_waterlevel } })
// } // }
} }
@ -417,7 +426,6 @@ exports.motorAction = async (req, reply) => {
connection.motor_status = "1"; connection.motor_status = "1";
await sumpTank.save(); await sumpTank.save();
} }
sump_sump_count++;
// console.log(receiver_capacity,"0",receiver_tank_info.tankName) // console.log(receiver_capacity,"0",receiver_tank_info.tankName)
await Tank.findOneAndUpdate({customerId, tankName: receiver_tank,tankLocation:receiver_type}, { $set: { motor_status: "1" } }); await Tank.findOneAndUpdate({customerId, tankName: receiver_tank,tankLocation:receiver_type}, { $set: { motor_status: "1" } });
@ -441,11 +449,26 @@ exports.motorAction = async (req, reply) => {
clearInterval(intervals[interval_variable]); // Clear the interval for this tank clearInterval(intervals[interval_variable]); // Clear the interval for this tank
delete intervals[interval_variable]; delete intervals[interval_variable];
sump_sump_count--; const sumpTank = await Tank.findOne({ customerId, tankName: receiver_tank, tankLocation: receiver_type });
if (sump_sump_count===0){ const connection = sumpTank.connections.inputConnections.find((conn) => conn.inputConnections === supplier_tank);
await Tank.findOneAndUpdate({customerId, tankName: receiver_tank,tankLocation:receiver_type}, { $set: { motor_status: "0" } });
} if (connection) {
connection.motor_status = "0";
await sumpTank.save();
}
}
const tankToUpdate = await Tank.findOne({ customerId, tankName: receiver_tank, tankLocation: receiver_type });
// Check if all objects in inputConnections have motor_status === "0"
const allMotorStatusZero = tankToUpdate.connections.inputConnections.every(connection => connection.motor_status === "0");
if (allMotorStatusZero) {
// Update the motor_status field to "0" for the tank
await Tank.findOneAndUpdate(
{ customerId, tankName: receiver_tank, tankLocation: receiver_type },
{ $set: { motor_status: "0" } }
);
console.log("end for" + receiver_tank); console.log("end for" + receiver_tank);
} else { } else {
// Update water levels in database // Update water levels in database
@ -473,7 +496,6 @@ exports.motorAction = async (req, reply) => {
if(supplier_tank_type==="bore" && receiver_type === "sump"){ if(supplier_tank_type==="bore" && receiver_type === "sump"){
const receiver_capacity = parseInt(receiver_tank_info.capacity.replace(/,/g, ''), 10) const receiver_capacity = parseInt(receiver_tank_info.capacity.replace(/,/g, ''), 10)
// console.log(receiver_capacity,"0",receiver_tank_info.tankName) // console.log(receiver_capacity,"0",receiver_tank_info.tankName)
bore_sump_count++;
await Tank.findOneAndUpdate({customerId, tankName: receiver_tank,tankLocation:receiver_type}, { $set: { motor_status: "1" } }); await Tank.findOneAndUpdate({customerId, tankName: receiver_tank,tankLocation:receiver_type}, { $set: { motor_status: "1" } });
const sumpTank = await Tank.findOne({ customerId, tankName: receiver_tank, tankLocation: receiver_type }); const sumpTank = await Tank.findOne({ customerId, tankName: receiver_tank, tankLocation: receiver_type });
const connection = sumpTank.connections.inputConnections.find((conn) => conn.inputConnections === supplier_tank); const connection = sumpTank.connections.inputConnections.find((conn) => conn.inputConnections === supplier_tank);
@ -500,18 +522,29 @@ exports.motorAction = async (req, reply) => {
clearInterval(intervals[interval_variable]); // Clear the interval for this tank clearInterval(intervals[interval_variable]); // Clear the interval for this tank
delete intervals[interval_variable]; delete intervals[interval_variable];
bore_sump_count--;
if (bore_sump_count===0){
await Tank.findOneAndUpdate({customerId, tankName: receiver_tank,tankLocation:receiver_type}, { $set: { motor_status: "0" } });
}
const sumpTank = await Tank.findOne({ customerId, tankName: receiver_tank, tankLocation: receiver_type }); const sumpTank = await Tank.findOne({ customerId, tankName: receiver_tank, tankLocation: receiver_type });
const connection = sumpTank.connections.inputConnections.find((conn) => conn.inputConnections === supplier_tank); const connection = sumpTank.connections.inputConnections.find((conn) => conn.inputConnections === supplier_tank);
if (connection) { if (connection) {
connection.motor_status = "0"; connection.motor_status = "0";
await sumpTank.save(); await sumpTank.save();
} }
const tankToUpdate = await Tank.findOne({ customerId, tankName: receiver_tank, tankLocation: receiver_type });
// Check if all objects in inputConnections have motor_status === "0"
const allMotorStatusZero = tankToUpdate.connections.inputConnections.every(connection => connection.motor_status === "0");
if (allMotorStatusZero) {
// Update the motor_status field to "0" for the tank
await Tank.findOneAndUpdate(
{ customerId, tankName: receiver_tank, tankLocation: receiver_type },
{ $set: { motor_status: "0" } }
);
}
console.log("end for" + receiver_tank); console.log("end for" + receiver_tank);
} else { } else {
// Update water levels in database // Update water levels in database
@ -526,77 +559,14 @@ exports.motorAction = async (req, reply) => {
} }
// console.log(customerId,req.body.from,req.body.from_type,receiver_tank,req.body.to_type,) // console.log(customerId,req.body.from,req.body.from_type,receiver_tank,req.body.to_type,)
motorData = {
customerId:customerId,
supplierTank : req.body.from,
supplier_type: req.body.from_type,
receiverTank: receiver_tank,
receiver_type: req.body.to_type,
startTime: req.body.startTime,
stopTime: req.body.stopTime,
};
var motorData = new MotorData(motorData);
checkFormEncoding = isUserFormUrlEncoded(req);
if (checkFormEncoding.isUserFormUrlEncoded) {
usertobeInserted = checkFormEncoding.motorData;
console.log("thsi true url string");
motorData.customerId = customerId;
motorData.supplierTank = req.body.from;
motorData.receiverTank = receiver_tank;
motorData.supplier_type = req.body.from_type;
motorData.receiver_type = req.body.to_type;
motorData.startTime = usertobeInserted.startTime;
motorData.stopTime = usertobeInserted.stopTime;
}
const motor_data = await motorData.save();
console.log(motor_data)
// reply.send({ status_code: 200, data: motor_data });
reply.send({ status_code: 200, "start time": start_time, data: motor_data});
console.log(start_time)
return motor_data
} }
else if (action === "stop") { else if (action === "stop") {
const stop_time = new Date().toLocaleString('en-US', {timeZone: 'Asia/Kolkata'}) stop_time = new Date().toLocaleString('en-US', {timeZone: 'Asia/Kolkata'})
clearInterval(intervals[interval_variable]); // Clear the interval for this tank clearInterval(intervals[interval_variable]); // Clear the interval for this tank
delete intervals[interval_variable]; delete intervals[interval_variable];
if (supplier_tank_type === "sump" && receiver_type ==="sump"){
sump_sump_count--;
if (sump_sump_count===0){
await Tank.findOneAndUpdate({customerId, tankName: receiver_tank,tankLocation:receiver_type}, { $set: { motor_status: "0" } });
}
}
if (supplier_tank_type === "sump"){
sum_oh_count--;
if (sum_oh_count===0){
await Tank.findOneAndUpdate({customerId, tankName: receiver_tank,tankLocation:(req.body.to_type).toLowerCase()}, { $set: { motor_status: "0" } });
}
}
if (supplier_tank_type === "bore"){
bore_sump_count--;
if (bore_sump_count===0){
await Tank.findOneAndUpdate({customerId, tankName: receiver_tank,tankLocation:(req.body.to_type).toLowerCase()}, { $set: { motor_status: "0" } });
}
}
const overheadTank = await Tank.findOne({ customerId, tankName: receiver_tank, tankLocation: receiver_type }); const overheadTank = await Tank.findOne({ customerId, tankName: receiver_tank, tankLocation: receiver_type });
const connection = overheadTank.connections.inputConnections.find((conn) => conn.inputConnections === supplier_tank); const connection = overheadTank.connections.inputConnections.find((conn) => conn.inputConnections === supplier_tank);
@ -605,12 +575,70 @@ exports.motorAction = async (req, reply) => {
connection.motor_status = "0"; connection.motor_status = "0";
await overheadTank.save(); await overheadTank.save();
} }
const tankToUpdate = await Tank.findOne({ customerId, tankName: receiver_tank, tankLocation: receiver_type });
// Check if all objects in inputConnections have motor_status === "0"
const allMotorStatusZero = tankToUpdate.connections.inputConnections.every(connection => connection.motor_status === "0");
if (allMotorStatusZero) {
// Update the motor_status field to "0" for the tank
await Tank.findOneAndUpdate(
{ customerId, tankName: receiver_tank, tankLocation: receiver_type },
{ $set: { motor_status: "0" } }
);
}
motorData = {
customerId:customerId,
supplierTank : supplier_tank,
supplier_type: supplier_tank_type,
receiverTank: receiver_tank,
receiver_type: receiver_type,
// startTime: startTime,
stopTime: req.body.stopTime,
};
var motorData = new MotorData(motorData);
checkFormEncoding = isUserFormUrlEncoded(req);
if (checkFormEncoding.isUserFormUrlEncoded) {
usertobeInserted = checkFormEncoding.motorData;
console.log("thsi true url string");
motorData.customerId = customerId;
motorData.supplierTank = supplierTank;
motorData.receiverTank = receiver_tank;
motorData.supplier_type = supplier_type;
motorData.receiver_type = receiver_type;
//motorData.startTime = startTime;
motorData.stopTime = stop_time;
}
const motor_data = await motorData.save();
console.log(motor_data)
// reply.send({ status_code: 200, data: motor_data });
// reply.send({ status_code: 200, "start time": start_time, data: motor_data});
console.log(start_time)
// return motor_data
// console.log(stop_time) // console.log(stop_time)
// clearInterval(intervalId); // clearInterval(intervalId);
// await Tank.findOneAndUpdate({customerId, tankName: receiver_tank,tankLocation:(req.body.to_type).toLowerCase()}, { $set: { motor_status: "0" } }); // await Tank.findOneAndUpdate({customerId, tankName: receiver_tank,tankLocation:(req.body.to_type).toLowerCase()}, { $set: { motor_status: "0" } });
reply.send({ status_code: 200, "stop time": stop_time}); reply.send({ status_code: 200, "stop time": stop_time,data: motor_data});
} else { } else {
throw new Error("Invalid action"); throw new Error("Invalid action");
} }
@ -1006,3 +1034,34 @@ exports.startUpdateLoop = async (request, reply) => {
} }
}, updateInterval); }, updateInterval);
}; };
exports.updatewaterlevelsatmidnight = async (req, reply) => {
try {
// Schedule the task to run every day at 10 seconds past the minute
cron.schedule('0 0 * * *', async () => {
try {
const tanks = await Tank.find({ customerId: req.query.customerId });
for (const tank of tanks) {
tank.waterlevel_at_midnight = tank.waterlevel;
console.log(tank.waterlevel_at_midnight)
await tank.save();
}
console.log('Waterlevel noted in waterlevel_at_midnight');
} catch (error) {
console.error('Error occurred:', error);
}
});
await Tank.find({ customerId: req.query.customerId })
.exec()
.then((docs) => {
reply.send({ status_code: 200, data: docs, count: docs.length });
})
.catch((err) => {
console.log(err);
reply.send({ error: err });
});
} catch (err) {
throw boom.boomify(err);
}
};

@ -42,6 +42,7 @@ const tanksSchema = new mongoose.Schema({
waterlevel: { type: String, default: "0" }, waterlevel: { type: String, default: "0" },
tankLocation: { type: String, default: null }, tankLocation: { type: String, default: null },
motor_status: { type: String, default: "0" }, motor_status: { type: String, default: "0" },
waterlevel_at_midnight:{ type: String,default:"0" },
connections: { connections: {
source: { type: String }, source: { type: String },
inputConnections: [ inputConnections: [

@ -506,7 +506,23 @@ module.exports = function (fastify, opts, next) {
handler: tanksController.startUpdateLoop, handler: tanksController.startUpdateLoop,
}); });
fastify.get("/api/updatewaterlevelsatmidnight", {
schema: {
tags: ["Tank"],
description: "This is for storing waterlevels in tank at midnight",
summary: "This is for storing waterlevels in tank at midnight",
querystring: {
customerId: {type: 'string'}
},
security: [
{
basicAuth: [],
},
],
},
preHandler: fastify.auth([fastify.authenticate]),
handler: tanksController.updatewaterlevelsatmidnight,
});
next(); next();
} }

Loading…
Cancel
Save