node-opcua-client 2.59.0 → 2.62.1
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/opcua_client.d.ts +4 -0
- package/dist/opcua_client.js +14 -0
- package/dist/opcua_client.js.map +1 -1
- package/dist/private/client_base_impl.js +19 -5
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_publish_engine.js +14 -5
- package/dist/private/client_publish_engine.js.map +1 -1
- package/dist/private/client_session_impl.js +1 -3
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/opcua_client_impl.d.ts +33 -0
- package/dist/private/opcua_client_impl.js +85 -10
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/reconnection.js +31 -15
- package/dist/reconnection.js.map +1 -1
- package/dist/tools/read_history_server_capabilities.js +1 -1
- package/dist/tools/read_history_server_capabilities.js.map +1 -1
- package/package.json +40 -40
- package/source/opcua_client.ts +13 -0
- package/source/private/client_base_impl.ts +19 -5
- package/source/private/client_publish_engine.ts +13 -6
- package/source/private/client_session_impl.ts +2 -4
- package/source/private/opcua_client_impl.ts +103 -11
- package/source/reconnection.ts +35 -17
- package/source/tools/read_history_server_capabilities.ts +1 -1
|
@@ -278,7 +278,7 @@ function createUserNameIdentityToken(
|
|
|
278
278
|
|
|
279
279
|
// istanbul ignore next
|
|
280
280
|
if (!cryptoFactory) {
|
|
281
|
-
throw new Error(" Unsupported security Policy");
|
|
281
|
+
throw new Error(" Unsupported security Policy "+ securityPolicy.toString());
|
|
282
282
|
}
|
|
283
283
|
|
|
284
284
|
identityToken = new UserNameIdentityToken({
|
|
@@ -418,6 +418,42 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
418
418
|
});
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
+
/**
|
|
422
|
+
* createSession2 create a session with persistance
|
|
423
|
+
*
|
|
424
|
+
* - if the server returns BadTooManySession, the method will make an other attempt
|
|
425
|
+
* unitl create session succeed or connection is closed.
|
|
426
|
+
*
|
|
427
|
+
* @experiemental
|
|
428
|
+
* @param userIdentityInfo
|
|
429
|
+
*/
|
|
430
|
+
public async createSession2(userIdentityInfo?: UserIdentityInfo): Promise<ClientSession>;
|
|
431
|
+
public createSession2(userIdentityInfo: UserIdentityInfo, callback: Callback<ClientSession>): void;
|
|
432
|
+
public createSession2(callback: Callback<ClientSession>): void;
|
|
433
|
+
public createSession2(...args: any[]): any {
|
|
434
|
+
if (args.length === 1) {
|
|
435
|
+
return this.createSession2({ type: UserTokenType.Anonymous }, args[0]);
|
|
436
|
+
}
|
|
437
|
+
const userIdentityInfo = args[0] as UserIdentityInfo;
|
|
438
|
+
const callback = args[1] as Callback<ClientSession>;
|
|
439
|
+
if (!this._secureChannel) {
|
|
440
|
+
// we do not have a connection anymore
|
|
441
|
+
return callback(new Error("Connection is closed"));
|
|
442
|
+
}
|
|
443
|
+
return this.createSession(args[0], (err: Error | null, session?: ClientSession) => {
|
|
444
|
+
if (err && err.message.match(/BadTooManySessions/)) {
|
|
445
|
+
const delayToRetry = 5; // seconds
|
|
446
|
+
errorLog(`TooManySession .... we need to retry later ... in ${delayToRetry} secondes`);
|
|
447
|
+
const retryCreateSessionTimer = setTimeout(() => {
|
|
448
|
+
errorLog("TooManySession .... now retrying");
|
|
449
|
+
this.createSession2(userIdentityInfo, callback);
|
|
450
|
+
}, delayToRetry * 1000);
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
callback(err, session);
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
421
457
|
/**
|
|
422
458
|
* @method changeSessionIdentity
|
|
423
459
|
* @param session
|
|
@@ -471,6 +507,52 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
471
507
|
return str;
|
|
472
508
|
}
|
|
473
509
|
|
|
510
|
+
/**
|
|
511
|
+
*
|
|
512
|
+
* @example
|
|
513
|
+
*
|
|
514
|
+
* ```javascript
|
|
515
|
+
*
|
|
516
|
+
* const session = await OPCUAClient.createSession(endpointUrl);
|
|
517
|
+
* const dataValue = await session.read({ nodeId, attributeId: AttributeIds.Value });
|
|
518
|
+
* await session.close();
|
|
519
|
+
*
|
|
520
|
+
* ```
|
|
521
|
+
* @stability experimental
|
|
522
|
+
*
|
|
523
|
+
* @param endpointUrl
|
|
524
|
+
* @param userIdentity
|
|
525
|
+
* @returns session
|
|
526
|
+
*
|
|
527
|
+
*
|
|
528
|
+
* const create
|
|
529
|
+
*/
|
|
530
|
+
public static async createSession(
|
|
531
|
+
endpointUrl: string,
|
|
532
|
+
userIdentity?: UserIdentityInfo,
|
|
533
|
+
clientOptions?: OPCUAClientOptions
|
|
534
|
+
): Promise<ClientSession> {
|
|
535
|
+
const client = OPCUAClient.create(clientOptions || {});
|
|
536
|
+
|
|
537
|
+
await client.connect(endpointUrl);
|
|
538
|
+
const session = await client.createSession2(userIdentity);
|
|
539
|
+
|
|
540
|
+
const oldClose = session.close as any;
|
|
541
|
+
(session as any).close = thenify.withCallback((...args: any[]): any => {
|
|
542
|
+
if (args.length === 1) {
|
|
543
|
+
return session.close(true, args[0]);
|
|
544
|
+
}
|
|
545
|
+
const deleteSubscriptions = args[0] as boolean;
|
|
546
|
+
const callback = args[1] as Callback<void>;
|
|
547
|
+
session.close = oldClose;
|
|
548
|
+
oldClose.call(session, deleteSubscriptions, (err?: Error) => {
|
|
549
|
+
client.disconnect((err?: Error | null) => {
|
|
550
|
+
callback(err!);
|
|
551
|
+
});
|
|
552
|
+
});
|
|
553
|
+
});
|
|
554
|
+
return session;
|
|
555
|
+
}
|
|
474
556
|
/**
|
|
475
557
|
* @method withSession
|
|
476
558
|
*/
|
|
@@ -484,7 +566,6 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
484
566
|
inner_func: (session: ClientSession, done: (err?: Error) => void) => void,
|
|
485
567
|
callback: (err?: Error) => void
|
|
486
568
|
): void;
|
|
487
|
-
|
|
488
569
|
/**
|
|
489
570
|
* @internal
|
|
490
571
|
* @param args
|
|
@@ -514,6 +595,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
514
595
|
this.connect(endpointUrl, (err?: Error) => {
|
|
515
596
|
need_disconnect = true;
|
|
516
597
|
if (err) {
|
|
598
|
+
warningLog(err.message);
|
|
517
599
|
errorLog(" cannot connect to endpoint :", endpointUrl);
|
|
518
600
|
}
|
|
519
601
|
innerCallback(err);
|
|
@@ -522,7 +604,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
522
604
|
|
|
523
605
|
// step 2 : createSession
|
|
524
606
|
(innerCallback: ErrorCallback) => {
|
|
525
|
-
this.
|
|
607
|
+
this.createSession2(userIdentity, (err: Error | null, session?: ClientSession) => {
|
|
526
608
|
if (err) {
|
|
527
609
|
return innerCallback(err);
|
|
528
610
|
}
|
|
@@ -570,7 +652,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
570
652
|
],
|
|
571
653
|
(err1) => {
|
|
572
654
|
if (err1) {
|
|
573
|
-
console.log("err", err1);
|
|
655
|
+
console.log("err", err1.message);
|
|
574
656
|
}
|
|
575
657
|
if (need_disconnect) {
|
|
576
658
|
errorLog("Disconnecting client after failure");
|
|
@@ -624,7 +706,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
624
706
|
typeof connectionPoint === "string" ? { type: UserTokenType.Anonymous } : connectionPoint.userIdentity;
|
|
625
707
|
|
|
626
708
|
await this.connect(endpointUrl);
|
|
627
|
-
const session = await this.
|
|
709
|
+
const session = await this.createSession2(userIdentity);
|
|
628
710
|
|
|
629
711
|
let result;
|
|
630
712
|
try {
|
|
@@ -673,7 +755,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
673
755
|
|
|
674
756
|
assert(typeof callback === "function");
|
|
675
757
|
if (!this._secureChannel) {
|
|
676
|
-
|
|
758
|
+
return callback!(new Error(" client must be connected first"));
|
|
677
759
|
}
|
|
678
760
|
// istanbul ignore next
|
|
679
761
|
if (!this.__resolveEndPoint() || !this.endpoint) {
|
|
@@ -737,13 +819,15 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
737
819
|
callback: (err: Error | null, session?: ClientSessionImpl) => void
|
|
738
820
|
): void {
|
|
739
821
|
assert(typeof callback === "function");
|
|
740
|
-
if (!this._secureChannel) {
|
|
741
|
-
throw new Error("Invalid channel");
|
|
742
|
-
}
|
|
743
822
|
assert(this.serverUri !== undefined, " must have a valid server URI " + this.serverUri);
|
|
744
823
|
assert(this.endpointUrl !== undefined, " must have a valid server endpointUrl");
|
|
745
824
|
assert(this.endpoint);
|
|
746
825
|
|
|
826
|
+
// istanbul ignore next
|
|
827
|
+
if (!this._secureChannel) {
|
|
828
|
+
return callback(new Error("Invalid channel"));
|
|
829
|
+
}
|
|
830
|
+
|
|
747
831
|
const applicationUri = this._getApplicationUri();
|
|
748
832
|
|
|
749
833
|
const applicationDescription: ApplicationDescriptionOptions = {
|
|
@@ -777,7 +861,13 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
777
861
|
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
778
862
|
/* istanbul ignore next */
|
|
779
863
|
if (err) {
|
|
780
|
-
|
|
864
|
+
// we could have an invalid state here or a connection error
|
|
865
|
+
errorLog("error: ", err.message, " retrying in ... 5 secondes");
|
|
866
|
+
setTimeout(() => {
|
|
867
|
+
errorLog(" .... now retrying");
|
|
868
|
+
this.__createSession_step3(session, callback);
|
|
869
|
+
}, 5 * 1000);
|
|
870
|
+
return;
|
|
781
871
|
}
|
|
782
872
|
|
|
783
873
|
/* istanbul ignore next */
|
|
@@ -786,7 +876,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
786
876
|
}
|
|
787
877
|
|
|
788
878
|
if (response.responseHeader.serviceResult === StatusCodes.BadTooManySessions) {
|
|
789
|
-
return callback(new Error(
|
|
879
|
+
return callback(new Error(response.responseHeader.serviceResult.toString()));
|
|
790
880
|
}
|
|
791
881
|
|
|
792
882
|
if (response.responseHeader.serviceResult !== StatusCodes.Good) {
|
|
@@ -848,6 +938,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
848
938
|
public _activateSession(session: ClientSessionImpl, callback: (err: Error | null, session?: ClientSessionImpl) => void): void {
|
|
849
939
|
// see OPCUA Part 4 - $7.35
|
|
850
940
|
assert(typeof callback === "function");
|
|
941
|
+
|
|
851
942
|
// istanbul ignore next
|
|
852
943
|
if (!this._secureChannel) {
|
|
853
944
|
return callback(new Error(" No secure channel"));
|
|
@@ -1169,6 +1260,7 @@ const thenify = require("thenify");
|
|
|
1169
1260
|
*
|
|
1170
1261
|
*/
|
|
1171
1262
|
OPCUAClientImpl.prototype.createSession = thenify.withCallback(OPCUAClientImpl.prototype.createSession);
|
|
1263
|
+
OPCUAClientImpl.prototype.createSession2 = thenify.withCallback(OPCUAClientImpl.prototype.createSession2);
|
|
1172
1264
|
/**
|
|
1173
1265
|
* @method changeSessionIdentity
|
|
1174
1266
|
* @async
|
package/source/reconnection.ts
CHANGED
|
@@ -8,7 +8,7 @@ import * as chalk from "chalk";
|
|
|
8
8
|
import { assert } from "node-opcua-assert";
|
|
9
9
|
import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
10
10
|
import { TransferSubscriptionsRequest, TransferSubscriptionsResponse } from "node-opcua-service-subscription";
|
|
11
|
-
import { StatusCodes } from "node-opcua-status-code";
|
|
11
|
+
import { CallbackT, StatusCodes } from "node-opcua-status-code";
|
|
12
12
|
import { ErrorCallback } from "node-opcua-status-code";
|
|
13
13
|
|
|
14
14
|
import { SubscriptionId } from "./client_session";
|
|
@@ -133,6 +133,33 @@ function _ask_for_subscription_republish(session: ClientSessionImpl, callback: (
|
|
|
133
133
|
});
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
function create_session_and_repeat_if_failed(
|
|
137
|
+
client: IClientBase,
|
|
138
|
+
session: ClientSessionImpl,
|
|
139
|
+
callback: CallbackT<ClientSessionImpl>
|
|
140
|
+
) {
|
|
141
|
+
if (session.hasBeenClosed()) {
|
|
142
|
+
return callback(new Error("Cannot complete subscription republish due to session termination"));
|
|
143
|
+
}
|
|
144
|
+
debugLog(chalk.bgWhite.red(" => creating a new session ...."));
|
|
145
|
+
// create new session, based on old session,
|
|
146
|
+
// so we can reuse subscriptions data
|
|
147
|
+
client.__createSession_step2(session, (err: Error | null, session1?: ClientSessionImpl) => {
|
|
148
|
+
debugLog(chalk.bgWhite.cyan(" => creating a new session (based on old session data).... Done"));
|
|
149
|
+
if (!err && session1) {
|
|
150
|
+
const newSession = session1;
|
|
151
|
+
assert(session === session1, "session should have been recycled");
|
|
152
|
+
callback(err, newSession);
|
|
153
|
+
return;
|
|
154
|
+
} else {
|
|
155
|
+
setTimeout(() => {
|
|
156
|
+
create_session_and_repeat_if_failed(client, session, callback);
|
|
157
|
+
}, 1000);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
callback(err);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
136
163
|
function repair_client_session_by_recreating_a_new_session(
|
|
137
164
|
client: IClientBase,
|
|
138
165
|
session: ClientSessionImpl,
|
|
@@ -164,20 +191,11 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
164
191
|
},
|
|
165
192
|
|
|
166
193
|
function create_new_session(innerCallback: ErrorCallback) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
debugLog(chalk.bgWhite.red(" => creating a new session ...."));
|
|
172
|
-
// create new session, based on old session,
|
|
173
|
-
// so we can reuse subscriptions data
|
|
174
|
-
client.__createSession_step2(session, (err: Error | null, session1?: ClientSessionImpl) => {
|
|
175
|
-
debugLog(chalk.bgWhite.cyan(" => creating a new session (based on old session data).... Done"));
|
|
176
|
-
if (!err && session1) {
|
|
177
|
-
newSession = session1;
|
|
178
|
-
assert(session === session1, "session should have been recycled");
|
|
194
|
+
create_session_and_repeat_if_failed(client, session, (err?: Error | null, _newSession?: ClientSessionImpl) => {
|
|
195
|
+
if (_newSession) {
|
|
196
|
+
newSession = _newSession;
|
|
179
197
|
}
|
|
180
|
-
innerCallback(err
|
|
198
|
+
innerCallback(err || undefined);
|
|
181
199
|
});
|
|
182
200
|
},
|
|
183
201
|
|
|
@@ -386,8 +404,8 @@ export function repair_client_session(client: IClientBase, session: ClientSessio
|
|
|
386
404
|
_repair_client_session(client, session, (err) => {
|
|
387
405
|
privateSession._reconnecting.reconnecting = false;
|
|
388
406
|
if (err) {
|
|
389
|
-
|
|
390
|
-
|
|
407
|
+
errorLog(chalk.red("SESSION RESTORED HAS FAILED! retrying"), err.message, session.sessionId.toString());
|
|
408
|
+
return _repair_client_session(client, session, callback);
|
|
391
409
|
}
|
|
392
410
|
debugLog(chalk.yellow("SESSION RESTORED"), session.sessionId.toString());
|
|
393
411
|
session.emit("session_restored");
|
|
@@ -413,7 +431,7 @@ export function repair_client_sessions(client: IClientBase, callback: (err?: Err
|
|
|
413
431
|
repair_client_session(client, session as ClientSessionImpl, next);
|
|
414
432
|
},
|
|
415
433
|
(err) => {
|
|
416
|
-
|
|
434
|
+
err && errorLog("sessions reactivation completed: err ", err ? err.message : "null");
|
|
417
435
|
return callback(err!);
|
|
418
436
|
}
|
|
419
437
|
);
|
|
@@ -91,7 +91,7 @@ export function readHistoryServerCapabilities(
|
|
|
91
91
|
const nodeIds = results.map((innerResult: BrowsePathResult) =>
|
|
92
92
|
innerResult.statusCode === StatusCodes.Good && innerResult.targets
|
|
93
93
|
? innerResult.targets[0].targetId
|
|
94
|
-
: NodeId
|
|
94
|
+
: new NodeId()
|
|
95
95
|
);
|
|
96
96
|
|
|
97
97
|
const nodesToRead: ReadValueIdOptions[] = nodeIds.map((nodeId: NodeId) => ({
|