APIs

Show:

const assert = require("node-opcua-assert").assert;
const EventEmitter = require("events").EventEmitter;
const util = require("util");

const coerceNodeId = require("node-opcua-nodeid").coerceNodeId;
const VariableIds = require("node-opcua-constants").VariableIds;

const serverStatus_State_Id = coerceNodeId(VariableIds.Server_ServerStatus_State);
const ServerState = require("node-opcua-common").ServerState;
const StatusCodes = require("node-opcua-status-code").StatusCodes;

const debugLog = require("node-opcua-debug").make_debugLog(__filename);
const doDebug = require("node-opcua-debug").checkDebugFlag(__filename);


function ClientSessionKeepAliveManager(session) {
    const self = this;
    self.session = session;
    self.timerId = 0;
}
util.inherits(ClientSessionKeepAliveManager, EventEmitter);
/**
 * @method ping_server
 *
 * when a session is opened on a server, the client shall send request on a regular basis otherwise the server
 * session object might time out.
 * start_ping make sure that ping_server is called on a regular basis to prevent session to timeout.
 *
 * @param callback
 */
ClientSessionKeepAliveManager.prototype.ping_server = function(callback) {
    const self = this;
    callback = callback || function () { };
    const the_session = this.session;
    if (!the_session) {
        return callback();
    }

    const now = Date.now();

    const timeSinceLastServerContact = now - the_session.lastResponseReceivedTime;
    if (timeSinceLastServerContact < self.pingTimeout) {
        // no need to send a ping yet
        //xx console.log("Skipping ",timeSinceLastServerContact,self.session.timeout);
        return callback();
    }

    if (the_session.isReconnecting) {
        debugLog("ClientSessionKeepAliveManager#ping_server skipped because client is reconnecting");
        return callback();
    }
    debugLog("ClientSessionKeepAliveManager#ping_server ",timeSinceLastServerContact,self.session.timeout);
    // Server_ServerStatus_State
    the_session.readVariableValue(serverStatus_State_Id, function (err, dataValue) {
        if (err) {
            console.log(" warning : ClientSessionKeepAliveManager#ping_server ".cyan, err.message.yellow);
            self.stop();

            /**
             * @event failure
             * raised when the server is not responding or is responding with en error to
             * the keep alive read Variable value transaction
             */
            self.emit("failure");

        } else {
            if (dataValue.statusCode === StatusCodes.Good) {
                const newState = ServerState.get(dataValue.value.value);
                //istanbul ignore next
                if (newState !== self.lastKnownState) {
                    console.log(" Server State = ", newState.toString());
                }
                self.lastKnownState = newState;
            }

            self.emit("keepalive",self.lastKnownState);
        }
        callback();
    });
};


ClientSessionKeepAliveManager.prototype.start = function() {
    const self = this;
    assert(!self.timerId);
    assert(self.session.timeout > 100);

    self.pingTimeout   =  self.session.timeout * 2/3;
    self.checkInterval =  self.pingTimeout  / 3;
    self.timerId = setInterval(self.ping_server.bind(self),self.checkInterval);
};

ClientSessionKeepAliveManager.prototype.stop = function() {
    const self = this;
    if (self.timerId) {
        clearInterval(self.timerId);
        self.timerId = 0;
    }
};

exports.ClientSessionKeepAliveManager = ClientSessionKeepAliveManager;