node-opcua-client
Version:
pure nodejs OPCUA SDK - module client
718 lines (716 loc) • 36.4 kB
JavaScript
;
/**
* @module node-opcua-client-private
*/
// tslint:disable:unified-signatures
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientSubscriptionImpl = exports.TERMINATING_SUBSCRIPTION_ID = exports.TERMINATED_SUBSCRIPTION_ID = exports.PENDING_SUBSCRIPTION_ID = void 0;
exports.ClientMonitoredItem_create = ClientMonitoredItem_create;
exports.__create_subscription = __create_subscription;
const chalk_1 = __importDefault(require("chalk"));
const events_1 = require("events");
const node_opcua_assert_1 = require("node-opcua-assert");
const node_opcua_client_dynamic_extension_object_1 = require("node-opcua-client-dynamic-extension-object");
const node_opcua_data_model_1 = require("node-opcua-data-model");
const node_opcua_debug_1 = require("node-opcua-debug");
const node_opcua_nodeid_1 = require("node-opcua-nodeid");
const node_opcua_service_subscription_1 = require("node-opcua-service-subscription");
const node_opcua_status_code_1 = require("node-opcua-status-code");
const node_opcua_utils_1 = require("node-opcua-utils");
const client_monitored_item_toolbox_1 = require("../client_monitored_item_toolbox");
const client_subscription_1 = require("../client_subscription");
const client_monitored_item_group_impl_1 = require("./client_monitored_item_group_impl");
const client_monitored_item_impl_1 = require("./client_monitored_item_impl");
const performance_1 = require("./performance");
const debugLog = (0, node_opcua_debug_1.make_debugLog)("CLIENT_SUBSCRIPTION");
const doDebug = (0, node_opcua_debug_1.checkDebugFlag)("CLIENT_SUBSCRIPTION");
const warningLog = (0, node_opcua_debug_1.make_warningLog)("CLIENT_SUBSCRIPTION");
exports.PENDING_SUBSCRIPTION_ID = 0xc0cac01a;
exports.TERMINATED_SUBSCRIPTION_ID = 0xc0cac01b;
exports.TERMINATING_SUBSCRIPTION_ID = 0xc0cac01c;
const minimumMaxKeepAliveCount = 3;
function displayKeepAliveWarning(sessionTimeout, maxKeepAliveCount, publishingInterval) {
const keepAliveInterval = maxKeepAliveCount * publishingInterval;
// c8 ignore next
if (sessionTimeout < keepAliveInterval) {
warningLog(chalk_1.default.yellowBright(`[NODE-OPCUA-W09] The subscription parameters are not compatible with the session timeout !
session timeout = ${sessionTimeout} milliseconds
maxKeepAliveCount = ${maxKeepAliveCount}
publishingInterval = ${publishingInterval} milliseconds"
It is important that the session timeout ( ${chalk_1.default.red(sessionTimeout)} ms) is largely greater than :
(maxKeepAliveCount*publishingInterval = ${chalk_1.default.red(keepAliveInterval)} ms),
otherwise you may experience unexpected disconnection from the server if your monitored items are not
changing frequently.`));
if (sessionTimeout < 3000 && publishingInterval <= 1000) {
warningLog(`[NODE-OPCUA-W10] You'll need to increase your sessionTimeout significantly.`);
}
if (sessionTimeout >= 3000 &&
sessionTimeout < publishingInterval * minimumMaxKeepAliveCount &&
maxKeepAliveCount <= minimumMaxKeepAliveCount + 2) {
warningLog(`[NODE-OPCUA-W11] your publishingInterval interval is probably too large, consider reducing it.`);
}
const idealMaxKeepAliveCount = Math.max(4, Math.floor((sessionTimeout * 0.8) / publishingInterval - 0.5));
const idealPublishingInternal = Math.min(publishingInterval, sessionTimeout / (idealMaxKeepAliveCount + 3));
const idealKeepAliveInterval = idealMaxKeepAliveCount * publishingInterval;
warningLog(`[NODE-OPCUA-W12] An ideal value for maxKeepAliveCount could be ${idealMaxKeepAliveCount}.
An ideal value for publishingInterval could be ${idealPublishingInternal} ms.
This will make your subscription emit a keep alive signal every ${idealKeepAliveInterval} ms
if no monitored items are generating notifications.
for instance:
const client = OPCUAClient.create({
requestedSessionTimeout: 30* 60* 1000, // 30 minutes
});
`);
if (!client_subscription_1.ClientSubscription.ignoreNextWarning) {
throw new Error("[NODE-OPCUA-W09] The subscription parameters are not compatible with the session timeout ");
}
return true;
}
return false;
}
class ClientSubscriptionImpl extends events_1.EventEmitter {
/**
* the associated session
* @property session
* @type {ClientSession}
*/
get session() {
(0, node_opcua_assert_1.assert)(this.hasSession, "expecting a valid session");
return this.publishEngine.session;
}
get hasSession() {
return !!this.publishEngine?.session;
}
get isActive() {
return (this.hasSession &&
!(this.subscriptionId === exports.PENDING_SUBSCRIPTION_ID ||
this.subscriptionId === exports.TERMINATED_SUBSCRIPTION_ID ||
this.subscriptionId === exports.TERMINATING_SUBSCRIPTION_ID));
}
subscriptionId;
publishingInterval;
lifetimeCount;
maxKeepAliveCount;
maxNotificationsPerPublish;
publishingEnabled;
priority;
#monitoredItems;
get monitoredItems() {
return this.#monitoredItems;
}
set monitoredItems(value) {
this.#monitoredItems = value;
}
#monitoredItemGroups = [];
timeoutHint = 0;
publishEngine;
lastSequenceNumber;
#nextClientHandle = 0;
hasTimedOut;
constructor(session, options) {
super();
const sessionImpl = session;
this.publishEngine = sessionImpl.getPublishEngine();
this.lastSequenceNumber = -1;
options = options || {};
options.requestedPublishingInterval = options.requestedPublishingInterval || 100;
options.requestedLifetimeCount = options.requestedLifetimeCount || 60;
options.requestedMaxKeepAliveCount = options.requestedMaxKeepAliveCount || 10;
options.requestedMaxKeepAliveCount = Math.max(options.requestedMaxKeepAliveCount, minimumMaxKeepAliveCount);
// perform some verification
const warningEmitted = displayKeepAliveWarning(session.timeout, options.requestedMaxKeepAliveCount, options.requestedPublishingInterval);
// c8 ignore next
if (warningEmitted) {
warningLog(JSON.stringify({
...options
}, null, " "));
}
options.maxNotificationsPerPublish = (0, node_opcua_utils_1.isNullOrUndefined)(options.maxNotificationsPerPublish)
? 0
: options.maxNotificationsPerPublish;
options.publishingEnabled = !!options.publishingEnabled;
options.priority = options.priority || 1;
this.publishingInterval = options.requestedPublishingInterval;
this.lifetimeCount = options.requestedLifetimeCount;
this.maxKeepAliveCount = options.requestedMaxKeepAliveCount;
this.maxNotificationsPerPublish = options.maxNotificationsPerPublish || 0;
this.publishingEnabled = options.publishingEnabled === undefined ? true : options.publishingEnabled;
this.priority = options.priority;
this.subscriptionId = exports.PENDING_SUBSCRIPTION_ID;
this.#nextClientHandle = 0;
this.#monitoredItems = {};
/**
* set to True when the server has notified us that this subscription has timed out
* ( maxLifeCounter x published interval without being able to process a PublishRequest
* @property hasTimedOut
* @type {boolean}
*/
this.hasTimedOut = false;
setImmediate(() => {
__create_subscription(this, (err) => {
if (!err) {
setImmediate(() => {
/**
* notify the observers that the subscription has now started
* @event started
*/
this.emit("started", this.subscriptionId);
});
}
else {
setImmediate(() => {
/**
* notify the observers that the subscription has now failed
* @event failed
*/
this.emit("error", err);
});
}
});
});
}
terminate(...args) {
debugLog("Terminating client subscription ", this.subscriptionId);
const callback = args[0];
(0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback function");
if (this.subscriptionId === exports.TERMINATED_SUBSCRIPTION_ID || this.subscriptionId === exports.TERMINATING_SUBSCRIPTION_ID) {
// already terminated... just ignore
return callback();
}
if (isFinite(this.subscriptionId)) {
const subscriptionId = this.subscriptionId;
this.subscriptionId = exports.TERMINATING_SUBSCRIPTION_ID;
this.publishEngine.unregisterSubscription(subscriptionId);
if (!this.hasSession) {
return this._terminate_step2(callback);
}
const session = this.session;
if (!session) {
return callback(new Error("no session"));
}
session.deleteSubscriptions({
subscriptionIds: [subscriptionId]
}, (err, response) => {
if (response && response.results[0] !== node_opcua_status_code_1.StatusCodes.Good) {
debugLog("warning: deleteSubscription returned ", response.results);
}
if (err) {
/**
* notify the observers that an error has occurred
* @event internal_error
* @param err the error
*/
this.emit("internal_error", err);
}
this._terminate_step2(callback);
});
}
else {
debugLog("subscriptionId is not value ", this.subscriptionId);
(0, node_opcua_assert_1.assert)(this.subscriptionId === exports.PENDING_SUBSCRIPTION_ID);
this._terminate_step2(callback);
}
}
/**
*/
_nextClientHandle() {
this.#nextClientHandle += 1;
return this.#nextClientHandle;
}
monitor(...args) {
const itemToMonitor = args[0];
const requestedParameters = args[1];
const timestampsToReturn = args[2];
const monitoringMode = typeof args[3] === "function" ? node_opcua_service_subscription_1.MonitoringMode.Reporting : args[3];
const done = (typeof args[3] === "function" ? args[3] : args[4]);
(0, node_opcua_assert_1.assert)(typeof done === "function", "expecting a function here");
itemToMonitor.nodeId = (0, node_opcua_nodeid_1.resolveNodeId)(itemToMonitor.nodeId);
const monitoredItem = ClientMonitoredItem_create(this, itemToMonitor, requestedParameters, timestampsToReturn, monitoringMode, (err1, monitoredItem2) => {
if (err1) {
return done && done(err1);
}
done(err1 || null, monitoredItem);
});
}
monitorItems(...args) {
const itemsToMonitor = args[0];
const requestedParameters = args[1];
const timestampsToReturn = args[2];
const done = args[3];
const monitoredItemGroup = new client_monitored_item_group_impl_1.ClientMonitoredItemGroupImpl(this, itemsToMonitor, requestedParameters, timestampsToReturn);
this._wait_for_subscription_to_be_ready((err) => {
if (err) {
return done(err);
}
monitoredItemGroup._monitor((err1) => {
if (err1) {
return done && done(err1);
}
done(err1, monitoredItemGroup);
});
});
}
_delete_monitored_items(monitoredItems, callback) {
(0, node_opcua_assert_1.assert)(typeof callback === "function");
(0, node_opcua_assert_1.assert)(Array.isArray(monitoredItems));
(0, node_opcua_assert_1.assert)(this.isActive);
for (const monitoredItem of monitoredItems) {
this._remove(monitoredItem);
}
const session = this.session;
session.deleteMonitoredItems({
monitoredItemIds: monitoredItems.map((monitoredItem) => monitoredItem.monitoredItemId),
subscriptionId: this.subscriptionId
}, (err, response) => {
callback(err);
});
}
setPublishingMode(...args) {
const publishingEnabled = args[0];
const callback = args[1];
(0, node_opcua_assert_1.assert)(typeof callback === "function");
const session = this.session;
if (!session) {
return callback(new Error("no session"));
}
const subscriptionId = this.subscriptionId;
session.setPublishingMode(publishingEnabled, subscriptionId, (err, statusCode) => {
if (err) {
return callback(err);
}
/* c8 ignore next */
if (!statusCode) {
return callback(new Error("Internal Error"));
}
if (statusCode.isNotGood()) {
return callback(null, statusCode);
}
callback(null, node_opcua_status_code_1.StatusCodes.Good);
});
}
setTriggering(...args) {
const triggeringItem = args[0];
const linksToAdd = args[1];
const linksToRemove = args[2];
const callback = args[3];
(0, node_opcua_assert_1.assert)(typeof callback === "function");
const session = this.session;
if (!session) {
return callback(new Error("no session"));
}
const subscriptionId = this.subscriptionId;
const triggeringItemId = triggeringItem.monitoredItemId;
const setTriggeringRequest = new node_opcua_service_subscription_1.SetTriggeringRequest({
linksToAdd: linksToAdd ? linksToAdd.map((i) => i.monitoredItemId) : null,
linksToRemove: linksToRemove ? linksToRemove.map((i) => i.monitoredItemId) : null,
subscriptionId,
triggeringItemId
});
session.setTriggering(setTriggeringRequest, (err, response) => {
if (err) {
if (response) {
// use soft error, no exceptions
return callback(null, response);
}
else {
return callback(err);
}
}
// c8 ignore next
if (!response) {
return callback(new Error("Internal Error"));
}
callback(null, response);
});
}
modify(...args) {
const modifySubscriptionRequest = args[0];
const callback = args[1];
const session = this.session;
if (!session) {
return callback(new Error("no session"));
}
modifySubscriptionRequest.subscriptionId = this.subscriptionId;
modifySubscriptionRequest.priority =
modifySubscriptionRequest.priority === undefined ? this.priority : modifySubscriptionRequest.priority;
modifySubscriptionRequest.requestedLifetimeCount =
modifySubscriptionRequest.requestedLifetimeCount === undefined
? this.lifetimeCount
: modifySubscriptionRequest.requestedLifetimeCount;
modifySubscriptionRequest.requestedMaxKeepAliveCount =
modifySubscriptionRequest.requestedMaxKeepAliveCount === undefined
? this.maxKeepAliveCount
: modifySubscriptionRequest.requestedMaxKeepAliveCount;
modifySubscriptionRequest.requestedPublishingInterval =
modifySubscriptionRequest.requestedPublishingInterval === undefined
? this.publishingInterval
: modifySubscriptionRequest.requestedPublishingInterval;
modifySubscriptionRequest.maxNotificationsPerPublish =
modifySubscriptionRequest.maxNotificationsPerPublish === undefined
? this.maxNotificationsPerPublish
: modifySubscriptionRequest.maxNotificationsPerPublish;
session.modifySubscription(modifySubscriptionRequest, (err, response) => {
if (err || !response) {
return callback(err);
}
this.publishingInterval = response.revisedPublishingInterval;
this.lifetimeCount = response.revisedLifetimeCount;
this.maxKeepAliveCount = response.revisedMaxKeepAliveCount;
callback(null, response);
});
}
getMonitoredItems(...args) {
this.session.getMonitoredItems(this.subscriptionId, args[0]);
}
toString() {
let str = "";
str += "subscriptionId : " + this.subscriptionId + "\n";
str += "publishingInterval : " + this.publishingInterval + "\n";
str += "lifetimeCount : " + this.lifetimeCount + "\n";
str += "maxKeepAliveCount : " + this.maxKeepAliveCount + "\n";
str += "hasTimedOut : " + this.hasTimedOut + "\n";
const timeToLive = this.lifetimeCount * this.publishingInterval;
str += "(maxKeepAliveCount*publishingInterval: " + this.publishingInterval * this.maxKeepAliveCount + " ms)\n";
str += "(maxLifetimeCount*publishingInterval: " + timeToLive + " ms)\n";
const lastRequestSentTime = this.publishEngine.lastRequestSentTime;
str += "lastRequestSentTime : " + lastRequestSentTime.toString() + "\n";
const duration = Date.now() - lastRequestSentTime.getTime();
const extra = duration - timeToLive > 0
? chalk_1.default.red(" expired since " + (duration - timeToLive) / 1000 + " seconds")
: chalk_1.default.green(" valid for " + -(duration - timeToLive) / 1000 + " seconds");
str += "timeSinceLast PR : " + duration + "ms" + extra + "\n";
str += "has expired : " + (duration > timeToLive) + "\n";
str += "(session timeout : " + this.session.timeout + " ms)\n";
return str;
}
/**
* returns the approximated remaining life time of this subscription in milliseconds
*/
evaluateRemainingLifetime() {
const now = Date.now();
const timeout = this.publishingInterval * this.lifetimeCount;
const lastRequestSentTime = this.publishEngine.lastRequestSentTime;
const expiryTime = lastRequestSentTime.getTime() + timeout;
return Math.max(0, expiryTime - now);
}
_add_monitored_item(clientHandle, monitoredItem) {
(0, node_opcua_assert_1.assert)(this.isActive, "subscription must be active and not terminated");
(0, node_opcua_assert_1.assert)(monitoredItem.monitoringParameters.clientHandle === clientHandle);
this.#monitoredItems[clientHandle] = monitoredItem;
/**
* notify the observers that a new monitored item has been added to the subscription.
* @event item_added
* @param the monitored item.
*/
this.emit("item_added", monitoredItem);
}
_add_monitored_items_group(monitoredItemGroup) {
this.#monitoredItemGroups.push(monitoredItemGroup);
}
_wait_for_subscription_to_be_ready(done) {
let _watchDogCount = 0;
const waitForSubscriptionAndMonitor = () => {
_watchDogCount++;
if (this.subscriptionId === exports.PENDING_SUBSCRIPTION_ID) {
// the subscriptionID is not yet known because the server hasn't replied yet
// let postpone this call, a little bit, to let things happen
setImmediate(waitForSubscriptionAndMonitor);
}
else if (this.subscriptionId === exports.TERMINATED_SUBSCRIPTION_ID) {
// the subscription has been terminated in the meantime
// this indicates a potential issue in the code using this api.
if (typeof done === "function") {
done(new Error("subscription has been deleted"));
}
}
else {
done();
}
};
setImmediate(waitForSubscriptionAndMonitor);
}
__on_publish_response_DataChangeNotification(notification) {
(0, node_opcua_assert_1.assert)(notification.schema.name === "DataChangeNotification");
const monitoredItems = notification.monitoredItems || [];
let repeated = 0;
for (const monitoredItem of monitoredItems) {
const monitorItemObj = this.#monitoredItems[monitoredItem.clientHandle];
if (monitorItemObj) {
if (monitorItemObj.itemToMonitor.attributeId === node_opcua_data_model_1.AttributeIds.EventNotifier) {
warningLog(chalk_1.default.yellow("Warning"), chalk_1.default.cyan(" Server send a DataChangeNotification for an EventNotifier." + " EventNotificationList was expected"));
warningLog(chalk_1.default.cyan(" the Server may not be fully OPCUA compliant"), chalk_1.default.yellow(". This notification will be ignored."));
}
else {
const monitoredItemImpl = monitorItemObj;
monitoredItemImpl._notify_value_change(monitoredItem.value);
}
}
else {
repeated += 1;
if (repeated === 1) {
warningLog("Receiving a notification for a unknown monitoredItem with clientHandle ", monitoredItem.clientHandle);
}
}
}
// c8 ignore next
if (repeated > 1) {
warningLog("previous message repeated", repeated, "times");
}
}
__on_publish_response_StatusChangeNotification(notification) {
(0, node_opcua_assert_1.assert)(notification.schema.name === "StatusChangeNotification");
debugLog("Client has received a Status Change Notification ", notification.status.toString());
if (notification.status === node_opcua_status_code_1.StatusCodes.GoodSubscriptionTransferred) {
// OPCUA UA Spec 1.0.3 : part 3 - page 82 - 5.13.7 TransferSubscriptions:
// If the Server transfers the Subscription to the new Session, the Server shall issue
// a StatusChangeNotification notificationMessage with the status code
// Good_SubscriptionTransferred to the old Session.
debugLog("ClientSubscription#__on_publish_response_StatusChangeNotification : GoodSubscriptionTransferred");
// may be it has been transferred after a reconnection.... in this case should do nothing about it
}
if (notification.status === node_opcua_status_code_1.StatusCodes.BadTimeout) {
// the server tells use that the subscription has timed out ..
// this mean that this subscription has been closed on the server side and cannot process any
// new PublishRequest.
//
// from Spec OPCUA Version 1.03 Part 4 - 5.13.1.1 Description : Page 69:
//
// h. Subscriptions have a lifetime counter that counts the number of consecutive publishing cycles in
// which there have been no Publish requests available to send a Publish response for the
// Subscription. Any Service call that uses the SubscriptionId or the processing of a Publish
// response resets the lifetime counter of this Subscription. When this counter reaches the value
// calculated for the lifetime of a Subscription based on the MaxKeepAliveCount parameter in the
// CreateSubscription Service (5.13.2), the Subscription is closed. Closing the Subscription causes
// its MonitoredItems to be deleted. In addition the Server shall issue a StatusChangeNotification
// notificationMessage with the status code BadTimeout.
//
this.hasTimedOut = true;
this.terminate(() => {
/* empty */
});
}
/**
* notify the observers that the server has send a status changed notification (such as BadTimeout )
* @event status_changed
*/
this.emit("status_changed", notification.status, notification.diagnosticInfo);
}
__on_publish_response_EventNotificationList(notification) {
(0, node_opcua_assert_1.assert)(notification.schema.name === "EventNotificationList");
const events = notification.events || [];
for (const event of events) {
const monitorItemObj = this.#monitoredItems[event.clientHandle];
(0, node_opcua_assert_1.assert)(monitorItemObj, "Expecting a monitored item");
const monitoredItemImpl = monitorItemObj;
monitoredItemImpl._notify_event(event.eventFields || []);
}
}
onNotificationMessage(notificationMessage) {
(0, node_opcua_assert_1.assert)(Object.hasOwn(notificationMessage, "sequenceNumber"));
this.lastSequenceNumber = notificationMessage.sequenceNumber;
this.emit("raw_notification", notificationMessage);
const notificationData = (notificationMessage.notificationData || []);
if (notificationData.length === 0) {
// this is a keep alive message
debugLog(chalk_1.default.yellow("Client : received a keep alive notification from client"));
/**
* notify the observers that a keep alive Publish Response has been received from the server.
* @event keepalive
*/
this.emit("keepalive");
}
else {
/**
* notify the observers that some notifications has been received from the server in a PublishResponse
* each modified monitored Item
* @event received_notifications
*/
this.emit("received_notifications", notificationMessage);
// let publish a global event
(0, node_opcua_client_dynamic_extension_object_1.promoteOpaqueStructureInNotificationData)(this.session, notificationData).then(() => {
(0, performance_1.detectLongOperation)(() => {
// now process all notifications
for (const notification of notificationData) {
// c8 ignore next
if (!notification) {
continue;
}
// DataChangeNotification / StatusChangeNotification / EventNotification
switch (notification.schema.name) {
case "DataChangeNotification":
// now inform each individual monitored item
this.__on_publish_response_DataChangeNotification(notification);
break;
case "StatusChangeNotification":
this.__on_publish_response_StatusChangeNotification(notification);
break;
case "EventNotificationList":
this.__on_publish_response_EventNotificationList(notification);
break;
default:
warningLog(" Invalid notification :", notification.toString());
}
}
}, (duration) => {
const s = (a) => {
const b = a;
b.$_slowNotifCount = b.$_slowNotifCount || 0;
b.$_maxDuration = b.$_maxDuration || 0;
return b;
};
s(this).$_maxDuration = Math.max(s(this).$_maxDuration, duration);
if (s(this).$_slowNotifCount > 0 && s(this).$_slowNotifCount % 1000 !== 0)
return;
s(this).$_slowNotifCount++;
warningLog(`[NODE-OPCUA-W32]}: monitored.item event handler takes too much time : operation duration ${duration} ms [repeated ${s(this).$_slowNotifCount} times]\n please ensure that your monitoredItem event handler is not blocking the event loop.`);
});
});
}
}
_terminate_step2(callback) {
const monitoredItems = Object.values(this.#monitoredItems);
for (const monitoredItem of monitoredItems) {
this._remove(monitoredItem);
}
const monitoredItemGroups = this.#monitoredItemGroups;
for (const monitoredItemGroup of monitoredItemGroups) {
this._removeGroup(monitoredItemGroup);
}
(0, node_opcua_assert_1.assert)(Object.values(this.#monitoredItems).length === 0);
setImmediate(() => {
/**
* notify the observers that the client subscription has terminated
* @event terminated
*/
this.subscriptionId = exports.TERMINATED_SUBSCRIPTION_ID;
this.emit("terminated");
callback();
});
}
_remove(monitoredItem) {
const clientHandle = monitoredItem.monitoringParameters.clientHandle;
this._removeMonitoredItem(clientHandle);
const priv = monitoredItem;
priv._terminate_and_emit();
}
_removeMonitoredItem(clientHandle) {
if (this.#monitoredItems[clientHandle]) {
delete this.#monitoredItems[clientHandle];
}
}
_removeGroup(monitoredItemGroup) {
monitoredItemGroup._terminate_and_emit();
this.#monitoredItemGroups = this.#monitoredItemGroups.filter((obj) => obj !== monitoredItemGroup);
}
/**
* @private
* @param itemToMonitor
* @param monitoringParameters
* @param timestampsToReturn
*/
_createMonitoredItem(itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode = node_opcua_service_subscription_1.MonitoringMode.Reporting) {
/* c8 ignore next*/
const monitoredItem = new client_monitored_item_impl_1.ClientMonitoredItemImpl(this, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode);
return monitoredItem;
}
}
exports.ClientSubscriptionImpl = ClientSubscriptionImpl;
function ClientMonitoredItem_create(subscription, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode = node_opcua_service_subscription_1.MonitoringMode.Reporting, callback) {
const subscriptionImpl = subscription;
if (!subscriptionImpl) {
throw new Error("Invalid subscription");
}
const monitoredItem = new client_monitored_item_impl_1.ClientMonitoredItemImpl(subscriptionImpl, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode);
setImmediate(() => {
subscriptionImpl._wait_for_subscription_to_be_ready((err) => {
if (err) {
if (callback) {
callback(err);
}
return;
}
client_monitored_item_toolbox_1.ClientMonitoredItemToolbox._toolbox_monitor(subscription, timestampsToReturn, [monitoredItem], (err1) => {
if (err1) {
monitoredItem._terminate_and_emit(err1);
}
if (callback) {
callback(err1, monitoredItem);
}
});
});
});
return monitoredItem;
}
// tslint:disable:no-var-requires
// tslint:disable:max-line-length
const thenify_ex_1 = require("thenify-ex");
const opts = { multiArgs: false };
ClientSubscriptionImpl.prototype.setPublishingMode = (0, thenify_ex_1.withCallback)(ClientSubscriptionImpl.prototype.setPublishingMode);
ClientSubscriptionImpl.prototype.monitor = (0, thenify_ex_1.withCallback)(ClientSubscriptionImpl.prototype.monitor);
ClientSubscriptionImpl.prototype.monitorItems = (0, thenify_ex_1.withCallback)(ClientSubscriptionImpl.prototype.monitorItems);
ClientSubscriptionImpl.prototype.setTriggering = (0, thenify_ex_1.withCallback)(ClientSubscriptionImpl.prototype.setTriggering);
ClientSubscriptionImpl.prototype.modify = (0, thenify_ex_1.withCallback)(ClientSubscriptionImpl.prototype.modify);
ClientSubscriptionImpl.prototype.terminate = (0, thenify_ex_1.withCallback)(ClientSubscriptionImpl.prototype.terminate);
ClientSubscriptionImpl.prototype.getMonitoredItems = (0, thenify_ex_1.withCallback)(ClientSubscriptionImpl.prototype.getMonitoredItems);
client_subscription_1.ClientSubscription.create = (clientSession, options) => {
return new ClientSubscriptionImpl(clientSession, options);
};
function __create_subscription(subscription, callback) {
// c8 ignore next
if (!subscription.hasSession) {
return callback(new Error("__create_subscription: subscription has no Session"));
}
const session = subscription.session;
debugLog(chalk_1.default.yellow.bold("ClientSubscription created "));
const request = new node_opcua_service_subscription_1.CreateSubscriptionRequest({
maxNotificationsPerPublish: subscription.maxNotificationsPerPublish,
priority: subscription.priority,
publishingEnabled: subscription.publishingEnabled,
requestedLifetimeCount: subscription.lifetimeCount,
requestedMaxKeepAliveCount: subscription.maxKeepAliveCount,
requestedPublishingInterval: subscription.publishingInterval
});
session.createSubscription(request, (err, response) => {
if (err) {
/* c8 ignore next */
subscription.emit("internal_error", err);
if (callback) {
return callback(err);
}
return;
}
/* c8 ignore next */
if (!response) {
return callback(new Error("internal error"));
}
if (!subscription.hasSession) {
return callback(new Error("createSubscription has failed = > no session"));
}
(0, node_opcua_assert_1.assert)(subscription.hasSession);
subscription.subscriptionId = response.subscriptionId;
subscription.publishingInterval = response.revisedPublishingInterval;
subscription.lifetimeCount = response.revisedLifetimeCount;
subscription.maxKeepAliveCount = response.revisedMaxKeepAliveCount;
subscription.timeoutHint = Math.min((subscription.maxKeepAliveCount + 10) * subscription.publishingInterval * 2, 0x7ffff);
displayKeepAliveWarning(subscription.session.timeout, subscription.maxKeepAliveCount, subscription.publishingInterval);
client_subscription_1.ClientSubscription.ignoreNextWarning = false;
// c8 ignore next
if (doDebug) {
debugLog(chalk_1.default.yellow.bold("registering callback"));
debugLog(chalk_1.default.yellow.bold("publishingInterval "), subscription.publishingInterval);
debugLog(chalk_1.default.yellow.bold("lifetimeCount "), subscription.lifetimeCount);
debugLog(chalk_1.default.yellow.bold("maxKeepAliveCount "), subscription.maxKeepAliveCount);
debugLog(chalk_1.default.yellow.bold("publish request timeout hint = "), subscription.timeoutHint);
debugLog(chalk_1.default.yellow.bold("hasTimedOut "), subscription.hasTimedOut);
debugLog(chalk_1.default.yellow.bold("timeoutHint for publish request "), subscription.timeoutHint);
}
subscription.publishEngine.registerSubscription(subscription);
if (callback) {
callback();
}
});
}
//# sourceMappingURL=client_subscription_impl.js.map