node-opcua-client 2.123.0 → 2.125.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/alarms_and_conditions/client_alarm_tools.js.map +1 -1
- package/dist/alarms_and_conditions/client_tools.js.map +1 -1
- package/dist/client_monitored_item_toolbox.js.map +1 -1
- package/dist/client_session_keepalive_manager.js.map +1 -1
- package/dist/client_utils.js.map +1 -1
- package/dist/private/client_base_impl.d.ts +11 -4
- package/dist/private/client_base_impl.js +130 -70
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_monitored_item_group_impl.js.map +1 -1
- package/dist/private/client_monitored_item_impl.js.map +1 -1
- package/dist/private/client_publish_engine.d.ts +9 -4
- package/dist/private/client_publish_engine.js +5 -99
- package/dist/private/client_publish_engine.js.map +1 -1
- package/dist/private/client_session_impl.d.ts +20 -4
- package/dist/private/client_session_impl.js +5 -24
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/client_subscription_impl.d.ts +5 -8
- package/dist/private/client_subscription_impl.js +83 -174
- package/dist/private/client_subscription_impl.js.map +1 -1
- package/dist/private/i_private_client.d.ts +0 -1
- package/dist/private/opcua_client_impl.js +1 -1
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/private/performance.js.map +1 -1
- package/dist/private/reconnection/client_publish_engine_reconnection.d.ts +2 -0
- package/dist/private/reconnection/client_publish_engine_reconnection.js +118 -0
- package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -0
- package/dist/private/reconnection/client_reconnection.d.ts +2 -0
- package/dist/private/reconnection/client_reconnection.js +20 -0
- package/dist/private/reconnection/client_reconnection.js.map +1 -0
- package/dist/private/reconnection/client_subscription_reconnection.d.ts +7 -0
- package/dist/private/reconnection/client_subscription_reconnection.js +124 -0
- package/dist/private/reconnection/client_subscription_reconnection.js.map +1 -0
- package/dist/private/reconnection/reconnection.d.ts +12 -0
- package/dist/private/reconnection/reconnection.js +564 -0
- package/dist/private/reconnection/reconnection.js.map +1 -0
- package/dist/tools/findservers.js.map +1 -1
- package/dist/tools/read_history_server_capabilities.js.map +1 -1
- package/dist/verify.js.map +1 -1
- package/package.json +43 -43
- package/source/index.ts +4 -1
- package/source/opcua_client.ts +11 -5
- package/source/private/client_base_impl.ts +136 -81
- package/source/private/client_publish_engine.ts +13 -129
- package/source/private/client_session_impl.ts +56 -78
- package/source/private/client_subscription_impl.ts +85 -207
- package/source/private/i_private_client.ts +0 -2
- package/source/private/opcua_client_impl.ts +16 -149
- package/source/private/reconnection/client_publish_engine_reconnection.ts +146 -0
- package/source/private/reconnection/client_reconnection.ts +17 -0
- package/source/private/reconnection/client_subscription_reconnection.ts +124 -0
- package/source/{reconnection.ts → private/reconnection/reconnection.ts} +121 -76
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
// tslint:disable:unified-signatures
|
|
5
5
|
import { EventEmitter } from "events";
|
|
6
|
-
import async from "async";
|
|
7
6
|
import chalk from "chalk";
|
|
8
7
|
|
|
9
8
|
import { assert } from "node-opcua-assert";
|
|
@@ -13,14 +12,11 @@ import { resolveNodeId } from "node-opcua-nodeid";
|
|
|
13
12
|
|
|
14
13
|
import { ReadValueIdOptions, TimestampsToReturn } from "node-opcua-service-read";
|
|
15
14
|
import {
|
|
16
|
-
CreateMonitoredItemsRequest,
|
|
17
|
-
CreateMonitoredItemsResponse,
|
|
18
15
|
CreateSubscriptionRequest,
|
|
19
16
|
CreateSubscriptionResponse,
|
|
20
17
|
DataChangeNotification,
|
|
21
18
|
DeleteMonitoredItemsResponse,
|
|
22
19
|
DeleteSubscriptionsResponse,
|
|
23
|
-
MonitoredItemCreateRequestOptions,
|
|
24
20
|
MonitoringParametersOptions,
|
|
25
21
|
NotificationMessage,
|
|
26
22
|
StatusChangeNotification,
|
|
@@ -37,9 +33,7 @@ import { StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
|
37
33
|
import { Callback, ErrorCallback } from "node-opcua-status-code";
|
|
38
34
|
import { isNullOrUndefined } from "node-opcua-utils";
|
|
39
35
|
import { promoteOpaqueStructureInNotificationData } from "node-opcua-client-dynamic-extension-object";
|
|
40
|
-
import { createMonitoredItemsLimit, IBasicSessionReadAsync, readOperationLimits } from "node-opcua-pseudo-session";
|
|
41
36
|
|
|
42
|
-
import { IBasicSessionWithSubscription } from "node-opcua-pseudo-session";
|
|
43
37
|
import { ClientMonitoredItemBase } from "../client_monitored_item_base";
|
|
44
38
|
import { ClientMonitoredItemGroup } from "../client_monitored_item_group";
|
|
45
39
|
import { ClientSession, MonitoredItemData, SubscriptionId } from "../client_session";
|
|
@@ -59,13 +53,13 @@ import { ClientSidePublishEngine } from "./client_publish_engine";
|
|
|
59
53
|
import { ClientSessionImpl } from "./client_session_impl";
|
|
60
54
|
import { detectLongOperation } from "./performance";
|
|
61
55
|
|
|
62
|
-
const debugLog = make_debugLog(
|
|
63
|
-
const doDebug = checkDebugFlag(
|
|
64
|
-
const warningLog = make_warningLog(
|
|
56
|
+
const debugLog = make_debugLog("CLIENT_SUBSCRIPTION");
|
|
57
|
+
const doDebug = checkDebugFlag("CLIENT_SUBSCRIPTION");
|
|
58
|
+
const warningLog = make_warningLog("CLIENT_SUBSCRIPTION");
|
|
65
59
|
|
|
66
|
-
const PENDING_SUBSCRIPTION_ID = 0xc0cac01a;
|
|
67
|
-
const TERMINATED_SUBSCRIPTION_ID = 0xc0cac01b;
|
|
68
|
-
const TERMINATING_SUBSCRIPTION_ID = 0xc0cac01c;
|
|
60
|
+
export const PENDING_SUBSCRIPTION_ID = 0xc0cac01a;
|
|
61
|
+
export const TERMINATED_SUBSCRIPTION_ID = 0xc0cac01b;
|
|
62
|
+
export const TERMINATING_SUBSCRIPTION_ID = 0xc0cac01c;
|
|
69
63
|
|
|
70
64
|
const minimumMaxKeepAliveCount = 3;
|
|
71
65
|
|
|
@@ -122,20 +116,6 @@ function displayKeepAliveWarning(sessionTimeout: number, maxKeepAliveCount: numb
|
|
|
122
116
|
return false;
|
|
123
117
|
}
|
|
124
118
|
|
|
125
|
-
function createMonitoredItemsAndRespectOperationalLimits(
|
|
126
|
-
session: IBasicSessionReadAsync & IBasicSessionWithSubscription,
|
|
127
|
-
createMonitorItemsRequest: CreateMonitoredItemsRequest,
|
|
128
|
-
callback: (err: Error | null, response?: CreateMonitoredItemsResponse) => void
|
|
129
|
-
) {
|
|
130
|
-
readOperationLimits(session)
|
|
131
|
-
.then((operationalLimits) => {
|
|
132
|
-
createMonitoredItemsLimit(operationalLimits.maxMonitoredItemsPerCall || 0, session, createMonitorItemsRequest)
|
|
133
|
-
.then((createMonitoredItemResponse) => callback(null, createMonitoredItemResponse))
|
|
134
|
-
.catch(callback);
|
|
135
|
-
})
|
|
136
|
-
.catch(callback);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
119
|
export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscription {
|
|
140
120
|
/**
|
|
141
121
|
* the associated session
|
|
@@ -171,9 +151,8 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
|
|
|
171
151
|
public publishEngine: ClientSidePublishEngine;
|
|
172
152
|
|
|
173
153
|
public lastSequenceNumber: number;
|
|
174
|
-
private lastRequestSentTime: Date;
|
|
175
154
|
private _nextClientHandle = 0;
|
|
176
|
-
|
|
155
|
+
public hasTimedOut: boolean;
|
|
177
156
|
|
|
178
157
|
constructor(session: ClientSession, options: ClientSubscriptionOptions) {
|
|
179
158
|
super();
|
|
@@ -219,7 +198,7 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
|
|
|
219
198
|
this.lifetimeCount = options.requestedLifetimeCount;
|
|
220
199
|
this.maxKeepAliveCount = options.requestedMaxKeepAliveCount;
|
|
221
200
|
this.maxNotificationsPerPublish = options.maxNotificationsPerPublish || 0;
|
|
222
|
-
this.publishingEnabled = options.publishingEnabled;
|
|
201
|
+
this.publishingEnabled = options.publishingEnabled === undefined ? true : options.publishingEnabled;
|
|
223
202
|
this.priority = options.priority;
|
|
224
203
|
|
|
225
204
|
this.subscriptionId = PENDING_SUBSCRIPTION_ID;
|
|
@@ -227,8 +206,6 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
|
|
|
227
206
|
this._nextClientHandle = 0;
|
|
228
207
|
this.monitoredItems = {};
|
|
229
208
|
|
|
230
|
-
this.lastRequestSentTime = new Date(1, 1, 1970);
|
|
231
|
-
|
|
232
209
|
/**
|
|
233
210
|
* set to True when the server has notified us that this subscription has timed out
|
|
234
211
|
* ( maxLifeCounter x published interval without being able to process a PublishRequest
|
|
@@ -238,7 +215,7 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
|
|
|
238
215
|
this.hasTimedOut = false;
|
|
239
216
|
|
|
240
217
|
setImmediate(() => {
|
|
241
|
-
|
|
218
|
+
__create_subscription(this, (err?: Error) => {
|
|
242
219
|
if (!err) {
|
|
243
220
|
setImmediate(() => {
|
|
244
221
|
/**
|
|
@@ -536,103 +513,6 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
|
|
|
536
513
|
this.session.getMonitoredItems(this.subscriptionId, args[0]);
|
|
537
514
|
}
|
|
538
515
|
|
|
539
|
-
/**
|
|
540
|
-
* utility function to recreate new subscription
|
|
541
|
-
* @method recreateSubscriptionAndMonitoredItem
|
|
542
|
-
*/
|
|
543
|
-
public recreateSubscriptionAndMonitoredItem(callback: ErrorCallback): void {
|
|
544
|
-
debugLog("ClientSubscription#recreateSubscriptionAndMonitoredItem");
|
|
545
|
-
|
|
546
|
-
if (this.subscriptionId === TERMINATED_SUBSCRIPTION_ID) {
|
|
547
|
-
debugLog("Subscription is not in a valid state");
|
|
548
|
-
return callback();
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
const oldMonitoredItems = this.monitoredItems;
|
|
552
|
-
|
|
553
|
-
this.publishEngine.unregisterSubscription(this.subscriptionId);
|
|
554
|
-
|
|
555
|
-
async.series(
|
|
556
|
-
[
|
|
557
|
-
(innerCallback: ErrorCallback) => {
|
|
558
|
-
this.__create_subscription(innerCallback);
|
|
559
|
-
},
|
|
560
|
-
(innerCallback: ErrorCallback) => {
|
|
561
|
-
const test = this.publishEngine.getSubscription(this.subscriptionId);
|
|
562
|
-
|
|
563
|
-
debugLog("recreating ", Object.keys(oldMonitoredItems).length, " monitored Items");
|
|
564
|
-
// re-create monitored items
|
|
565
|
-
const itemsToCreate: MonitoredItemCreateRequestOptions[] = [];
|
|
566
|
-
|
|
567
|
-
for (const monitoredItem of Object.values(oldMonitoredItems)) {
|
|
568
|
-
assert(monitoredItem.monitoringParameters.clientHandle > 0);
|
|
569
|
-
itemsToCreate.push({
|
|
570
|
-
itemToMonitor: monitoredItem.itemToMonitor,
|
|
571
|
-
monitoringMode: monitoredItem.monitoringMode,
|
|
572
|
-
requestedParameters: monitoredItem.monitoringParameters
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
const createMonitorItemsRequest = new CreateMonitoredItemsRequest({
|
|
577
|
-
itemsToCreate,
|
|
578
|
-
subscriptionId: this.subscriptionId,
|
|
579
|
-
timestampsToReturn: TimestampsToReturn.Both // this.timestampsToReturn,
|
|
580
|
-
});
|
|
581
|
-
|
|
582
|
-
const session = this.session;
|
|
583
|
-
// istanbul ignore next
|
|
584
|
-
if (!session) {
|
|
585
|
-
return innerCallback(new Error("no session"));
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
debugLog("Recreating ", itemsToCreate.length, " monitored items");
|
|
589
|
-
|
|
590
|
-
createMonitoredItemsAndRespectOperationalLimits(
|
|
591
|
-
session,
|
|
592
|
-
createMonitorItemsRequest,
|
|
593
|
-
(err: Error | null, response?: CreateMonitoredItemsResponse) => {
|
|
594
|
-
if (err) {
|
|
595
|
-
debugLog("Recreating monitored item has failed with ", err.message);
|
|
596
|
-
return innerCallback(err);
|
|
597
|
-
}
|
|
598
|
-
/* istanbul ignore next */
|
|
599
|
-
if (!response) {
|
|
600
|
-
return innerCallback(new Error("Internal Error"));
|
|
601
|
-
}
|
|
602
|
-
const monitoredItemResults = response.results || [];
|
|
603
|
-
|
|
604
|
-
monitoredItemResults.forEach((monitoredItemResult, index) => {
|
|
605
|
-
const itemToCreate = itemsToCreate[index];
|
|
606
|
-
/* istanbul ignore next */
|
|
607
|
-
if (!itemToCreate || !itemToCreate.requestedParameters) {
|
|
608
|
-
throw new Error("Internal Error");
|
|
609
|
-
}
|
|
610
|
-
const clientHandle = itemToCreate.requestedParameters.clientHandle;
|
|
611
|
-
/* istanbul ignore next */
|
|
612
|
-
if (!clientHandle) {
|
|
613
|
-
throw new Error("Internal Error");
|
|
614
|
-
}
|
|
615
|
-
const monitoredItem = this.monitoredItems[clientHandle] as ClientMonitoredItemImpl;
|
|
616
|
-
if (monitoredItem) {
|
|
617
|
-
monitoredItem._applyResult(monitoredItemResult);
|
|
618
|
-
} else {
|
|
619
|
-
warningLog("cannot find monitored item for clientHandle !:", clientHandle);
|
|
620
|
-
}
|
|
621
|
-
});
|
|
622
|
-
innerCallback();
|
|
623
|
-
}
|
|
624
|
-
);
|
|
625
|
-
}
|
|
626
|
-
],
|
|
627
|
-
(err) => {
|
|
628
|
-
if (err) {
|
|
629
|
-
warningLog(err.message);
|
|
630
|
-
}
|
|
631
|
-
callback(err!);
|
|
632
|
-
}
|
|
633
|
-
);
|
|
634
|
-
}
|
|
635
|
-
|
|
636
516
|
public toString(): string {
|
|
637
517
|
let str = "";
|
|
638
518
|
str += "subscriptionId : " + this.subscriptionId + "\n";
|
|
@@ -642,9 +522,12 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
|
|
|
642
522
|
str += "hasTimedOut : " + this.hasTimedOut + "\n";
|
|
643
523
|
|
|
644
524
|
const timeToLive = this.lifetimeCount * this.publishingInterval;
|
|
645
|
-
str += "
|
|
646
|
-
str += "
|
|
647
|
-
|
|
525
|
+
str += "(maxKeepAliveCount*publishingInterval: " + this.publishingInterval * this.maxKeepAliveCount + " ms)\n";
|
|
526
|
+
str += "(maxLifetimeCount*publishingInterval: " + timeToLive + " ms)\n";
|
|
527
|
+
|
|
528
|
+
const lastRequestSentTime = this.publishEngine.lastRequestSentTime;
|
|
529
|
+
str += "lastRequestSentTime : " + lastRequestSentTime.toString() + "\n";
|
|
530
|
+
const duration = Date.now() - lastRequestSentTime.getTime();
|
|
648
531
|
const extra =
|
|
649
532
|
duration - timeToLive > 0
|
|
650
533
|
? chalk.red(" expired since " + (duration - timeToLive) / 1000 + " seconds")
|
|
@@ -654,7 +537,6 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
|
|
|
654
537
|
str += "has expired : " + (duration > timeToLive) + "\n";
|
|
655
538
|
|
|
656
539
|
str += "(session timeout : " + this.session.timeout + " ms)\n";
|
|
657
|
-
str += "(maxKeepAliveCount*publishingInterval: " + this.publishingInterval * this.session.timeout + " ms)\n";
|
|
658
540
|
|
|
659
541
|
return str;
|
|
660
542
|
}
|
|
@@ -665,7 +547,8 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
|
|
|
665
547
|
public evaluateRemainingLifetime(): number {
|
|
666
548
|
const now = Date.now();
|
|
667
549
|
const timeout = this.publishingInterval * this.lifetimeCount;
|
|
668
|
-
const
|
|
550
|
+
const lastRequestSentTime = this.publishEngine.lastRequestSentTime;
|
|
551
|
+
const expiryTime = lastRequestSentTime.getTime() + timeout;
|
|
669
552
|
return Math.max(0, expiryTime - now);
|
|
670
553
|
}
|
|
671
554
|
|
|
@@ -710,75 +593,6 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
|
|
|
710
593
|
setImmediate(waitForSubscriptionAndMonitor);
|
|
711
594
|
}
|
|
712
595
|
|
|
713
|
-
private __create_subscription(callback: ErrorCallback) {
|
|
714
|
-
assert(typeof callback === "function");
|
|
715
|
-
|
|
716
|
-
// istanbul ignore next
|
|
717
|
-
if (!this.hasSession) {
|
|
718
|
-
return callback(new Error("No Session"));
|
|
719
|
-
}
|
|
720
|
-
const session = this.session;
|
|
721
|
-
|
|
722
|
-
debugLog(chalk.yellow.bold("ClientSubscription created "));
|
|
723
|
-
|
|
724
|
-
const request = new CreateSubscriptionRequest({
|
|
725
|
-
maxNotificationsPerPublish: this.maxNotificationsPerPublish,
|
|
726
|
-
priority: this.priority,
|
|
727
|
-
publishingEnabled: this.publishingEnabled,
|
|
728
|
-
requestedLifetimeCount: this.lifetimeCount,
|
|
729
|
-
requestedMaxKeepAliveCount: this.maxKeepAliveCount,
|
|
730
|
-
requestedPublishingInterval: this.publishingInterval
|
|
731
|
-
});
|
|
732
|
-
|
|
733
|
-
session.createSubscription(request, (err: Error | null, response?: CreateSubscriptionResponse) => {
|
|
734
|
-
if (err) {
|
|
735
|
-
/* istanbul ignore next */
|
|
736
|
-
this.emit("internal_error", err);
|
|
737
|
-
if (callback) {
|
|
738
|
-
return callback(err);
|
|
739
|
-
}
|
|
740
|
-
return;
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
/* istanbul ignore next */
|
|
744
|
-
if (!response) {
|
|
745
|
-
return callback(new Error("internal error"));
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
if (!this.hasSession) {
|
|
749
|
-
return callback(new Error("createSubscription has failed = > no session"));
|
|
750
|
-
}
|
|
751
|
-
assert(this.hasSession);
|
|
752
|
-
|
|
753
|
-
this.subscriptionId = response.subscriptionId;
|
|
754
|
-
this.publishingInterval = response.revisedPublishingInterval;
|
|
755
|
-
this.lifetimeCount = response.revisedLifetimeCount;
|
|
756
|
-
this.maxKeepAliveCount = response.revisedMaxKeepAliveCount;
|
|
757
|
-
|
|
758
|
-
this.timeoutHint = Math.min((this.maxKeepAliveCount + 10) * this.publishingInterval * 2, 0x7ffff);
|
|
759
|
-
|
|
760
|
-
displayKeepAliveWarning(this.session.timeout, this.maxKeepAliveCount, this.publishingInterval);
|
|
761
|
-
ClientSubscription.ignoreNextWarning = false;
|
|
762
|
-
|
|
763
|
-
// istanbul ignore next
|
|
764
|
-
if (doDebug) {
|
|
765
|
-
debugLog(chalk.yellow.bold("registering callback"));
|
|
766
|
-
debugLog(chalk.yellow.bold("publishingInterval "), this.publishingInterval);
|
|
767
|
-
debugLog(chalk.yellow.bold("lifetimeCount "), this.lifetimeCount);
|
|
768
|
-
debugLog(chalk.yellow.bold("maxKeepAliveCount "), this.maxKeepAliveCount);
|
|
769
|
-
debugLog(chalk.yellow.bold("publish request timeout hint = "), this.timeoutHint);
|
|
770
|
-
debugLog(chalk.yellow.bold("hasTimedOut "), this.hasTimedOut);
|
|
771
|
-
debugLog(chalk.yellow.bold("timeoutHint for publish request "), this.timeoutHint);
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
this.publishEngine.registerSubscription(this);
|
|
775
|
-
|
|
776
|
-
if (callback) {
|
|
777
|
-
callback();
|
|
778
|
-
}
|
|
779
|
-
});
|
|
780
|
-
}
|
|
781
|
-
|
|
782
596
|
private __on_publish_response_DataChangeNotification(notification: DataChangeNotification) {
|
|
783
597
|
assert(notification.schema.name === "DataChangeNotification");
|
|
784
598
|
|
|
@@ -939,7 +753,7 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
|
|
|
939
753
|
warningLog(
|
|
940
754
|
`[NODE-OPCUA-W32]}: monitored.item event handler takes too much time : operation duration ${duration} ms [repeated ${
|
|
941
755
|
s(this).$_slowNotifCount
|
|
942
|
-
} times]\n please ensure that your
|
|
756
|
+
} times]\n please ensure that your monitoredItem event handler is not blocking the event loop.`
|
|
943
757
|
);
|
|
944
758
|
}
|
|
945
759
|
);
|
|
@@ -1057,12 +871,76 @@ ClientSubscriptionImpl.prototype.monitor = thenify.withCallback(ClientSubscripti
|
|
|
1057
871
|
ClientSubscriptionImpl.prototype.monitorItems = thenify.withCallback(ClientSubscriptionImpl.prototype.monitorItems);
|
|
1058
872
|
ClientSubscriptionImpl.prototype.setTriggering = thenify.withCallback(ClientSubscriptionImpl.prototype.setTriggering);
|
|
1059
873
|
ClientSubscriptionImpl.prototype.modify = thenify.withCallback(ClientSubscriptionImpl.prototype.modify);
|
|
1060
|
-
ClientSubscriptionImpl.prototype.recreateSubscriptionAndMonitoredItem = thenify.withCallback(
|
|
1061
|
-
ClientSubscriptionImpl.prototype.recreateSubscriptionAndMonitoredItem
|
|
1062
|
-
);
|
|
1063
874
|
ClientSubscriptionImpl.prototype.terminate = thenify.withCallback(ClientSubscriptionImpl.prototype.terminate);
|
|
1064
875
|
ClientSubscriptionImpl.prototype.getMonitoredItems = thenify.withCallback(ClientSubscriptionImpl.prototype.getMonitoredItems);
|
|
1065
876
|
|
|
1066
877
|
ClientSubscription.create = (clientSession: ClientSession, options: ClientSubscriptionOptions) => {
|
|
1067
878
|
return new ClientSubscriptionImpl(clientSession, options);
|
|
1068
879
|
};
|
|
880
|
+
|
|
881
|
+
export function __create_subscription(subscription: ClientSubscriptionImpl, callback: ErrorCallback) {
|
|
882
|
+
// istanbul ignore next
|
|
883
|
+
if (!subscription.hasSession) {
|
|
884
|
+
return callback(new Error("__create_subscription: subscription has no Session"));
|
|
885
|
+
}
|
|
886
|
+
const session = subscription.session;
|
|
887
|
+
|
|
888
|
+
debugLog(chalk.yellow.bold("ClientSubscription created "));
|
|
889
|
+
|
|
890
|
+
const request = new CreateSubscriptionRequest({
|
|
891
|
+
maxNotificationsPerPublish: subscription.maxNotificationsPerPublish,
|
|
892
|
+
priority: subscription.priority,
|
|
893
|
+
publishingEnabled: subscription.publishingEnabled,
|
|
894
|
+
requestedLifetimeCount: subscription.lifetimeCount,
|
|
895
|
+
requestedMaxKeepAliveCount: subscription.maxKeepAliveCount,
|
|
896
|
+
requestedPublishingInterval: subscription.publishingInterval
|
|
897
|
+
});
|
|
898
|
+
|
|
899
|
+
session.createSubscription(request, (err: Error | null, response?: CreateSubscriptionResponse) => {
|
|
900
|
+
if (err) {
|
|
901
|
+
/* istanbul ignore next */
|
|
902
|
+
subscription.emit("internal_error", err);
|
|
903
|
+
if (callback) {
|
|
904
|
+
return callback(err);
|
|
905
|
+
}
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/* istanbul ignore next */
|
|
910
|
+
if (!response) {
|
|
911
|
+
return callback(new Error("internal error"));
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
if (!subscription.hasSession) {
|
|
915
|
+
return callback(new Error("createSubscription has failed = > no session"));
|
|
916
|
+
}
|
|
917
|
+
assert(subscription.hasSession);
|
|
918
|
+
|
|
919
|
+
subscription.subscriptionId = response.subscriptionId;
|
|
920
|
+
subscription.publishingInterval = response.revisedPublishingInterval;
|
|
921
|
+
subscription.lifetimeCount = response.revisedLifetimeCount;
|
|
922
|
+
subscription.maxKeepAliveCount = response.revisedMaxKeepAliveCount;
|
|
923
|
+
|
|
924
|
+
subscription.timeoutHint = Math.min((subscription.maxKeepAliveCount + 10) * subscription.publishingInterval * 2, 0x7ffff);
|
|
925
|
+
|
|
926
|
+
displayKeepAliveWarning(subscription.session.timeout, subscription.maxKeepAliveCount, subscription.publishingInterval);
|
|
927
|
+
ClientSubscription.ignoreNextWarning = false;
|
|
928
|
+
|
|
929
|
+
// istanbul ignore next
|
|
930
|
+
if (doDebug) {
|
|
931
|
+
debugLog(chalk.yellow.bold("registering callback"));
|
|
932
|
+
debugLog(chalk.yellow.bold("publishingInterval "), subscription.publishingInterval);
|
|
933
|
+
debugLog(chalk.yellow.bold("lifetimeCount "), subscription.lifetimeCount);
|
|
934
|
+
debugLog(chalk.yellow.bold("maxKeepAliveCount "), subscription.maxKeepAliveCount);
|
|
935
|
+
debugLog(chalk.yellow.bold("publish request timeout hint = "), subscription.timeoutHint);
|
|
936
|
+
debugLog(chalk.yellow.bold("hasTimedOut "), subscription.hasTimedOut);
|
|
937
|
+
debugLog(chalk.yellow.bold("timeoutHint for publish request "), subscription.timeoutHint);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
subscription.publishEngine.registerSubscription(subscription);
|
|
941
|
+
|
|
942
|
+
if (callback) {
|
|
943
|
+
callback();
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
}
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { callbackify } from "util";
|
|
5
5
|
import { randomBytes, createPublicKey } from "crypto";
|
|
6
|
-
import async from "async";
|
|
7
6
|
import chalk from "chalk";
|
|
8
7
|
|
|
9
8
|
import { assert } from "node-opcua-assert";
|
|
@@ -38,6 +37,7 @@ import { ErrorCallback, Callback } from "node-opcua-status-code";
|
|
|
38
37
|
|
|
39
38
|
import { SignatureDataOptions, UserIdentityToken } from "node-opcua-types";
|
|
40
39
|
import { isNullOrUndefined, matchUri } from "node-opcua-utils";
|
|
40
|
+
import { readNamespaceArray } from "node-opcua-pseudo-session";
|
|
41
41
|
|
|
42
42
|
import { ClientSession } from "../client_session";
|
|
43
43
|
import { ClientSubscription, ClientSubscriptionOptions } from "../client_subscription";
|
|
@@ -51,7 +51,7 @@ import {
|
|
|
51
51
|
} from "../opcua_client";
|
|
52
52
|
import { AnonymousIdentity, UserIdentityInfo, UserIdentityInfoUserName, UserIdentityInfoX509 } from "../user_identity_info";
|
|
53
53
|
|
|
54
|
-
import { repair_client_sessions } from "
|
|
54
|
+
import { repair_client_sessions } from "./reconnection/reconnection";
|
|
55
55
|
import { ClientBaseImpl } from "./client_base_impl";
|
|
56
56
|
import { ClientSessionImpl } from "./client_session_impl";
|
|
57
57
|
import { ClientSubscriptionImpl } from "./client_subscription_impl";
|
|
@@ -603,151 +603,14 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
603
603
|
});
|
|
604
604
|
return session;
|
|
605
605
|
}
|
|
606
|
+
|
|
606
607
|
/**
|
|
607
|
-
*
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
inner_func: (session: ClientSession) => Promise<T>
|
|
612
|
-
): Promise<T>;
|
|
613
|
-
|
|
614
|
-
public withSession(
|
|
615
|
-
endpointUrl: string | EndpointWithUserIdentity,
|
|
616
|
-
inner_func: (session: ClientSession, done: (err?: Error) => void) => void,
|
|
617
|
-
callback: (err?: Error) => void
|
|
618
|
-
): void;
|
|
619
|
-
/**
|
|
620
|
-
* @internal
|
|
621
|
-
* @param args
|
|
608
|
+
*
|
|
609
|
+
* @param connectionPoint
|
|
610
|
+
* @param func
|
|
611
|
+
* @returns
|
|
622
612
|
*/
|
|
623
|
-
public
|
|
624
|
-
connectionPoint: string | EndpointWithUserIdentity,
|
|
625
|
-
inner_func: (session: ClientSession, done: (err?: Error) => void) => void,
|
|
626
|
-
...args: any[]
|
|
627
|
-
): any {
|
|
628
|
-
const endpointUrl: string = typeof connectionPoint === "string" ? connectionPoint : connectionPoint.endpointUrl;
|
|
629
|
-
const userIdentity: UserIdentityInfo =
|
|
630
|
-
typeof connectionPoint === "string" ? { type: UserTokenType.Anonymous } : connectionPoint.userIdentity;
|
|
631
|
-
|
|
632
|
-
const callback = args[0];
|
|
633
|
-
|
|
634
|
-
assert(typeof inner_func === "function", "expecting inner function");
|
|
635
|
-
assert(typeof callback === "function", "expecting callback function");
|
|
636
|
-
|
|
637
|
-
let theSession: ClientSession;
|
|
638
|
-
let the_error: Error | undefined;
|
|
639
|
-
|
|
640
|
-
let need_disconnect = false;
|
|
641
|
-
async.series(
|
|
642
|
-
[
|
|
643
|
-
// step 1 : connect to
|
|
644
|
-
(innerCallback: ErrorCallback) => {
|
|
645
|
-
this.connect(endpointUrl, (err?: Error) => {
|
|
646
|
-
need_disconnect = true;
|
|
647
|
-
if (err) {
|
|
648
|
-
warningLog(err.message);
|
|
649
|
-
errorLog(" cannot connect to endpoint :", endpointUrl);
|
|
650
|
-
}
|
|
651
|
-
innerCallback(err);
|
|
652
|
-
});
|
|
653
|
-
},
|
|
654
|
-
|
|
655
|
-
// step 2 : createSession
|
|
656
|
-
(innerCallback: ErrorCallback) => {
|
|
657
|
-
this.createSession2(userIdentity, (err: Error | null, session?: ClientSession) => {
|
|
658
|
-
if (err) {
|
|
659
|
-
return innerCallback(err);
|
|
660
|
-
}
|
|
661
|
-
if (!session) {
|
|
662
|
-
return innerCallback(new Error("internal error"));
|
|
663
|
-
}
|
|
664
|
-
theSession = session;
|
|
665
|
-
innerCallback();
|
|
666
|
-
});
|
|
667
|
-
},
|
|
668
|
-
|
|
669
|
-
(innerCallback: ErrorCallback) => {
|
|
670
|
-
try {
|
|
671
|
-
inner_func(theSession, (err?: Error) => {
|
|
672
|
-
the_error = err;
|
|
673
|
-
innerCallback();
|
|
674
|
-
});
|
|
675
|
-
} catch (err) {
|
|
676
|
-
errorLog("Exception catch in inner function, check your code ", err);
|
|
677
|
-
errorLog("OPCUAClientImpl#withClientSession", (<Error>err).message);
|
|
678
|
-
the_error = err as Error;
|
|
679
|
-
innerCallback();
|
|
680
|
-
}
|
|
681
|
-
},
|
|
682
|
-
|
|
683
|
-
// close session
|
|
684
|
-
(innerCallback: ErrorCallback) => {
|
|
685
|
-
theSession.close(/*deleteSubscriptions=*/ true, (err?: Error) => {
|
|
686
|
-
if (err) {
|
|
687
|
-
debugLog("OPCUAClientImpl#withClientSession: session closed failed ?");
|
|
688
|
-
}
|
|
689
|
-
innerCallback();
|
|
690
|
-
});
|
|
691
|
-
},
|
|
692
|
-
|
|
693
|
-
(innerCallback: ErrorCallback) => {
|
|
694
|
-
this.disconnect((err?: Error) => {
|
|
695
|
-
need_disconnect = false;
|
|
696
|
-
if (err) {
|
|
697
|
-
errorLog("OPCUAClientImpl#withClientSession: client disconnect failed ?");
|
|
698
|
-
}
|
|
699
|
-
innerCallback();
|
|
700
|
-
});
|
|
701
|
-
}
|
|
702
|
-
],
|
|
703
|
-
(err1) => {
|
|
704
|
-
if (err1) {
|
|
705
|
-
errorLog("err", err1.message);
|
|
706
|
-
}
|
|
707
|
-
if (need_disconnect) {
|
|
708
|
-
errorLog("Disconnecting client after failure");
|
|
709
|
-
this.disconnect((err2) => {
|
|
710
|
-
return callback(the_error || err1 || err2);
|
|
711
|
-
});
|
|
712
|
-
} else {
|
|
713
|
-
return callback(the_error || err1);
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
);
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
public withSubscription(
|
|
720
|
-
endpointUrl: string | EndpointWithUserIdentity,
|
|
721
|
-
subscriptionParameters: ClientSubscriptionOptions,
|
|
722
|
-
innerFunc: (session: ClientSession, subscription: ClientSubscription, done: (err?: Error) => void) => void,
|
|
723
|
-
callback: (err?: Error) => void
|
|
724
|
-
): void {
|
|
725
|
-
assert(typeof innerFunc === "function");
|
|
726
|
-
assert(typeof callback === "function");
|
|
727
|
-
|
|
728
|
-
this.withSession(
|
|
729
|
-
endpointUrl,
|
|
730
|
-
(session: ClientSession, done: (err?: Error) => void) => {
|
|
731
|
-
assert(typeof done === "function");
|
|
732
|
-
|
|
733
|
-
const subscription = new ClientSubscriptionImpl(session as ClientSessionImpl, subscriptionParameters);
|
|
734
|
-
|
|
735
|
-
try {
|
|
736
|
-
innerFunc(session, subscription, (err?: Error) => {
|
|
737
|
-
subscription.terminate((err1?: Error) => {
|
|
738
|
-
done(err1);
|
|
739
|
-
});
|
|
740
|
-
});
|
|
741
|
-
} catch (err) {
|
|
742
|
-
debugLog(err);
|
|
743
|
-
done(err as Error);
|
|
744
|
-
}
|
|
745
|
-
},
|
|
746
|
-
callback
|
|
747
|
-
);
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
public async withSessionAsync(connectionPoint: string | EndpointWithUserIdentity, func: WithSessionFuncP<any>): Promise<any> {
|
|
613
|
+
public async withSessionAsync<T>(connectionPoint: string | EndpointWithUserIdentity, func: WithSessionFuncP<T>): Promise<T> {
|
|
751
614
|
assert(typeof func === "function");
|
|
752
615
|
assert(func.length === 1, "expecting a single argument in func");
|
|
753
616
|
|
|
@@ -764,6 +627,10 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
764
627
|
try {
|
|
765
628
|
const session = await this.createSession2(userIdentity);
|
|
766
629
|
let result;
|
|
630
|
+
|
|
631
|
+
// always need this
|
|
632
|
+
await readNamespaceArray(session);
|
|
633
|
+
|
|
767
634
|
try {
|
|
768
635
|
result = await func(session);
|
|
769
636
|
return result;
|
|
@@ -781,12 +648,12 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
781
648
|
}
|
|
782
649
|
}
|
|
783
650
|
|
|
784
|
-
public async withSubscriptionAsync(
|
|
651
|
+
public async withSubscriptionAsync<T>(
|
|
785
652
|
connectionPoint: string | EndpointWithUserIdentity,
|
|
786
653
|
parameters: ClientSubscriptionOptions,
|
|
787
|
-
func: WithSubscriptionFuncP<
|
|
788
|
-
): Promise<
|
|
789
|
-
await this.withSessionAsync(connectionPoint, async (session: ClientSession) => {
|
|
654
|
+
func: WithSubscriptionFuncP<T>
|
|
655
|
+
): Promise<T> {
|
|
656
|
+
return await this.withSessionAsync(connectionPoint, async (session: ClientSession) => {
|
|
790
657
|
assert(session, " session must exist");
|
|
791
658
|
const subscription = await session.createSubscription2(parameters);
|
|
792
659
|
try {
|