UNPKG

watchdog

Version:

An Timer used to Detect and Recover from Malfunctions

235 lines (234 loc) 9.34 kB
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