"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const _ = require("underscore");
const events_1 = require("events");
const node_opcua_assert_1 = require("node-opcua-assert");
function has_expired(watchDogData, currentTime) {
const elapsed_time = currentTime - watchDogData.last_seen;
return elapsed_time > watchDogData.timeout;
}
function keepAliveFunc() {
const self = this;
node_opcua_assert_1.assert(self._watchDog instanceof WatchDog);
node_opcua_assert_1.assert(_.isNumber(self._watchDogData.key));
self._watchDogData.last_seen = Date.now();
if (self.onClientSeen) {
self.onClientSeen(new Date(self._watchDogData.last_seen));
}
}
class WatchDog extends events_1.EventEmitter {
constructor() {
super();
this._watchdogDataMap = {};
this._counter = 0;
this._current_time = Date.now();
this._visit_subscriber_b = this._visit_subscriber.bind(this);
this._timer = null; // as NodeJS.Timer;
}
_visit_subscriber() {
const self = this;
self._current_time = Date.now();
const expired_subscribers = _.filter(self._watchdogDataMap, function (watchDogData) {
watchDogData.visitCount += 1;
return has_expired(watchDogData, self._current_time);
});
//xx console.log("_visit_subscriber", _.map(expired_subscribers, _.property("key")));
if (expired_subscribers.length) {
self.emit("timeout", expired_subscribers);
}
expired_subscribers.forEach((watchDogData) => {
self.removeSubscriber(watchDogData.subscriber);
watchDogData.subscriber.watchdogReset();
});
//xx self._current_time = Date.now();
}
/**
* add a subscriber to the WatchDog.
* @method addSubscriber
*
* add a subscriber to the WatchDog.
*
* This method modifies the subscriber be adding a
* new method to it called 'keepAlive'
* The subscriber must also provide a "watchdogReset". watchdogReset will be called
* if the subscriber failed to call keepAlive withing the timeout period.
* @param subscriber
* @param timeout
* @return {number}
*/
addSubscriber(subscriber, timeout) {
const self = this;
self._current_time = Date.now();
timeout = timeout || 1000;
node_opcua_assert_1.assert(_.isNumber(timeout), " invalid timeout ");
node_opcua_assert_1.assert(_.isFunction(subscriber.watchdogReset), " the subscriber must provide a watchdogReset method ");
node_opcua_assert_1.assert(!_.isFunction(subscriber.keepAlive));
self._counter += 1;
const key = self._counter;
subscriber._watchDog = self;
subscriber._watchDogData = {
key: key,
subscriber: subscriber,
timeout: timeout,
last_seen: self._current_time,
visitCount: 0
};
self._watchdogDataMap[key] = subscriber._watchDogData;
if (subscriber.onClientSeen) {
subscriber.onClientSeen(new Date(subscriber._watchDogData.last_seen));
}
subscriber.keepAlive = keepAliveFunc.bind(subscriber);
// start timer when the first subscriber comes in
if (self.subscriberCount === 1) {
node_opcua_assert_1.assert(self._timer === null);
this._start_timer();
}
return key;
}
removeSubscriber(subscriber) {
if (!subscriber._watchDog) {
return; // already removed !!!
}
node_opcua_assert_1.assert(subscriber._watchDog instanceof WatchDog);
node_opcua_assert_1.assert(_.isNumber(subscriber._watchDogData.key));
node_opcua_assert_1.assert(_.isFunction(subscriber.keepAlive));
node_opcua_assert_1.assert(this._watchdogDataMap.hasOwnProperty(subscriber._watchDogData.key));
delete this._watchdogDataMap[subscriber._watchDogData.key];
delete subscriber._watchDog;
delete subscriber._watchDogData;
delete subscriber.keepAlive;
// delete timer when the last subscriber comes out
//xx console.log("xxxx WatchDog.prototype.removeSubscriber ",this.subscriberCount );
if (this.subscriberCount === 0) {
this._stop_timer();
}
}
shutdown() {
node_opcua_assert_1.assert(this._timer === null && Object.keys(this._watchdogDataMap).length === 0, " leaking subscriber in watchdog");
}
/**
* returns the number of subscribers using the WatchDog object.
* @property subscriberCount
* @type {number}
*/
get subscriberCount() {
return Object.keys(this._watchdogDataMap).length;
}
_start_timer() {
node_opcua_assert_1.assert(this._timer === null, " setInterval already called ?");
this._timer = setInterval(this._visit_subscriber_b, 1000);
}
_stop_timer() {
node_opcua_assert_1.assert(this._timer !== null, "_stop_timer already called ?");
if (this._timer !== null) {
clearInterval(this._timer);
this._timer = null;
}
}
}
exports.WatchDog = WatchDog;
//# sourceMappingURL=watchdog.js.map