watchdog
Version:
An Timer used to Detect and Recover from Malfunctions
235 lines (234 loc) • 9.34 kB
JavaScript
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
}
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
/* watchdog version 0.8.17 */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('events'), require('brolog')) :
typeof define === 'function' && define.amd ? define(['exports', 'events', 'brolog'], factory) :
(factory((global.window = {}), global.events, global.brolog));
}(this, (function (exports, events, brolog) {
'use strict';
// https://github.com/andrew-filonenko/ya-watchdog
var log = new brolog.Brolog();
var VERSION = require('../package.json').version;
var Watchdog = /** @class */ (function (_super) {
__extends(Watchdog, _super);
/**
* A Timer used to detect and recover from malfunctions
*
* @class Watchdog
* @param {number} [defaultTimeout=60 * 1000]
* @param {string} [name='Bark']
* @example
* const TIMEOUT = 1 * 1000 // 1 second
* const dog = new watchdog(TIMEOUT)
*
* const food = { data: 'delicious' }
*
* dog.on('reset', () => console.log('reset-ed'))
* dog.on('feed', () => console.log('feed-ed'))
*
* dog.feed(food)
* // Output: feed-ed
*
* setTimeout(function() {
* dog.sleep()
* console.log('dog sleep-ed. Demo over.')
* }, TIMEOUT + 1)
* // Output: reset-ed.
* // Output: dog sleep-ed. Demo over.
*
*/
function Watchdog(defaultTimeout, name) {
if (defaultTimeout === void 0) { defaultTimeout = 60 * 1000; }
if (name === void 0) { name = 'Bark'; }
var _this = _super.call(this) || this;
_this.defaultTimeout = defaultTimeout;
_this.name = name;
log.verbose('Watchdog', '<%s>: constructor(name=%s, defaultTimeout=%d)', name, name, defaultTimeout);
return _this;
}
Watchdog.prototype.version = function () {
return VERSION;
};
/**
* @desc Watchdog Class Event Type
* @typedef WatchdogEvent
* @property { string } feed - Emit when feed the dog.
* @property { string } reset - Emit when timeout and reset.
* @property { string } sleep - Emit when timer is cleared out.
*/
/**
* @desc Watchdog Class Event Function
* @typedef WatchdogListener
* @property { Function } - (food: WatchdogFood<T, D>, left: number) => void
*/
/**
* @listens Watchdog
* @param { WatchdogEvent } event
* @param { WatchdogListener<T, D> } listener
* @returns { this }
*
* @example <caption>Event:reset </caption>
* dog.on('reset', () => console.log('reset-ed'))
* @example <caption>Event:feed </caption>
* dog.on('feed', () => console.log('feed-ed'))
* @example <caption>Event:sleep </caption>
* dog.on('sleep', () => console.log('sleep-ed'))
*
*/
Watchdog.prototype.on = function (event, listener) {
log.verbose('Watchdog', '<%s> on(%s, listener) registered.', this.name, event);
_super.prototype.on.call(this, event, listener);
return this;
};
Watchdog.prototype.startTimer = function (timeout) {
var _this = this;
log.verbose('Watchdog', '<%s> startTimer()', this.name);
if (this.timer) {
throw new Error('timer already exist!');
}
this.timer = setTimeout(function () {
log.verbose('Watchdog', '<%s> startTimer() setTimeout() after %d', _this.name, timeout);
_this.timer = undefined; // sleep after reset
_this.emit('reset', _this.lastFood, _this.lastFood && _this.lastFood.timeout || _this.defaultTimeout);
}, timeout);
this.timer.unref(); // should not block node quit
return;
};
Watchdog.prototype.stopTimer = function (sleep) {
if (sleep === void 0) { sleep = false; }
log.verbose('Watchdog', '<%s> stopTimer()', this.name);
if (typeof this.timer === 'undefined') { // first time
log.verbose('Watchdog', '<%s> stopTimer() first run(or after sleep)', this.name);
return;
}
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
else if (!sleep) {
throw new Error('timer is already stoped!');
}
};
/**
* Get the left time
* @returns {number}
*/
Watchdog.prototype.left = function () {
var left;
if (typeof this.lastFeed !== 'undefined'
&& Number.isInteger(this.lastFeed)) {
// console.log('lastFeed=', this.lastFeed)
// console.log('timeout=', this.lastFood.timeout)
// console.log('Date.now()=', Date.now())
left = this.lastFeed + this.defaultTimeout - Date.now();
log.verbose('Watchdog', '<%s> timerLeft() = %d', this.name, left);
}
else {
left = 0;
log.verbose('Watchdog', '<%s> timerLeft() first feed, left=%s', this.name, left);
}
return left;
};
/**
* Dog Feed content
*
* @typedef WatchdogFood
* @property {D} data - feed content.
* @property {number} timeout - option, set timeout.
* @property {T} type - option.
*/
/**
* feed the dog
* @param {WatchdogFood} food
* @returns {number}
* @example
* const food = {
* data: 'delicious',
* timeout: 1 * 1000,
* }
* const dog = new Watchdog()
* dog.feed(food)
*/
Watchdog.prototype.feed = function (food) {
// JSON.stringify, avoid TypeError: Converting circular structure to JSON
// https://stackoverflow.com/a/11616993/1123955
function replacerFactory() {
// Note: cache should not be re-used by repeated calls to JSON.stringify.
var cache = [];
return function (_, value) {
if (typeof value === 'object' && value !== null) {
if (cache.indexOf(value) !== -1) {
// Circular reference found, discard key
return;
}
// Store value in our collection
cache.push(value);
}
return value;
};
}
log.verbose('Watchdog', '<%s> feed(%s)', this.name, JSON.stringify(food, replacerFactory()));
if (typeof food !== 'object') {
/**
* weak typing compitable:
* if user call watchdog.feed('string'), we need to pre-processs the food to a object.
* or we will meet a exception: we can not set property on string type.
*/
food = {
data: food,
};
}
if (!food.timeout) {
food.timeout = this.defaultTimeout;
}
var left = this.left();
this.stopTimer();
this.startTimer(food.timeout);
this.lastFeed = Date.now();
this.lastFood = food;
this.emit('feed', food, left);
return left;
};
/**
* Clear timer.
* @example
* const dog = new Watchdog()
* dog.sleep()
*/
Watchdog.prototype.sleep = function () {
log.verbose('Watchdog', '<%s> sleep()', this.name);
this.stopTimer(true);
this.timer = undefined;
this.emit('sleep', this.lastFood, this.left());
};
/**
*
*/
Watchdog.prototype.unref = function () {
log.verbose('Watchdog', '<%s> unref()', this.name);
if (this.timer) {
this.timer.unref();
}
};
return Watchdog;
}(events.EventEmitter));
exports.log = log;
exports.VERSION = VERSION;
exports.Watchdog = Watchdog;
exports.default = Watchdog;
Object.defineProperty(exports, '__esModule', { value: true });
})));
/* https://github.com/huan */
//# sourceMappingURL=watchdog.es6.umd.js.map