node-opcua-client
Version:
pure nodejs OPCUA SDK - module client
128 lines • 6.12 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.republish = republish;
const chalk_1 = __importDefault(require("chalk"));
const node_opcua_assert_1 = __importDefault(require("node-opcua-assert"));
const node_opcua_debug_1 = require("node-opcua-debug");
const node_opcua_status_code_1 = require("node-opcua-status-code");
const node_opcua_types_1 = require("node-opcua-types");
const client_subscription_reconnection_1 = require("./client_subscription_reconnection");
const reconnection_1 = require("./reconnection");
const debugLog = (0, node_opcua_debug_1.make_debugLog)("RECONNECTION");
const doDebug = (0, node_opcua_debug_1.checkDebugFlag)("RECONNECTION");
function _sendRepublish(session, subscription) {
return new Promise((resolve, reject) => {
(0, node_opcua_assert_1.default)(Number.isFinite(subscription.lastSequenceNumber) && subscription.lastSequenceNumber + 1 >= 0);
const request = new node_opcua_types_1.RepublishRequest({
retransmitSequenceNumber: subscription.lastSequenceNumber + 1,
subscriptionId: subscription.subscriptionId
});
// c8 ignore next
if (doDebug) {
// c8 ignore next
debugLog(chalk_1.default.bgCyan.yellow.bold(" republish Request for subscription"), request.subscriptionId, " retransmitSequenceNumber=", request.retransmitSequenceNumber);
}
if (!session || session._closeEventHasBeenEmitted) {
debugLog("ClientPublishEngine#_republish aborted ");
return resolve({ isDone: true });
}
session.republish(request, (err, response) => {
if (!response) {
reject(err);
return;
}
const statusCode = err ? node_opcua_status_code_1.StatusCodes.Bad : response.responseHeader.serviceResult;
if (!err && (statusCode.equals(node_opcua_status_code_1.StatusCodes.Good) || statusCode.equals(node_opcua_status_code_1.StatusCodes.BadMessageNotAvailable))) {
// reprocess notification message and keep going
if (statusCode.equals(node_opcua_status_code_1.StatusCodes.Good)) {
subscription.onNotificationMessage(response.notificationMessage);
}
return resolve({ isDone: false });
}
if (!err) {
err = new Error(response.responseHeader.serviceResult.toString());
}
debugLog(" _send_republish ends with ", err.message);
reject(err);
});
});
}
async function _republish(engine, subscription) {
const session = engine.session;
// loop until done (all messages re-published or error)
let isDone = false;
while (!isDone) {
// yield to event loop before each iteration
await new Promise((resolve) => setImmediate(resolve));
const result = await _sendRepublish(session, subscription);
isDone = result.isDone;
}
debugLog("nbPendingPublishRequest = ", engine.nbPendingPublishRequests);
debugLog(" _republish ends with ", "null");
}
async function __askSubscriptionRepublish(engine, subscription) {
try {
await _republish(engine, subscription);
}
catch (err) {
// prettier-ignore
{
const _err = (0, reconnection_1._shouldNotContinue2)(subscription);
if (_err) {
throw _err;
}
}
const error = err;
debugLog("__askSubscriptionRepublish--------------------- err =", error.message);
if (error.message.match(/BadSessionInvalid/)) {
// _republish failed because session is not valid anymore on server side.
throw error;
}
if (error.message.match(/SubscriptionIdInvalid/)) {
// _republish failed because subscriptionId is not valid anymore on server side.
//
// This could happen when the subscription has timed out and has been deleted by server
// Subscription may time out if the duration of the connection break exceed the max life time
// of the subscription.
//
// In this case, Client must recreate a subscription and recreate monitored item without altering
// the event handlers
//
debugLog(chalk_1.default.bgWhite.red("__askSubscriptionRepublish failed " + " subscriptionId is not valid anymore on server side."));
await (0, client_subscription_reconnection_1.recreateSubscriptionAndMonitoredItem)(subscription);
return;
}
if (error.message.match(/|MessageNotAvailable/)) {
// start engine and start monitoring
}
}
// check after successful republish too
const _err = (0, reconnection_1._shouldNotContinue2)(subscription);
if (_err) {
throw _err;
}
}
function republish(engine, callback) {
// After re-establishing the connection the Client shall call Republish in a loop, starting with
// the next expected sequence number and incrementing the sequence number until the Server returns
// the status BadMessageNotAvailable.
// After receiving this status, the Client shall start sending Publish requests with the normal Publish
// handling.
// This sequence ensures that the lost NotificationMessages queued in the Server are not overwritten
// by newPublish responses
/**
* call Republish continuously until all Notification messages of
* un-acknowledged notifications are reprocessed.
*/
const processAll = async () => {
const entries = Object.entries(engine.subscriptionMap);
for (const [_subscriptionId, subscription] of entries) {
await __askSubscriptionRepublish(engine, subscription);
}
};
processAll().then(() => callback()).catch(() => callback());
}
//# sourceMappingURL=client_publish_engine_reconnection.js.map