node-opcua-client 2.72.2 → 2.74.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/LICENSE +3 -1
- package/README.md +54 -0
- package/dist/client_base.d.ts +23 -40
- package/dist/client_base.js +1 -0
- package/dist/client_base.js.map +1 -1
- package/dist/client_session.d.ts +2 -2
- package/dist/client_session.js.map +1 -1
- package/dist/private/client_base_impl.d.ts +5 -17
- package/dist/private/client_base_impl.js +144 -131
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_session_impl.js +1 -0
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/client_subscription_impl.js +7 -2
- package/dist/private/client_subscription_impl.js.map +1 -1
- package/dist/private/opcua_client_impl.js +10 -7
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/reconnection.js +57 -11
- package/dist/reconnection.js.map +1 -1
- package/dist/tools/findservers.js +2 -2
- package/dist/tools/findservers.js.map +1 -1
- package/package.json +43 -43
- package/source/client_base.ts +23 -40
- package/source/client_session.ts +4 -2
- package/source/private/client_base_impl.ts +181 -150
- package/source/private/client_session_impl.ts +11 -5
- package/source/private/client_subscription_impl.ts +6 -2
- package/source/private/opcua_client_impl.ts +14 -10
- package/source/reconnection.ts +65 -12
- package/source/tools/findservers.ts +2 -2
|
@@ -10,8 +10,7 @@ import {
|
|
|
10
10
|
ExtraDataTypeManager,
|
|
11
11
|
getExtensionObjectConstructor,
|
|
12
12
|
getExtraDataTypeManager,
|
|
13
|
-
promoteOpaqueStructure
|
|
14
|
-
resolveDynamicExtensionObject
|
|
13
|
+
promoteOpaqueStructure
|
|
15
14
|
} from "node-opcua-client-dynamic-extension-object";
|
|
16
15
|
import { Certificate, Nonce } from "node-opcua-crypto";
|
|
17
16
|
import { attributeNameById, BrowseDirection, LocalizedTextLike } from "node-opcua-data-model";
|
|
@@ -21,7 +20,7 @@ import { ExtensionObject } from "node-opcua-extension-object";
|
|
|
21
20
|
import { coerceNodeId, NodeId, NodeIdLike, resolveNodeId } from "node-opcua-nodeid";
|
|
22
21
|
import { getBuiltInDataType, getArgumentDefinitionHelper, IBasicSession } from "node-opcua-pseudo-session";
|
|
23
22
|
import { AnyConstructorFunc } from "node-opcua-schemas";
|
|
24
|
-
import {
|
|
23
|
+
import { requestHandleNotSetValue, SignatureData } from "node-opcua-secure-channel";
|
|
25
24
|
import { BrowseDescription, BrowseRequest, BrowseResponse, BrowseResult } from "node-opcua-service-browse";
|
|
26
25
|
import { CallMethodRequest, CallMethodResult, CallRequest, CallResponse } from "node-opcua-service-call";
|
|
27
26
|
import { EndpointDescription } from "node-opcua-service-endpoints";
|
|
@@ -83,7 +82,13 @@ import {
|
|
|
83
82
|
import { WriteRequest, WriteResponse, WriteValue } from "node-opcua-service-write";
|
|
84
83
|
import { StatusCode, StatusCodes, Callback, CallbackT } from "node-opcua-status-code";
|
|
85
84
|
import { ErrorCallback } from "node-opcua-status-code";
|
|
86
|
-
import {
|
|
85
|
+
import {
|
|
86
|
+
BrowseNextRequest,
|
|
87
|
+
BrowseNextResponse,
|
|
88
|
+
HistoryReadValueIdOptions,
|
|
89
|
+
ServiceFault,
|
|
90
|
+
WriteValueOptions
|
|
91
|
+
} from "node-opcua-types";
|
|
87
92
|
import { buffer_ellipsis, getFunctionParameterNames, isNullOrUndefined, lowerFirstLetter } from "node-opcua-utils";
|
|
88
93
|
import { DataType, Variant, VariantLike } from "node-opcua-variant";
|
|
89
94
|
|
|
@@ -115,7 +120,6 @@ import { repair_client_session } from "../reconnection";
|
|
|
115
120
|
|
|
116
121
|
import { ClientSidePublishEngine } from "./client_publish_engine";
|
|
117
122
|
import { ClientSubscriptionImpl } from "./client_subscription_impl";
|
|
118
|
-
import { OPCUAClientImpl } from "./opcua_client_impl";
|
|
119
123
|
import { IClientBase } from "./i_private_client";
|
|
120
124
|
|
|
121
125
|
export type ResponseCallback<T> = (err: Error | null, response?: T) => void;
|
|
@@ -1542,6 +1546,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
|
|
|
1542
1546
|
if (err && err.message.match(/BadSessionIdInvalid/) && request.constructor.name !== "ActivateSessionRequest") {
|
|
1543
1547
|
debugLog("Transaction on Invalid Session ", request.constructor.name);
|
|
1544
1548
|
request.requestHeader.requestHandle = requestHandleNotSetValue;
|
|
1549
|
+
warningLog("client is now attempting to recreate a session");
|
|
1545
1550
|
this.recreate_session_and_reperform_transaction(request, callback);
|
|
1546
1551
|
return;
|
|
1547
1552
|
}
|
|
@@ -1597,6 +1602,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
|
|
|
1597
1602
|
}
|
|
1598
1603
|
return callback(err);
|
|
1599
1604
|
}
|
|
1605
|
+
|
|
1600
1606
|
/* istanbul ignore next */
|
|
1601
1607
|
if (!response) {
|
|
1602
1608
|
return callback(new Error("internal Error"));
|
|
@@ -471,8 +471,12 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
|
|
|
471
471
|
});
|
|
472
472
|
session.setTriggering(setTriggeringRequest, (err: Error | null, response?: SetTriggeringResponse) => {
|
|
473
473
|
if (err) {
|
|
474
|
-
|
|
475
|
-
|
|
474
|
+
if (response) {
|
|
475
|
+
// use soft error, no exceptions
|
|
476
|
+
return callback(null, response);
|
|
477
|
+
} else {
|
|
478
|
+
return callback(err);
|
|
479
|
+
}
|
|
476
480
|
}
|
|
477
481
|
// istanbul ignore next
|
|
478
482
|
if (!response) {
|
|
@@ -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({
|
|
@@ -411,7 +411,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
411
411
|
|
|
412
412
|
this._addSession(session as ClientSessionImpl);
|
|
413
413
|
|
|
414
|
-
this._activateSession(session as ClientSessionImpl, (err1: Error | null, session2?: ClientSessionImpl) => {
|
|
414
|
+
this._activateSession(session as ClientSessionImpl, (err1: Error | null, session2?: ClientSessionImpl) => {
|
|
415
415
|
callback(err1, session2);
|
|
416
416
|
});
|
|
417
417
|
}
|
|
@@ -861,13 +861,17 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
861
861
|
this.performMessageTransaction(request, (err: Error | null, response?: Response) => {
|
|
862
862
|
/* istanbul ignore next */
|
|
863
863
|
if (err) {
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
864
|
+
console.log("__createSession_step3 has failed", err.message);
|
|
865
|
+
return callback(err);
|
|
866
|
+
|
|
867
|
+
// //xxxxxx qdqsdqsdqsdqsd
|
|
868
|
+
// // we could have an invalid state here or a connection error
|
|
869
|
+
// errorLog("error: ", err.message, " retrying in ... 5 secondes");
|
|
870
|
+
// setTimeout(() => {
|
|
871
|
+
// errorLog(" .... now retrying");
|
|
872
|
+
// this.__createSession_step3(session, callback);
|
|
873
|
+
// }, 5 * 1000);
|
|
874
|
+
// return;
|
|
871
875
|
}
|
|
872
876
|
|
|
873
877
|
/* istanbul ignore next */
|
|
@@ -1039,7 +1043,7 @@ export class OPCUAClientImpl extends ClientBaseImpl implements OPCUAClient {
|
|
|
1039
1043
|
session.lastResponseReceivedTime = new Date();
|
|
1040
1044
|
if (this.keepSessionAlive) {
|
|
1041
1045
|
session.startKeepAliveManager();
|
|
1042
|
-
}
|
|
1046
|
+
}
|
|
1043
1047
|
return callback(null, session);
|
|
1044
1048
|
} else {
|
|
1045
1049
|
// restore client
|
package/source/reconnection.ts
CHANGED
|
@@ -10,12 +10,12 @@ import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "n
|
|
|
10
10
|
import { TransferSubscriptionsRequest, TransferSubscriptionsResponse } from "node-opcua-service-subscription";
|
|
11
11
|
import { CallbackT, StatusCodes } from "node-opcua-status-code";
|
|
12
12
|
import { ErrorCallback } from "node-opcua-status-code";
|
|
13
|
+
import { CloseSessionRequest } from "node-opcua-types";
|
|
13
14
|
|
|
14
15
|
import { SubscriptionId } from "./client_session";
|
|
15
16
|
import { ClientSessionImpl, Reconnectable } from "./private/client_session_impl";
|
|
16
17
|
import { ClientSubscriptionImpl } from "./private/client_subscription_impl";
|
|
17
18
|
import { IClientBase } from "./private/i_private_client";
|
|
18
|
-
import { OPCUAClientImpl } from "./private/opcua_client_impl";
|
|
19
19
|
|
|
20
20
|
const debugLog = make_debugLog(__filename);
|
|
21
21
|
const doDebug = checkDebugFlag(__filename);
|
|
@@ -133,7 +133,7 @@ function _ask_for_subscription_republish(session: ClientSessionImpl, callback: (
|
|
|
133
133
|
});
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
function
|
|
136
|
+
function create_session_and_repeat_if_failed_Old(
|
|
137
137
|
client: IClientBase,
|
|
138
138
|
session: ClientSessionImpl,
|
|
139
139
|
callback: CallbackT<ClientSessionImpl>
|
|
@@ -145,21 +145,53 @@ function create_session_and_repeat_if_failed(
|
|
|
145
145
|
// create new session, based on old session,
|
|
146
146
|
// so we can reuse subscriptions data
|
|
147
147
|
client.__createSession_step2(session, (err: Error | null, session1?: ClientSessionImpl) => {
|
|
148
|
-
|
|
148
|
+
if (err && session.hasBeenClosed()) {
|
|
149
|
+
return callback(new Error("Cannot complete subscription republish due to session termination"));
|
|
150
|
+
}
|
|
149
151
|
if (!err && session1) {
|
|
150
152
|
const newSession = session1;
|
|
151
153
|
assert(session === session1, "session should have been recycled");
|
|
152
154
|
callback(err, newSession);
|
|
153
155
|
return;
|
|
154
156
|
} else {
|
|
157
|
+
debugLog(chalk.bgWhite.cyan(" => creating a new session (based on old session data).... Done"));
|
|
155
158
|
setTimeout(() => {
|
|
156
159
|
create_session_and_repeat_if_failed(client, session, callback);
|
|
157
160
|
}, 1000);
|
|
158
161
|
return;
|
|
159
162
|
}
|
|
160
|
-
callback(err);
|
|
161
163
|
});
|
|
162
164
|
}
|
|
165
|
+
|
|
166
|
+
function create_session_and_repeat_if_failed(
|
|
167
|
+
client: IClientBase,
|
|
168
|
+
session: ClientSessionImpl,
|
|
169
|
+
callback: CallbackT<ClientSessionImpl>
|
|
170
|
+
) {
|
|
171
|
+
if (session.hasBeenClosed()) {
|
|
172
|
+
debugLog("Cannot complete subscription republish due to session terminatio");
|
|
173
|
+
return callback(new Error("Cannot complete subscription republish due to session termination"));
|
|
174
|
+
}
|
|
175
|
+
debugLog(chalk.bgWhite.red(" => creating a new session ...."));
|
|
176
|
+
// create new session, based on old session,
|
|
177
|
+
// so we can reuse subscriptions data
|
|
178
|
+
client.__createSession_step2(session, (err: Error | null, session1?: ClientSessionImpl) => {
|
|
179
|
+
if (err && session.hasBeenClosed()) {
|
|
180
|
+
debugLog("Cannot complete subscription republish due to session terminatio");
|
|
181
|
+
return callback(new Error("Cannot complete subscription republish due to session termination"));
|
|
182
|
+
}
|
|
183
|
+
if (!err && session1) {
|
|
184
|
+
const newSession = session1;
|
|
185
|
+
assert(session === session1, "session should have been recycled");
|
|
186
|
+
callback(err, newSession);
|
|
187
|
+
return;
|
|
188
|
+
} else {
|
|
189
|
+
debugLog("Cannot complete subscription republish err = ", err?.message);
|
|
190
|
+
callback(err);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
163
195
|
function repair_client_session_by_recreating_a_new_session(
|
|
164
196
|
client: IClientBase,
|
|
165
197
|
session: ClientSessionImpl,
|
|
@@ -207,7 +239,25 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
207
239
|
|
|
208
240
|
client._activateSession(newSession, (err: Error | null, session1?: ClientSessionImpl) => {
|
|
209
241
|
debugLog(chalk.bgWhite.cyan(" => activating a new session .... Done err=", err ? err.message : "null"));
|
|
210
|
-
|
|
242
|
+
if (err) {
|
|
243
|
+
debugLog(
|
|
244
|
+
chalk.bgWhite.cyan(
|
|
245
|
+
"reactivation of the new session has failed: let be smart and close it before failing this repair attempt"
|
|
246
|
+
)
|
|
247
|
+
);
|
|
248
|
+
// but just on the server side, not on the client side
|
|
249
|
+
const closeSessionRequest = new CloseSessionRequest({
|
|
250
|
+
deleteSubscriptions: true
|
|
251
|
+
});
|
|
252
|
+
session.performMessageTransaction(closeSessionRequest, (err2?: Error | null) => {
|
|
253
|
+
if (err2) {
|
|
254
|
+
warningLog("closing session", err2.message);
|
|
255
|
+
}
|
|
256
|
+
innerCallback(err);
|
|
257
|
+
});
|
|
258
|
+
} else {
|
|
259
|
+
innerCallback(err ? err : undefined);
|
|
260
|
+
}
|
|
211
261
|
});
|
|
212
262
|
},
|
|
213
263
|
|
|
@@ -238,8 +288,8 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
238
288
|
subscriptionsToTransfer,
|
|
239
289
|
(err: Error | null, transferSubscriptionsResponse?: TransferSubscriptionsResponse) => {
|
|
240
290
|
if (err) {
|
|
241
|
-
|
|
242
|
-
|
|
291
|
+
warningLog(chalk.bgCyan("Warning TransferSubscription has failed " + err.message));
|
|
292
|
+
warningLog(chalk.bgCyan("May be the server is not supporting this feature"));
|
|
243
293
|
// when transfer subscription has failed, we have no other choice but
|
|
244
294
|
// recreate the subscriptions on the server side
|
|
245
295
|
return innerCallback();
|
|
@@ -303,7 +353,7 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
303
353
|
|
|
304
354
|
(subscription as ClientSubscriptionImpl).recreateSubscriptionAndMonitoredItem((err1?: Error) => {
|
|
305
355
|
if (err1) {
|
|
306
|
-
debugLog("_recreateSubscription failed !");
|
|
356
|
+
debugLog("_recreateSubscription failed !" + err1.message);
|
|
307
357
|
}
|
|
308
358
|
|
|
309
359
|
debugLog(
|
|
@@ -356,7 +406,7 @@ function repair_client_session_by_recreating_a_new_session(
|
|
|
356
406
|
|
|
357
407
|
function _repair_client_session(client: IClientBase, session: ClientSessionImpl, callback: (err?: Error) => void): void {
|
|
358
408
|
const callback2 = (err2?: Error) => {
|
|
359
|
-
debugLog("Session
|
|
409
|
+
debugLog("Session repair completed with err: ", err2 ? err2.message : "<no error>", session.sessionId.toString());
|
|
360
410
|
session.emit("session_repaired");
|
|
361
411
|
callback(err2);
|
|
362
412
|
};
|
|
@@ -404,10 +454,13 @@ export function repair_client_session(client: IClientBase, session: ClientSessio
|
|
|
404
454
|
_repair_client_session(client, session, (err) => {
|
|
405
455
|
privateSession._reconnecting.reconnecting = false;
|
|
406
456
|
if (err) {
|
|
407
|
-
errorLog(chalk.red("
|
|
408
|
-
|
|
457
|
+
errorLog(chalk.red("session restoration has failed! err ="), err.message, session.sessionId.toString(), " => Let's retry");
|
|
458
|
+
setTimeout(() => {
|
|
459
|
+
_repair_client_session(client, session, callback);
|
|
460
|
+
}, 2000);
|
|
461
|
+
return;
|
|
409
462
|
}
|
|
410
|
-
debugLog(chalk.yellow("
|
|
463
|
+
debugLog(chalk.yellow("session has been restored"), session.sessionId.toString());
|
|
411
464
|
session.emit("session_restored");
|
|
412
465
|
const otherCallbacks = privateSession._reconnecting.pendingCallbacks;
|
|
413
466
|
privateSession._reconnecting.pendingCallbacks = [];
|
|
@@ -28,7 +28,7 @@ export function findServers(
|
|
|
28
28
|
discoveryServerEndpointUri: string,
|
|
29
29
|
callback?: (err: Error | null, result?: FindServerResults) => void
|
|
30
30
|
): any {
|
|
31
|
-
const client = new ClientBaseImpl({});
|
|
31
|
+
const client = new ClientBaseImpl({ connectionStrategy: { maxRetry: 3 } });
|
|
32
32
|
|
|
33
33
|
let servers: ApplicationDescription[] = [];
|
|
34
34
|
let endpoints: EndpointDescription[] = [];
|
|
@@ -77,7 +77,7 @@ export function findServersOnNetwork(
|
|
|
77
77
|
discoveryServerEndpointUri: string,
|
|
78
78
|
callback?: (err: Error | null, servers?: ServerOnNetwork[]) => void
|
|
79
79
|
): any {
|
|
80
|
-
const client = new ClientBaseImpl({});
|
|
80
|
+
const client = new ClientBaseImpl({ connectionStrategy: { maxRetry: 3 } });
|
|
81
81
|
|
|
82
82
|
client.connect(discoveryServerEndpointUri, (err?: Error) => {
|
|
83
83
|
if (!err) {
|