opcjs-client 0.1.18-alpha → 0.1.26-alpha
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/index.cjs +247 -344
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -116
- package/dist/index.d.ts +57 -116
- package/dist/index.js +248 -346
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -3,11 +3,38 @@
|
|
|
3
3
|
var opcjsBase = require('opcjs-base');
|
|
4
4
|
|
|
5
5
|
// src/client.ts
|
|
6
|
+
var SessionInvalidError = class extends Error {
|
|
7
|
+
statusCode;
|
|
8
|
+
constructor(statusCode) {
|
|
9
|
+
super(`Session is no longer valid: ${opcjsBase.StatusCodeToString(statusCode)} (0x${statusCode.toString(16).toUpperCase()})`);
|
|
10
|
+
this.name = "SessionInvalidError";
|
|
11
|
+
this.statusCode = statusCode;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// src/services/serviceBase.ts
|
|
6
16
|
var ServiceBase = class {
|
|
7
17
|
constructor(authToken, secureChannel) {
|
|
8
18
|
this.authToken = authToken;
|
|
9
19
|
this.secureChannel = secureChannel;
|
|
10
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Validates the `serviceResult` value from a response header.
|
|
23
|
+
*
|
|
24
|
+
* Throws `SessionInvalidError` for session-related status codes so callers
|
|
25
|
+
* can detect a dropped session and act accordingly (e.g. reconnect).
|
|
26
|
+
* Throws a generic `Error` for all other non-Good codes.
|
|
27
|
+
*
|
|
28
|
+
* @param result - The `serviceResult` value from the response header.
|
|
29
|
+
* @param context - Short description used in the error message (e.g. "ReadRequest").
|
|
30
|
+
*/
|
|
31
|
+
checkServiceResult(result, context) {
|
|
32
|
+
if (result === void 0 || result === opcjsBase.StatusCode.Good) return;
|
|
33
|
+
if (result === opcjsBase.StatusCode.BadSessionIdInvalid || result === opcjsBase.StatusCode.BadSessionClosed) {
|
|
34
|
+
throw new SessionInvalidError(result);
|
|
35
|
+
}
|
|
36
|
+
throw new Error(`${context} failed: ${opcjsBase.StatusCodeToString(result)} (${opcjsBase.StatusCodeToStringNumber(result)})`);
|
|
37
|
+
}
|
|
11
38
|
createRequestHeader() {
|
|
12
39
|
const requestHeader = new opcjsBase.RequestHeader();
|
|
13
40
|
requestHeader.authenticationToken = this.authToken;
|
|
@@ -28,6 +55,10 @@ var SessionService = class _SessionService extends ServiceBase {
|
|
|
28
55
|
this.configuration = configuration;
|
|
29
56
|
}
|
|
30
57
|
logger = opcjsBase.getLogger("services.SessionService");
|
|
58
|
+
/**
|
|
59
|
+
* Creates a new session on the server (OPC UA Part 4, Section 5.7.2).
|
|
60
|
+
* @returns The session ID, authentication token, and selected server endpoint.
|
|
61
|
+
*/
|
|
31
62
|
async createSession() {
|
|
32
63
|
this.logger.debug("Creating session...");
|
|
33
64
|
const clientDescription = new opcjsBase.ApplicationDescription();
|
|
@@ -57,6 +88,10 @@ var SessionService = class _SessionService extends ServiceBase {
|
|
|
57
88
|
if (!castedResponse || !castedResponse.sessionId || !castedResponse.authenticationToken) {
|
|
58
89
|
throw new Error("CreateSessionResponse missing SessionId or AuthenticationToken");
|
|
59
90
|
}
|
|
91
|
+
const serviceResult = castedResponse.responseHeader?.serviceResult;
|
|
92
|
+
if (serviceResult !== void 0 && serviceResult !== opcjsBase.StatusCode.Good) {
|
|
93
|
+
throw new Error(`CreateSessionRequest failed: ${opcjsBase.StatusCodeToString(serviceResult)}`);
|
|
94
|
+
}
|
|
60
95
|
const endpoint = "opc." + this.secureChannel.getEndpointUrl();
|
|
61
96
|
const endpointUrl = new URL(endpoint);
|
|
62
97
|
const securityMode = this.secureChannel.getSecurityMode();
|
|
@@ -75,6 +110,10 @@ var SessionService = class _SessionService extends ServiceBase {
|
|
|
75
110
|
endpoint: serverEndpoint
|
|
76
111
|
};
|
|
77
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Activates an existing session using the supplied identity token (OPC UA Part 4, Section 5.7.3).
|
|
115
|
+
* @param identityToken - User identity token (anonymous, username/password, certificate, or issued token).
|
|
116
|
+
*/
|
|
78
117
|
async activateSession(identityToken) {
|
|
79
118
|
const signatureData = new opcjsBase.SignatureData();
|
|
80
119
|
signatureData.algorithm = this.secureChannel.getSecurityPolicy();
|
|
@@ -87,7 +126,11 @@ var SessionService = class _SessionService extends ServiceBase {
|
|
|
87
126
|
request.userIdentityToken = opcjsBase.ExtensionObject.newBinary(identityToken);
|
|
88
127
|
request.userTokenSignature = signatureData;
|
|
89
128
|
this.logger.debug("Sending ActivateSessionRequest...");
|
|
90
|
-
await this.secureChannel.issueServiceRequest(request);
|
|
129
|
+
const activateResponse = await this.secureChannel.issueServiceRequest(request);
|
|
130
|
+
const activateResult = activateResponse?.responseHeader?.serviceResult;
|
|
131
|
+
if (activateResult !== void 0 && activateResult !== opcjsBase.StatusCode.Good) {
|
|
132
|
+
throw new Error(`ActivateSessionRequest failed: ${opcjsBase.StatusCodeToString(activateResult)}`);
|
|
133
|
+
}
|
|
91
134
|
this.logger.debug("Session activated.");
|
|
92
135
|
}
|
|
93
136
|
recreate(authToken) {
|
|
@@ -171,268 +214,17 @@ var SessionHandler = class {
|
|
|
171
214
|
// src/services/attributeServiceAttributes.ts
|
|
172
215
|
var AttrIdValue = 13;
|
|
173
216
|
|
|
174
|
-
// ../base/src/types/statusCode.ts
|
|
175
|
-
function StatusCodeToString(statusCode) {
|
|
176
|
-
if (statusCode === void 0) {
|
|
177
|
-
return "Unknown";
|
|
178
|
-
}
|
|
179
|
-
const name = Object.entries(StatusCode).find(([, v]) => v === statusCode)?.[0];
|
|
180
|
-
return name ?? `0x${statusCode.toString(16).toUpperCase().padStart(8, "0")}`;
|
|
181
|
-
}
|
|
182
|
-
var StatusCode = /* @__PURE__ */ ((StatusCode2) => {
|
|
183
|
-
StatusCode2[StatusCode2["Good"] = 0] = "Good";
|
|
184
|
-
StatusCode2[StatusCode2["Uncertain"] = 1073741824] = "Uncertain";
|
|
185
|
-
StatusCode2[StatusCode2["Bad"] = 2147483648] = "Bad";
|
|
186
|
-
StatusCode2[StatusCode2["BadUnexpectedError"] = 2147549184] = "BadUnexpectedError";
|
|
187
|
-
StatusCode2[StatusCode2["BadInternalError"] = 2147614720] = "BadInternalError";
|
|
188
|
-
StatusCode2[StatusCode2["BadOutOfMemory"] = 2147680256] = "BadOutOfMemory";
|
|
189
|
-
StatusCode2[StatusCode2["BadResourceUnavailable"] = 2147745792] = "BadResourceUnavailable";
|
|
190
|
-
StatusCode2[StatusCode2["BadCommunicationError"] = 2147811328] = "BadCommunicationError";
|
|
191
|
-
StatusCode2[StatusCode2["BadEncodingError"] = 2147876864] = "BadEncodingError";
|
|
192
|
-
StatusCode2[StatusCode2["BadDecodingError"] = 2147942400] = "BadDecodingError";
|
|
193
|
-
StatusCode2[StatusCode2["BadEncodingLimitsExceeded"] = 2148007936] = "BadEncodingLimitsExceeded";
|
|
194
|
-
StatusCode2[StatusCode2["BadRequestTooLarge"] = 2159542272] = "BadRequestTooLarge";
|
|
195
|
-
StatusCode2[StatusCode2["BadResponseTooLarge"] = 2159607808] = "BadResponseTooLarge";
|
|
196
|
-
StatusCode2[StatusCode2["BadUnknownResponse"] = 2148073472] = "BadUnknownResponse";
|
|
197
|
-
StatusCode2[StatusCode2["BadTimeout"] = 2148139008] = "BadTimeout";
|
|
198
|
-
StatusCode2[StatusCode2["BadServiceUnsupported"] = 2148204544] = "BadServiceUnsupported";
|
|
199
|
-
StatusCode2[StatusCode2["BadShutdown"] = 2148270080] = "BadShutdown";
|
|
200
|
-
StatusCode2[StatusCode2["BadServerNotConnected"] = 2148335616] = "BadServerNotConnected";
|
|
201
|
-
StatusCode2[StatusCode2["BadServerHalted"] = 2148401152] = "BadServerHalted";
|
|
202
|
-
StatusCode2[StatusCode2["BadNothingToDo"] = 2148466688] = "BadNothingToDo";
|
|
203
|
-
StatusCode2[StatusCode2["BadTooManyOperations"] = 2148532224] = "BadTooManyOperations";
|
|
204
|
-
StatusCode2[StatusCode2["BadTooManyMonitoredItems"] = 2161836032] = "BadTooManyMonitoredItems";
|
|
205
|
-
StatusCode2[StatusCode2["BadDataTypeIdUnknown"] = 2148597760] = "BadDataTypeIdUnknown";
|
|
206
|
-
StatusCode2[StatusCode2["BadCertificateInvalid"] = 2148663296] = "BadCertificateInvalid";
|
|
207
|
-
StatusCode2[StatusCode2["BadSecurityChecksFailed"] = 2148728832] = "BadSecurityChecksFailed";
|
|
208
|
-
StatusCode2[StatusCode2["BadCertificatePolicyCheckFailed"] = 2165571584] = "BadCertificatePolicyCheckFailed";
|
|
209
|
-
StatusCode2[StatusCode2["BadCertificateTimeInvalid"] = 2148794368] = "BadCertificateTimeInvalid";
|
|
210
|
-
StatusCode2[StatusCode2["BadCertificateIssuerTimeInvalid"] = 2148859904] = "BadCertificateIssuerTimeInvalid";
|
|
211
|
-
StatusCode2[StatusCode2["BadCertificateHostNameInvalid"] = 2148925440] = "BadCertificateHostNameInvalid";
|
|
212
|
-
StatusCode2[StatusCode2["BadCertificateUriInvalid"] = 2148990976] = "BadCertificateUriInvalid";
|
|
213
|
-
StatusCode2[StatusCode2["BadCertificateUseNotAllowed"] = 2149056512] = "BadCertificateUseNotAllowed";
|
|
214
|
-
StatusCode2[StatusCode2["BadCertificateIssuerUseNotAllowed"] = 2149122048] = "BadCertificateIssuerUseNotAllowed";
|
|
215
|
-
StatusCode2[StatusCode2["BadCertificateUntrusted"] = 2149187584] = "BadCertificateUntrusted";
|
|
216
|
-
StatusCode2[StatusCode2["BadCertificateRevocationUnknown"] = 2149253120] = "BadCertificateRevocationUnknown";
|
|
217
|
-
StatusCode2[StatusCode2["BadCertificateIssuerRevocationUnknown"] = 2149318656] = "BadCertificateIssuerRevocationUnknown";
|
|
218
|
-
StatusCode2[StatusCode2["BadCertificateRevoked"] = 2149384192] = "BadCertificateRevoked";
|
|
219
|
-
StatusCode2[StatusCode2["BadCertificateIssuerRevoked"] = 2149449728] = "BadCertificateIssuerRevoked";
|
|
220
|
-
StatusCode2[StatusCode2["BadCertificateChainIncomplete"] = 2165112832] = "BadCertificateChainIncomplete";
|
|
221
|
-
StatusCode2[StatusCode2["BadUserAccessDenied"] = 2149515264] = "BadUserAccessDenied";
|
|
222
|
-
StatusCode2[StatusCode2["BadIdentityTokenInvalid"] = 2149580800] = "BadIdentityTokenInvalid";
|
|
223
|
-
StatusCode2[StatusCode2["BadIdentityTokenRejected"] = 2149646336] = "BadIdentityTokenRejected";
|
|
224
|
-
StatusCode2[StatusCode2["BadSecureChannelIdInvalid"] = 2149711872] = "BadSecureChannelIdInvalid";
|
|
225
|
-
StatusCode2[StatusCode2["BadInvalidTimestamp"] = 2149777408] = "BadInvalidTimestamp";
|
|
226
|
-
StatusCode2[StatusCode2["BadNonceInvalid"] = 2149842944] = "BadNonceInvalid";
|
|
227
|
-
StatusCode2[StatusCode2["BadSessionIdInvalid"] = 2149908480] = "BadSessionIdInvalid";
|
|
228
|
-
StatusCode2[StatusCode2["BadSessionClosed"] = 2149974016] = "BadSessionClosed";
|
|
229
|
-
StatusCode2[StatusCode2["BadSessionNotActivated"] = 2150039552] = "BadSessionNotActivated";
|
|
230
|
-
StatusCode2[StatusCode2["BadSubscriptionIdInvalid"] = 2150105088] = "BadSubscriptionIdInvalid";
|
|
231
|
-
StatusCode2[StatusCode2["BadRequestHeaderInvalid"] = 2150236160] = "BadRequestHeaderInvalid";
|
|
232
|
-
StatusCode2[StatusCode2["BadTimestampsToReturnInvalid"] = 2150301696] = "BadTimestampsToReturnInvalid";
|
|
233
|
-
StatusCode2[StatusCode2["BadRequestCancelledByClient"] = 2150367232] = "BadRequestCancelledByClient";
|
|
234
|
-
StatusCode2[StatusCode2["BadTooManyArguments"] = 2162491392] = "BadTooManyArguments";
|
|
235
|
-
StatusCode2[StatusCode2["BadLicenseExpired"] = 2165178368] = "BadLicenseExpired";
|
|
236
|
-
StatusCode2[StatusCode2["BadLicenseLimitsExceeded"] = 2165243904] = "BadLicenseLimitsExceeded";
|
|
237
|
-
StatusCode2[StatusCode2["BadLicenseNotAvailable"] = 2165309440] = "BadLicenseNotAvailable";
|
|
238
|
-
StatusCode2[StatusCode2["GoodSubscriptionTransferred"] = 2949120] = "GoodSubscriptionTransferred";
|
|
239
|
-
StatusCode2[StatusCode2["GoodCompletesAsynchronously"] = 3014656] = "GoodCompletesAsynchronously";
|
|
240
|
-
StatusCode2[StatusCode2["GoodOverload"] = 3080192] = "GoodOverload";
|
|
241
|
-
StatusCode2[StatusCode2["GoodClamped"] = 3145728] = "GoodClamped";
|
|
242
|
-
StatusCode2[StatusCode2["BadNoCommunication"] = 2150694912] = "BadNoCommunication";
|
|
243
|
-
StatusCode2[StatusCode2["BadWaitingForInitialData"] = 2150760448] = "BadWaitingForInitialData";
|
|
244
|
-
StatusCode2[StatusCode2["BadNodeIdInvalid"] = 2150825984] = "BadNodeIdInvalid";
|
|
245
|
-
StatusCode2[StatusCode2["BadNodeIdUnknown"] = 2150891520] = "BadNodeIdUnknown";
|
|
246
|
-
StatusCode2[StatusCode2["BadAttributeIdInvalid"] = 2150957056] = "BadAttributeIdInvalid";
|
|
247
|
-
StatusCode2[StatusCode2["BadIndexRangeInvalid"] = 2151022592] = "BadIndexRangeInvalid";
|
|
248
|
-
StatusCode2[StatusCode2["BadIndexRangeNoData"] = 2151088128] = "BadIndexRangeNoData";
|
|
249
|
-
StatusCode2[StatusCode2["BadDataEncodingInvalid"] = 2151153664] = "BadDataEncodingInvalid";
|
|
250
|
-
StatusCode2[StatusCode2["BadDataEncodingUnsupported"] = 2151219200] = "BadDataEncodingUnsupported";
|
|
251
|
-
StatusCode2[StatusCode2["BadNotReadable"] = 2151284736] = "BadNotReadable";
|
|
252
|
-
StatusCode2[StatusCode2["BadNotWritable"] = 2151350272] = "BadNotWritable";
|
|
253
|
-
StatusCode2[StatusCode2["BadOutOfRange"] = 2151415808] = "BadOutOfRange";
|
|
254
|
-
StatusCode2[StatusCode2["BadNotSupported"] = 2151481344] = "BadNotSupported";
|
|
255
|
-
StatusCode2[StatusCode2["BadNotFound"] = 2151546880] = "BadNotFound";
|
|
256
|
-
StatusCode2[StatusCode2["BadObjectDeleted"] = 2151612416] = "BadObjectDeleted";
|
|
257
|
-
StatusCode2[StatusCode2["BadNotImplemented"] = 2151677952] = "BadNotImplemented";
|
|
258
|
-
StatusCode2[StatusCode2["BadMonitoringModeInvalid"] = 2151743488] = "BadMonitoringModeInvalid";
|
|
259
|
-
StatusCode2[StatusCode2["BadMonitoredItemIdInvalid"] = 2151809024] = "BadMonitoredItemIdInvalid";
|
|
260
|
-
StatusCode2[StatusCode2["BadMonitoredItemFilterInvalid"] = 2151874560] = "BadMonitoredItemFilterInvalid";
|
|
261
|
-
StatusCode2[StatusCode2["BadMonitoredItemFilterUnsupported"] = 2151940096] = "BadMonitoredItemFilterUnsupported";
|
|
262
|
-
StatusCode2[StatusCode2["BadFilterNotAllowed"] = 2152005632] = "BadFilterNotAllowed";
|
|
263
|
-
StatusCode2[StatusCode2["BadStructureMissing"] = 2152071168] = "BadStructureMissing";
|
|
264
|
-
StatusCode2[StatusCode2["BadEventFilterInvalid"] = 2152136704] = "BadEventFilterInvalid";
|
|
265
|
-
StatusCode2[StatusCode2["BadContentFilterInvalid"] = 2152202240] = "BadContentFilterInvalid";
|
|
266
|
-
StatusCode2[StatusCode2["BadFilterOperatorInvalid"] = 2160132096] = "BadFilterOperatorInvalid";
|
|
267
|
-
StatusCode2[StatusCode2["BadFilterOperatorUnsupported"] = 2160197632] = "BadFilterOperatorUnsupported";
|
|
268
|
-
StatusCode2[StatusCode2["BadFilterOperandCountMismatch"] = 2160263168] = "BadFilterOperandCountMismatch";
|
|
269
|
-
StatusCode2[StatusCode2["BadFilterOperandInvalid"] = 2152267776] = "BadFilterOperandInvalid";
|
|
270
|
-
StatusCode2[StatusCode2["BadFilterElementInvalid"] = 2160328704] = "BadFilterElementInvalid";
|
|
271
|
-
StatusCode2[StatusCode2["BadFilterLiteralInvalid"] = 2160394240] = "BadFilterLiteralInvalid";
|
|
272
|
-
StatusCode2[StatusCode2["BadContinuationPointInvalid"] = 2152333312] = "BadContinuationPointInvalid";
|
|
273
|
-
StatusCode2[StatusCode2["BadNoContinuationPoints"] = 2152398848] = "BadNoContinuationPoints";
|
|
274
|
-
StatusCode2[StatusCode2["BadReferenceTypeIdInvalid"] = 2152464384] = "BadReferenceTypeIdInvalid";
|
|
275
|
-
StatusCode2[StatusCode2["BadBrowseDirectionInvalid"] = 2152529920] = "BadBrowseDirectionInvalid";
|
|
276
|
-
StatusCode2[StatusCode2["BadNodeNotInView"] = 2152595456] = "BadNodeNotInView";
|
|
277
|
-
StatusCode2[StatusCode2["BadNumericOverflow"] = 2165440512] = "BadNumericOverflow";
|
|
278
|
-
StatusCode2[StatusCode2["BadServerUriInvalid"] = 2152660992] = "BadServerUriInvalid";
|
|
279
|
-
StatusCode2[StatusCode2["BadServerNameMissing"] = 2152726528] = "BadServerNameMissing";
|
|
280
|
-
StatusCode2[StatusCode2["BadDiscoveryUrlMissing"] = 2152792064] = "BadDiscoveryUrlMissing";
|
|
281
|
-
StatusCode2[StatusCode2["BadSempahoreFileMissing"] = 2152857600] = "BadSempahoreFileMissing";
|
|
282
|
-
StatusCode2[StatusCode2["BadRequestTypeInvalid"] = 2152923136] = "BadRequestTypeInvalid";
|
|
283
|
-
StatusCode2[StatusCode2["BadSecurityModeRejected"] = 2152988672] = "BadSecurityModeRejected";
|
|
284
|
-
StatusCode2[StatusCode2["BadSecurityPolicyRejected"] = 2153054208] = "BadSecurityPolicyRejected";
|
|
285
|
-
StatusCode2[StatusCode2["BadTooManySessions"] = 2153119744] = "BadTooManySessions";
|
|
286
|
-
StatusCode2[StatusCode2["BadUserSignatureInvalid"] = 2153185280] = "BadUserSignatureInvalid";
|
|
287
|
-
StatusCode2[StatusCode2["BadApplicationSignatureInvalid"] = 2153250816] = "BadApplicationSignatureInvalid";
|
|
288
|
-
StatusCode2[StatusCode2["BadNoValidCertificates"] = 2153316352] = "BadNoValidCertificates";
|
|
289
|
-
StatusCode2[StatusCode2["BadIdentityChangeNotSupported"] = 2160459776] = "BadIdentityChangeNotSupported";
|
|
290
|
-
StatusCode2[StatusCode2["BadRequestCancelledByRequest"] = 2153381888] = "BadRequestCancelledByRequest";
|
|
291
|
-
StatusCode2[StatusCode2["BadParentNodeIdInvalid"] = 2153447424] = "BadParentNodeIdInvalid";
|
|
292
|
-
StatusCode2[StatusCode2["BadReferenceNotAllowed"] = 2153512960] = "BadReferenceNotAllowed";
|
|
293
|
-
StatusCode2[StatusCode2["BadNodeIdRejected"] = 2153578496] = "BadNodeIdRejected";
|
|
294
|
-
StatusCode2[StatusCode2["BadNodeIdExists"] = 2153644032] = "BadNodeIdExists";
|
|
295
|
-
StatusCode2[StatusCode2["BadNodeClassInvalid"] = 2153709568] = "BadNodeClassInvalid";
|
|
296
|
-
StatusCode2[StatusCode2["BadBrowseNameInvalid"] = 2153775104] = "BadBrowseNameInvalid";
|
|
297
|
-
StatusCode2[StatusCode2["BadBrowseNameDuplicated"] = 2153840640] = "BadBrowseNameDuplicated";
|
|
298
|
-
StatusCode2[StatusCode2["BadNodeAttributesInvalid"] = 2153906176] = "BadNodeAttributesInvalid";
|
|
299
|
-
StatusCode2[StatusCode2["BadTypeDefinitionInvalid"] = 2153971712] = "BadTypeDefinitionInvalid";
|
|
300
|
-
StatusCode2[StatusCode2["BadSourceNodeIdInvalid"] = 2154037248] = "BadSourceNodeIdInvalid";
|
|
301
|
-
StatusCode2[StatusCode2["BadTargetNodeIdInvalid"] = 2154102784] = "BadTargetNodeIdInvalid";
|
|
302
|
-
StatusCode2[StatusCode2["BadDuplicateReferenceNotAllowed"] = 2154168320] = "BadDuplicateReferenceNotAllowed";
|
|
303
|
-
StatusCode2[StatusCode2["BadInvalidSelfReference"] = 2154233856] = "BadInvalidSelfReference";
|
|
304
|
-
StatusCode2[StatusCode2["BadReferenceLocalOnly"] = 2154299392] = "BadReferenceLocalOnly";
|
|
305
|
-
StatusCode2[StatusCode2["BadNoDeleteRights"] = 2154364928] = "BadNoDeleteRights";
|
|
306
|
-
StatusCode2[StatusCode2["UncertainReferenceNotDeleted"] = 1086062592] = "UncertainReferenceNotDeleted";
|
|
307
|
-
StatusCode2[StatusCode2["BadServerIndexInvalid"] = 2154430464] = "BadServerIndexInvalid";
|
|
308
|
-
StatusCode2[StatusCode2["BadViewIdUnknown"] = 2154496e3] = "BadViewIdUnknown";
|
|
309
|
-
StatusCode2[StatusCode2["BadViewTimestampInvalid"] = 2160656384] = "BadViewTimestampInvalid";
|
|
310
|
-
StatusCode2[StatusCode2["BadViewParameterMismatch"] = 2160721920] = "BadViewParameterMismatch";
|
|
311
|
-
StatusCode2[StatusCode2["BadViewVersionInvalid"] = 2160787456] = "BadViewVersionInvalid";
|
|
312
|
-
StatusCode2[StatusCode2["UncertainNotAllNodesAvailable"] = 1086324736] = "UncertainNotAllNodesAvailable";
|
|
313
|
-
StatusCode2[StatusCode2["GoodResultsMayBeIncomplete"] = 12189696] = "GoodResultsMayBeIncomplete";
|
|
314
|
-
StatusCode2[StatusCode2["BadNotTypeDefinition"] = 2160590848] = "BadNotTypeDefinition";
|
|
315
|
-
StatusCode2[StatusCode2["UncertainReferenceOutOfServer"] = 1080819712] = "UncertainReferenceOutOfServer";
|
|
316
|
-
StatusCode2[StatusCode2["BadTooManyMatches"] = 2154627072] = "BadTooManyMatches";
|
|
317
|
-
StatusCode2[StatusCode2["BadQueryTooComplex"] = 2154692608] = "BadQueryTooComplex";
|
|
318
|
-
StatusCode2[StatusCode2["BadNoMatch"] = 2154758144] = "BadNoMatch";
|
|
319
|
-
StatusCode2[StatusCode2["BadMaxAgeInvalid"] = 2154823680] = "BadMaxAgeInvalid";
|
|
320
|
-
StatusCode2[StatusCode2["BadSecurityModeInsufficient"] = 2162556928] = "BadSecurityModeInsufficient";
|
|
321
|
-
StatusCode2[StatusCode2["BadHistoryOperationInvalid"] = 2154889216] = "BadHistoryOperationInvalid";
|
|
322
|
-
StatusCode2[StatusCode2["BadHistoryOperationUnsupported"] = 2154954752] = "BadHistoryOperationUnsupported";
|
|
323
|
-
StatusCode2[StatusCode2["BadInvalidTimestampArgument"] = 2159869952] = "BadInvalidTimestampArgument";
|
|
324
|
-
StatusCode2[StatusCode2["BadWriteNotSupported"] = 2155020288] = "BadWriteNotSupported";
|
|
325
|
-
StatusCode2[StatusCode2["BadTypeMismatch"] = 2155085824] = "BadTypeMismatch";
|
|
326
|
-
StatusCode2[StatusCode2["BadMethodInvalid"] = 2155151360] = "BadMethodInvalid";
|
|
327
|
-
StatusCode2[StatusCode2["BadArgumentsMissing"] = 2155216896] = "BadArgumentsMissing";
|
|
328
|
-
StatusCode2[StatusCode2["BadNotExecutable"] = 2165374976] = "BadNotExecutable";
|
|
329
|
-
StatusCode2[StatusCode2["BadTooManySubscriptions"] = 2155282432] = "BadTooManySubscriptions";
|
|
330
|
-
StatusCode2[StatusCode2["BadTooManyPublishRequests"] = 2155347968] = "BadTooManyPublishRequests";
|
|
331
|
-
StatusCode2[StatusCode2["BadNoSubscription"] = 2155413504] = "BadNoSubscription";
|
|
332
|
-
StatusCode2[StatusCode2["BadSequenceNumberUnknown"] = 2155479040] = "BadSequenceNumberUnknown";
|
|
333
|
-
StatusCode2[StatusCode2["BadMessageNotAvailable"] = 2155544576] = "BadMessageNotAvailable";
|
|
334
|
-
StatusCode2[StatusCode2["BadInsufficientClientProfile"] = 2155610112] = "BadInsufficientClientProfile";
|
|
335
|
-
StatusCode2[StatusCode2["BadStateNotActive"] = 2160001024] = "BadStateNotActive";
|
|
336
|
-
StatusCode2[StatusCode2["BadAlreadyExists"] = 2165637120] = "BadAlreadyExists";
|
|
337
|
-
StatusCode2[StatusCode2["BadTcpServerTooBusy"] = 2155675648] = "BadTcpServerTooBusy";
|
|
338
|
-
StatusCode2[StatusCode2["BadTcpMessageTypeInvalid"] = 2155741184] = "BadTcpMessageTypeInvalid";
|
|
339
|
-
StatusCode2[StatusCode2["BadTcpSecureChannelUnknown"] = 2155806720] = "BadTcpSecureChannelUnknown";
|
|
340
|
-
StatusCode2[StatusCode2["BadTcpMessageTooLarge"] = 2155872256] = "BadTcpMessageTooLarge";
|
|
341
|
-
StatusCode2[StatusCode2["BadTcpNotEnoughResources"] = 2155937792] = "BadTcpNotEnoughResources";
|
|
342
|
-
StatusCode2[StatusCode2["BadTcpInternalError"] = 2156003328] = "BadTcpInternalError";
|
|
343
|
-
StatusCode2[StatusCode2["BadTcpEndpointUrlInvalid"] = 2156068864] = "BadTcpEndpointUrlInvalid";
|
|
344
|
-
StatusCode2[StatusCode2["BadRequestInterrupted"] = 2156134400] = "BadRequestInterrupted";
|
|
345
|
-
StatusCode2[StatusCode2["BadRequestTimeout"] = 2156199936] = "BadRequestTimeout";
|
|
346
|
-
StatusCode2[StatusCode2["BadSecureChannelClosed"] = 2156265472] = "BadSecureChannelClosed";
|
|
347
|
-
StatusCode2[StatusCode2["BadSecureChannelTokenUnknown"] = 2156331008] = "BadSecureChannelTokenUnknown";
|
|
348
|
-
StatusCode2[StatusCode2["BadSequenceNumberInvalid"] = 2156396544] = "BadSequenceNumberInvalid";
|
|
349
|
-
StatusCode2[StatusCode2["BadProtocolVersionUnsupported"] = 2159935488] = "BadProtocolVersionUnsupported";
|
|
350
|
-
StatusCode2[StatusCode2["BadConfigurationError"] = 2156462080] = "BadConfigurationError";
|
|
351
|
-
StatusCode2[StatusCode2["BadNotConnected"] = 2156527616] = "BadNotConnected";
|
|
352
|
-
StatusCode2[StatusCode2["BadDeviceFailure"] = 2156593152] = "BadDeviceFailure";
|
|
353
|
-
StatusCode2[StatusCode2["BadSensorFailure"] = 2156658688] = "BadSensorFailure";
|
|
354
|
-
StatusCode2[StatusCode2["BadOutOfService"] = 2156724224] = "BadOutOfService";
|
|
355
|
-
StatusCode2[StatusCode2["BadDeadbandFilterInvalid"] = 2156789760] = "BadDeadbandFilterInvalid";
|
|
356
|
-
StatusCode2[StatusCode2["UncertainNoCommunicationLastUsableValue"] = 1083113472] = "UncertainNoCommunicationLastUsableValue";
|
|
357
|
-
StatusCode2[StatusCode2["UncertainLastUsableValue"] = 1083179008] = "UncertainLastUsableValue";
|
|
358
|
-
StatusCode2[StatusCode2["UncertainSubstituteValue"] = 1083244544] = "UncertainSubstituteValue";
|
|
359
|
-
StatusCode2[StatusCode2["UncertainInitialValue"] = 1083310080] = "UncertainInitialValue";
|
|
360
|
-
StatusCode2[StatusCode2["UncertainSensorNotAccurate"] = 1083375616] = "UncertainSensorNotAccurate";
|
|
361
|
-
StatusCode2[StatusCode2["UncertainEngineeringUnitsExceeded"] = 1083441152] = "UncertainEngineeringUnitsExceeded";
|
|
362
|
-
StatusCode2[StatusCode2["UncertainSubNormal"] = 1083506688] = "UncertainSubNormal";
|
|
363
|
-
StatusCode2[StatusCode2["GoodLocalOverride"] = 9830400] = "GoodLocalOverride";
|
|
364
|
-
StatusCode2[StatusCode2["BadRefreshInProgress"] = 2157379584] = "BadRefreshInProgress";
|
|
365
|
-
StatusCode2[StatusCode2["BadConditionAlreadyDisabled"] = 2157445120] = "BadConditionAlreadyDisabled";
|
|
366
|
-
StatusCode2[StatusCode2["BadConditionAlreadyEnabled"] = 2160852992] = "BadConditionAlreadyEnabled";
|
|
367
|
-
StatusCode2[StatusCode2["BadConditionDisabled"] = 2157510656] = "BadConditionDisabled";
|
|
368
|
-
StatusCode2[StatusCode2["BadEventIdUnknown"] = 2157576192] = "BadEventIdUnknown";
|
|
369
|
-
StatusCode2[StatusCode2["BadEventNotAcknowledgeable"] = 2159738880] = "BadEventNotAcknowledgeable";
|
|
370
|
-
StatusCode2[StatusCode2["BadDialogNotActive"] = 2160918528] = "BadDialogNotActive";
|
|
371
|
-
StatusCode2[StatusCode2["BadDialogResponseInvalid"] = 2160984064] = "BadDialogResponseInvalid";
|
|
372
|
-
StatusCode2[StatusCode2["BadConditionBranchAlreadyAcked"] = 2161049600] = "BadConditionBranchAlreadyAcked";
|
|
373
|
-
StatusCode2[StatusCode2["BadConditionBranchAlreadyConfirmed"] = 2161115136] = "BadConditionBranchAlreadyConfirmed";
|
|
374
|
-
StatusCode2[StatusCode2["BadConditionAlreadyShelved"] = 2161180672] = "BadConditionAlreadyShelved";
|
|
375
|
-
StatusCode2[StatusCode2["BadConditionNotShelved"] = 2161246208] = "BadConditionNotShelved";
|
|
376
|
-
StatusCode2[StatusCode2["BadShelvingTimeOutOfRange"] = 2161311744] = "BadShelvingTimeOutOfRange";
|
|
377
|
-
StatusCode2[StatusCode2["BadNoData"] = 2157641728] = "BadNoData";
|
|
378
|
-
StatusCode2[StatusCode2["BadBoundNotFound"] = 2161573888] = "BadBoundNotFound";
|
|
379
|
-
StatusCode2[StatusCode2["BadBoundNotSupported"] = 2161639424] = "BadBoundNotSupported";
|
|
380
|
-
StatusCode2[StatusCode2["BadDataLost"] = 2157772800] = "BadDataLost";
|
|
381
|
-
StatusCode2[StatusCode2["BadDataUnavailable"] = 2157838336] = "BadDataUnavailable";
|
|
382
|
-
StatusCode2[StatusCode2["BadEntryExists"] = 2157903872] = "BadEntryExists";
|
|
383
|
-
StatusCode2[StatusCode2["BadNoEntryExists"] = 2157969408] = "BadNoEntryExists";
|
|
384
|
-
StatusCode2[StatusCode2["BadTimestampNotSupported"] = 2158034944] = "BadTimestampNotSupported";
|
|
385
|
-
StatusCode2[StatusCode2["GoodEntryInserted"] = 10616832] = "GoodEntryInserted";
|
|
386
|
-
StatusCode2[StatusCode2["GoodEntryReplaced"] = 10682368] = "GoodEntryReplaced";
|
|
387
|
-
StatusCode2[StatusCode2["UncertainDataSubNormal"] = 1084489728] = "UncertainDataSubNormal";
|
|
388
|
-
StatusCode2[StatusCode2["GoodNoData"] = 10813440] = "GoodNoData";
|
|
389
|
-
StatusCode2[StatusCode2["GoodMoreData"] = 10878976] = "GoodMoreData";
|
|
390
|
-
StatusCode2[StatusCode2["BadAggregateListMismatch"] = 2161377280] = "BadAggregateListMismatch";
|
|
391
|
-
StatusCode2[StatusCode2["BadAggregateNotSupported"] = 2161442816] = "BadAggregateNotSupported";
|
|
392
|
-
StatusCode2[StatusCode2["BadAggregateInvalidInputs"] = 2161508352] = "BadAggregateInvalidInputs";
|
|
393
|
-
StatusCode2[StatusCode2["BadAggregateConfigurationRejected"] = 2161770496] = "BadAggregateConfigurationRejected";
|
|
394
|
-
StatusCode2[StatusCode2["GoodDataIgnored"] = 14221312] = "GoodDataIgnored";
|
|
395
|
-
StatusCode2[StatusCode2["BadRequestNotAllowed"] = 2162425856] = "BadRequestNotAllowed";
|
|
396
|
-
StatusCode2[StatusCode2["BadRequestNotComplete"] = 2165506048] = "BadRequestNotComplete";
|
|
397
|
-
StatusCode2[StatusCode2["GoodEdited"] = 14417920] = "GoodEdited";
|
|
398
|
-
StatusCode2[StatusCode2["GoodPostActionFailed"] = 14483456] = "GoodPostActionFailed";
|
|
399
|
-
StatusCode2[StatusCode2["UncertainDominantValueChanged"] = 1088290816] = "UncertainDominantValueChanged";
|
|
400
|
-
StatusCode2[StatusCode2["GoodDependentValueChanged"] = 14680064] = "GoodDependentValueChanged";
|
|
401
|
-
StatusCode2[StatusCode2["BadDominantValueChanged"] = 2162229248] = "BadDominantValueChanged";
|
|
402
|
-
StatusCode2[StatusCode2["UncertainDependentValueChanged"] = 1088552960] = "UncertainDependentValueChanged";
|
|
403
|
-
StatusCode2[StatusCode2["BadDependentValueChanged"] = 2162360320] = "BadDependentValueChanged";
|
|
404
|
-
StatusCode2[StatusCode2["GoodEditedDependentValueChanged"] = 18219008] = "GoodEditedDependentValueChanged";
|
|
405
|
-
StatusCode2[StatusCode2["GoodEditedDominantValueChanged"] = 18284544] = "GoodEditedDominantValueChanged";
|
|
406
|
-
StatusCode2[StatusCode2["GoodEditedDominantValueChangedDependentValueChanged"] = 18350080] = "GoodEditedDominantValueChangedDependentValueChanged";
|
|
407
|
-
StatusCode2[StatusCode2["BadEditedOutOfRange"] = 2165899264] = "BadEditedOutOfRange";
|
|
408
|
-
StatusCode2[StatusCode2["BadInitialValueOutOfRange"] = 2165964800] = "BadInitialValueOutOfRange";
|
|
409
|
-
StatusCode2[StatusCode2["BadOutOfRangeDominantValueChanged"] = 2166030336] = "BadOutOfRangeDominantValueChanged";
|
|
410
|
-
StatusCode2[StatusCode2["BadEditedOutOfRangeDominantValueChanged"] = 2166095872] = "BadEditedOutOfRangeDominantValueChanged";
|
|
411
|
-
StatusCode2[StatusCode2["BadOutOfRangeDominantValueChangedDependentValueChanged"] = 2166161408] = "BadOutOfRangeDominantValueChangedDependentValueChanged";
|
|
412
|
-
StatusCode2[StatusCode2["BadEditedOutOfRangeDominantValueChangedDependentValueChanged"] = 2166226944] = "BadEditedOutOfRangeDominantValueChangedDependentValueChanged";
|
|
413
|
-
StatusCode2[StatusCode2["GoodCommunicationEvent"] = 10944512] = "GoodCommunicationEvent";
|
|
414
|
-
StatusCode2[StatusCode2["GoodShutdownEvent"] = 11010048] = "GoodShutdownEvent";
|
|
415
|
-
StatusCode2[StatusCode2["GoodCallAgain"] = 11075584] = "GoodCallAgain";
|
|
416
|
-
StatusCode2[StatusCode2["GoodNonCriticalTimeout"] = 11141120] = "GoodNonCriticalTimeout";
|
|
417
|
-
StatusCode2[StatusCode2["BadInvalidArgument"] = 2158690304] = "BadInvalidArgument";
|
|
418
|
-
StatusCode2[StatusCode2["BadConnectionRejected"] = 2158755840] = "BadConnectionRejected";
|
|
419
|
-
StatusCode2[StatusCode2["BadDisconnect"] = 2158821376] = "BadDisconnect";
|
|
420
|
-
StatusCode2[StatusCode2["BadConnectionClosed"] = 2158886912] = "BadConnectionClosed";
|
|
421
|
-
StatusCode2[StatusCode2["BadInvalidState"] = 2158952448] = "BadInvalidState";
|
|
422
|
-
StatusCode2[StatusCode2["BadEndOfStream"] = 2159017984] = "BadEndOfStream";
|
|
423
|
-
StatusCode2[StatusCode2["BadNoDataAvailable"] = 2159083520] = "BadNoDataAvailable";
|
|
424
|
-
StatusCode2[StatusCode2["BadWaitingForResponse"] = 2159149056] = "BadWaitingForResponse";
|
|
425
|
-
StatusCode2[StatusCode2["BadOperationAbandoned"] = 2159214592] = "BadOperationAbandoned";
|
|
426
|
-
StatusCode2[StatusCode2["BadExpectedStreamToBlock"] = 2159280128] = "BadExpectedStreamToBlock";
|
|
427
|
-
StatusCode2[StatusCode2["BadWouldBlock"] = 2159345664] = "BadWouldBlock";
|
|
428
|
-
StatusCode2[StatusCode2["BadSyntaxError"] = 2159411200] = "BadSyntaxError";
|
|
429
|
-
StatusCode2[StatusCode2["BadMaxConnectionsReached"] = 2159476736] = "BadMaxConnectionsReached";
|
|
430
|
-
return StatusCode2;
|
|
431
|
-
})(StatusCode || {});
|
|
432
|
-
|
|
433
217
|
// src/services/attributeService.ts
|
|
434
218
|
var AttributeService = class extends ServiceBase {
|
|
435
|
-
|
|
219
|
+
logger = opcjsBase.getLogger("services.AttributeService");
|
|
220
|
+
/**
|
|
221
|
+
* Reads the Value attribute of one or more Nodes (OPC UA Part 4, Section 5.10.2).
|
|
222
|
+
* @param nodeIds - NodeIds of the Nodes to read.
|
|
223
|
+
* @param maxAge - Maximum age of the cached value in milliseconds the server may return. 0 = always current value.
|
|
224
|
+
* @param timestampsToReturn - Which timestamps to include in results. Default: Source.
|
|
225
|
+
* @returns Array of results containing value and raw status code number, one per requested NodeId.
|
|
226
|
+
*/
|
|
227
|
+
async ReadValue(nodeIds, maxAge = 0, timestampsToReturn = opcjsBase.TimestampsToReturnEnum.Source) {
|
|
436
228
|
const readValueIds = nodeIds.map((ni) => {
|
|
437
229
|
const readValueId = new opcjsBase.ReadValueId();
|
|
438
230
|
readValueId.nodeId = ni;
|
|
@@ -443,18 +235,18 @@ var AttributeService = class extends ServiceBase {
|
|
|
443
235
|
});
|
|
444
236
|
const request = new opcjsBase.ReadRequest();
|
|
445
237
|
request.requestHeader = this.createRequestHeader();
|
|
446
|
-
request.maxAge =
|
|
447
|
-
request.timestampsToReturn =
|
|
238
|
+
request.maxAge = maxAge;
|
|
239
|
+
request.timestampsToReturn = timestampsToReturn;
|
|
448
240
|
request.nodesToRead = readValueIds;
|
|
449
|
-
|
|
241
|
+
this.logger.debug("Sending ReadRequest...");
|
|
450
242
|
const response = await this.secureChannel.issueServiceRequest(request);
|
|
243
|
+
this.checkServiceResult(response.responseHeader?.serviceResult, "ReadRequest");
|
|
451
244
|
const results = new Array();
|
|
452
245
|
for (const dataValue of response.results ?? []) {
|
|
453
|
-
|
|
454
|
-
|
|
246
|
+
results.push({
|
|
247
|
+
statusCode: dataValue.statusCode ?? opcjsBase.StatusCode.Good,
|
|
455
248
|
value: dataValue.value
|
|
456
|
-
};
|
|
457
|
-
results.push(result);
|
|
249
|
+
});
|
|
458
250
|
}
|
|
459
251
|
return results;
|
|
460
252
|
}
|
|
@@ -465,9 +257,9 @@ var AttributeService = class extends ServiceBase {
|
|
|
465
257
|
|
|
466
258
|
// src/readValueResult.ts
|
|
467
259
|
var ReadValueResult = class {
|
|
468
|
-
constructor(value,
|
|
260
|
+
constructor(value, statusCode) {
|
|
469
261
|
this.value = value;
|
|
470
|
-
this.
|
|
262
|
+
this.statusCode = statusCode;
|
|
471
263
|
}
|
|
472
264
|
};
|
|
473
265
|
|
|
@@ -482,13 +274,17 @@ var SubscriptionHandlerEntry = class {
|
|
|
482
274
|
};
|
|
483
275
|
|
|
484
276
|
// src/subscriptionHandler.ts
|
|
277
|
+
var NODE_ID_DATA_CHANGE_NOTIFICATION = 811;
|
|
278
|
+
var NODE_ID_STATUS_CHANGE_NOTIFICATION = 818;
|
|
485
279
|
var SubscriptionHandler = class {
|
|
486
280
|
constructor(subscriptionService, monitoredItemService) {
|
|
487
281
|
this.subscriptionService = subscriptionService;
|
|
488
282
|
this.monitoredItemService = monitoredItemService;
|
|
489
283
|
}
|
|
284
|
+
logger = opcjsBase.getLogger("SubscriptionHandler");
|
|
490
285
|
entries = new Array();
|
|
491
286
|
nextHandle = 0;
|
|
287
|
+
isRunning = false;
|
|
492
288
|
async subscribe(ids, callback) {
|
|
493
289
|
if (this.entries.length > 0) {
|
|
494
290
|
throw new Error("Subscribing more than once is not implemented");
|
|
@@ -496,80 +292,111 @@ var SubscriptionHandler = class {
|
|
|
496
292
|
const subscriptionId = await this.subscriptionService.createSubscription();
|
|
497
293
|
const items = [];
|
|
498
294
|
for (const id of ids) {
|
|
499
|
-
const entry = new SubscriptionHandlerEntry(
|
|
500
|
-
subscriptionId,
|
|
501
|
-
this.nextHandle++,
|
|
502
|
-
id,
|
|
503
|
-
callback
|
|
504
|
-
);
|
|
295
|
+
const entry = new SubscriptionHandlerEntry(subscriptionId, this.nextHandle++, id, callback);
|
|
505
296
|
this.entries.push(entry);
|
|
506
|
-
|
|
507
|
-
id,
|
|
508
|
-
handle: entry.handle
|
|
509
|
-
};
|
|
510
|
-
items.push(item);
|
|
297
|
+
items.push({ id, handle: entry.handle });
|
|
511
298
|
}
|
|
512
299
|
await this.monitoredItemService.createMonitoredItems(subscriptionId, items);
|
|
513
|
-
this.
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
300
|
+
this.isRunning = true;
|
|
301
|
+
void this.publishLoop([]);
|
|
302
|
+
}
|
|
303
|
+
// https://reference.opcfoundation.org/Core/Part4/v105/docs/5.14.5
|
|
304
|
+
async publishLoop(pendingAcknowledgements) {
|
|
305
|
+
if (!this.isRunning) return;
|
|
306
|
+
let response;
|
|
307
|
+
try {
|
|
308
|
+
response = await this.subscriptionService.publish(pendingAcknowledgements);
|
|
309
|
+
} catch (err) {
|
|
310
|
+
this.logger.error(`Publish failed, stopping publish loop: ${err}`);
|
|
311
|
+
this.isRunning = false;
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const { subscriptionId, availableSequenceNumbers, moreNotifications, notificationMessage } = response;
|
|
315
|
+
const notificationDatas = notificationMessage?.notificationData ?? [];
|
|
316
|
+
const seqNumber = notificationMessage?.sequenceNumber;
|
|
317
|
+
const nextAcknowledgements = [];
|
|
318
|
+
const isKeepAlive = notificationDatas.length === 0;
|
|
319
|
+
if (!isKeepAlive && seqNumber !== void 0) {
|
|
320
|
+
const isAvailable = !availableSequenceNumbers || availableSequenceNumbers.includes(seqNumber);
|
|
321
|
+
if (isAvailable) {
|
|
322
|
+
const ack = new opcjsBase.SubscriptionAcknowledgement();
|
|
323
|
+
ack.subscriptionId = subscriptionId;
|
|
324
|
+
ack.sequenceNumber = seqNumber;
|
|
325
|
+
nextAcknowledgements.push(ack);
|
|
326
|
+
}
|
|
522
327
|
}
|
|
523
|
-
const response = await this.subscriptionService.publish(acknowledgements);
|
|
524
|
-
const messagesToAcknowledge = response.notificationMessage.sequenceNumber;
|
|
525
|
-
const notificationDatas = response.notificationMessage.notificationData;
|
|
526
328
|
for (const notificationData of notificationDatas) {
|
|
527
329
|
const decodedData = notificationData.data;
|
|
528
330
|
const typeNodeId = notificationData.typeId;
|
|
529
|
-
if (typeNodeId.namespace === 0 && typeNodeId.identifier ===
|
|
331
|
+
if (typeNodeId.namespace === 0 && typeNodeId.identifier === NODE_ID_DATA_CHANGE_NOTIFICATION) {
|
|
530
332
|
const dataChangeNotification = decodedData;
|
|
531
333
|
for (const item of dataChangeNotification.monitoredItems) {
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
const entry = this.entries.find((e) => e.handle == clientHandle);
|
|
535
|
-
entry?.callback([{
|
|
536
|
-
id: entry.id,
|
|
537
|
-
value: value.value?.value
|
|
538
|
-
}]);
|
|
334
|
+
const entry = this.entries.find((e) => e.handle === item.clientHandle);
|
|
335
|
+
entry?.callback([{ id: entry.id, value: item.value.value?.value }]);
|
|
539
336
|
}
|
|
337
|
+
} else if (typeNodeId.namespace === 0 && typeNodeId.identifier === NODE_ID_STATUS_CHANGE_NOTIFICATION) {
|
|
338
|
+
const statusChange = decodedData;
|
|
339
|
+
this.logger.warn(
|
|
340
|
+
`Subscription ${subscriptionId} status changed: 0x${statusChange.status?.toString(16).toUpperCase()}`
|
|
341
|
+
);
|
|
342
|
+
this.isRunning = false;
|
|
343
|
+
return;
|
|
540
344
|
} else {
|
|
541
|
-
|
|
345
|
+
this.logger.warn(
|
|
346
|
+
`Notification data type ${typeNodeId.namespace}:${typeNodeId.identifier} is not supported.`
|
|
347
|
+
);
|
|
542
348
|
}
|
|
543
349
|
}
|
|
544
|
-
|
|
545
|
-
this.
|
|
546
|
-
}
|
|
350
|
+
if (moreNotifications) {
|
|
351
|
+
void this.publishLoop(nextAcknowledgements);
|
|
352
|
+
} else {
|
|
353
|
+
setTimeout(() => void this.publishLoop(nextAcknowledgements), 0);
|
|
354
|
+
}
|
|
547
355
|
}
|
|
548
356
|
};
|
|
549
357
|
var SubscriptionService = class extends ServiceBase {
|
|
358
|
+
logger = opcjsBase.getLogger("services.SubscriptionService");
|
|
359
|
+
/**
|
|
360
|
+
* Creates a new subscription on the server (OPC UA Part 4, Section 5.14.2).
|
|
361
|
+
* @param options - Optional subscription parameters; server revises all values.
|
|
362
|
+
* @returns The server-assigned subscription ID.
|
|
363
|
+
*/
|
|
550
364
|
// https://reference.opcfoundation.org/Core/Part4/v105/docs/5.14.2
|
|
551
|
-
async createSubscription() {
|
|
365
|
+
async createSubscription(options) {
|
|
552
366
|
const request = new opcjsBase.CreateSubscriptionRequest();
|
|
553
367
|
request.requestHeader = this.createRequestHeader();
|
|
554
|
-
request.requestedPublishingInterval = 2e3;
|
|
555
|
-
request.requestedLifetimeCount = 36e4;
|
|
556
|
-
request.requestedMaxKeepAliveCount = 6e4;
|
|
557
|
-
request.maxNotificationsPerPublish = 200;
|
|
368
|
+
request.requestedPublishingInterval = options?.requestedPublishingInterval ?? 2e3;
|
|
369
|
+
request.requestedLifetimeCount = options?.requestedLifetimeCount ?? 36e4;
|
|
370
|
+
request.requestedMaxKeepAliveCount = options?.requestedMaxKeepAliveCount ?? 6e4;
|
|
371
|
+
request.maxNotificationsPerPublish = options?.maxNotificationsPerPublish ?? 200;
|
|
558
372
|
request.publishingEnabled = true;
|
|
559
|
-
request.priority = 1;
|
|
560
|
-
|
|
373
|
+
request.priority = options?.priority ?? 1;
|
|
374
|
+
this.logger.debug("Sending CreateSubscriptionRequest...");
|
|
561
375
|
const response = await this.secureChannel.issueServiceRequest(request);
|
|
562
|
-
|
|
376
|
+
const serviceResult = response.responseHeader?.serviceResult;
|
|
377
|
+
if (serviceResult !== void 0 && serviceResult !== opcjsBase.StatusCode.Good) {
|
|
378
|
+
throw new Error(`CreateSubscriptionRequest failed: ${opcjsBase.StatusCodeToString(serviceResult)}`);
|
|
379
|
+
}
|
|
380
|
+
this.logger.debug(`Subscription created with id: ${response.subscriptionId}`);
|
|
563
381
|
return response.subscriptionId;
|
|
564
382
|
}
|
|
383
|
+
/**
|
|
384
|
+
* Sends a publish request to receive notifications from active subscriptions (OPC UA Part 4, Section 5.14.5).
|
|
385
|
+
* @param acknowledgements - Sequence numbers to acknowledge from previous publish responses.
|
|
386
|
+
* @returns The publish response containing notification data.
|
|
387
|
+
*/
|
|
565
388
|
// https://reference.opcfoundation.org/Core/Part4/v105/docs/5.14.5
|
|
566
389
|
async publish(acknowledgements) {
|
|
567
390
|
const request = new opcjsBase.PublishRequest();
|
|
568
391
|
request.requestHeader = this.createRequestHeader();
|
|
569
392
|
request.subscriptionAcknowledgements = acknowledgements;
|
|
570
|
-
|
|
393
|
+
this.logger.debug("Sending PublishRequest...");
|
|
571
394
|
const response = await this.secureChannel.issueServiceRequest(request);
|
|
572
|
-
|
|
395
|
+
const serviceResult = response.responseHeader?.serviceResult;
|
|
396
|
+
if (serviceResult !== void 0 && serviceResult !== opcjsBase.StatusCode.Good) {
|
|
397
|
+
throw new Error(`PublishRequest failed: ${opcjsBase.StatusCodeToString(serviceResult)}`);
|
|
398
|
+
}
|
|
399
|
+
this.logger.debug("Received PublishResponse.");
|
|
573
400
|
return response;
|
|
574
401
|
}
|
|
575
402
|
constructor(authToken, secureChannel) {
|
|
@@ -577,7 +404,15 @@ var SubscriptionService = class extends ServiceBase {
|
|
|
577
404
|
}
|
|
578
405
|
};
|
|
579
406
|
var MonitoredItemService = class extends ServiceBase {
|
|
580
|
-
|
|
407
|
+
logger = opcjsBase.getLogger("services.MonitoredItemService");
|
|
408
|
+
/**
|
|
409
|
+
* Creates monitored items within a subscription (OPC UA Part 4, Section 5.13.2).
|
|
410
|
+
* @param subscriptionId - ID of the subscription to add monitored items to.
|
|
411
|
+
* @param ids - Array of NodeIds and client handles identifying the items to monitor.
|
|
412
|
+
* @param samplingInterval - Requested sampling interval in milliseconds. -1 = use subscription publishing interval.
|
|
413
|
+
* @param queueSize - Requested queue size for each monitored item.
|
|
414
|
+
*/
|
|
415
|
+
async createMonitoredItems(subscriptionId, ids, samplingInterval = 1e3, queueSize = 100) {
|
|
581
416
|
const items = ids.map((ni) => {
|
|
582
417
|
const readValueId = new opcjsBase.ReadValueId();
|
|
583
418
|
readValueId.nodeId = ni.id;
|
|
@@ -586,9 +421,9 @@ var MonitoredItemService = class extends ServiceBase {
|
|
|
586
421
|
readValueId.dataEncoding = new opcjsBase.QualifiedName(0, "");
|
|
587
422
|
const monitoringParameters = new opcjsBase.MonitoringParameters();
|
|
588
423
|
monitoringParameters.clientHandle = ni.handle;
|
|
589
|
-
monitoringParameters.samplingInterval =
|
|
424
|
+
monitoringParameters.samplingInterval = samplingInterval;
|
|
590
425
|
monitoringParameters.filter = opcjsBase.ExtensionObject.newEmpty();
|
|
591
|
-
monitoringParameters.queueSize =
|
|
426
|
+
monitoringParameters.queueSize = queueSize;
|
|
592
427
|
monitoringParameters.discardOldest = true;
|
|
593
428
|
const monitoredItemCreateRequest = new opcjsBase.MonitoredItemCreateRequest();
|
|
594
429
|
monitoredItemCreateRequest.itemToMonitor = readValueId;
|
|
@@ -601,26 +436,38 @@ var MonitoredItemService = class extends ServiceBase {
|
|
|
601
436
|
request.subscriptionId = subscriptionId;
|
|
602
437
|
request.timestampsToReturn = opcjsBase.TimestampsToReturnEnum.Source;
|
|
603
438
|
request.itemsToCreate = items;
|
|
604
|
-
|
|
605
|
-
await this.secureChannel.issueServiceRequest(request);
|
|
439
|
+
this.logger.debug("Sending CreateMonitoredItemsRequest...");
|
|
440
|
+
const response = await this.secureChannel.issueServiceRequest(request);
|
|
441
|
+
const serviceResult = response.responseHeader?.serviceResult;
|
|
442
|
+
if (serviceResult !== void 0 && serviceResult !== opcjsBase.StatusCode.Good) {
|
|
443
|
+
throw new Error(`CreateMonitoredItemsRequest failed: ${opcjsBase.StatusCodeToString(serviceResult)}`);
|
|
444
|
+
}
|
|
445
|
+
for (const result of response.results ?? []) {
|
|
446
|
+
if (result.statusCode !== void 0 && result.statusCode !== opcjsBase.StatusCode.Good) {
|
|
447
|
+
this.logger.warn(`Failed to create monitored item: ${opcjsBase.StatusCodeToString(result.statusCode)}`);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
606
450
|
}
|
|
607
451
|
constructor(authToken, secureChannel) {
|
|
608
452
|
super(authToken, secureChannel);
|
|
609
453
|
}
|
|
610
454
|
};
|
|
611
455
|
var MethodService = class extends ServiceBase {
|
|
456
|
+
logger = opcjsBase.getLogger("services.MethodService");
|
|
612
457
|
/**
|
|
613
458
|
* Calls one or more methods on the server (OPC UA Part 4, Section 5.11.2).
|
|
614
459
|
* @param methodsToCall - Array of CallMethodRequest describing each method to invoke.
|
|
615
|
-
* @returns Array of
|
|
460
|
+
* @returns Array of results containing output argument values and raw status code number, one per requested method.
|
|
616
461
|
*/
|
|
617
462
|
async call(methodsToCall) {
|
|
618
463
|
const request = new opcjsBase.CallRequest();
|
|
619
464
|
request.requestHeader = this.createRequestHeader();
|
|
620
465
|
request.methodsToCall = methodsToCall;
|
|
466
|
+
this.logger.debug("Sending CallRequest...");
|
|
621
467
|
const response = await this.secureChannel.issueServiceRequest(request);
|
|
468
|
+
this.checkServiceResult(response.responseHeader?.serviceResult, "CallRequest");
|
|
622
469
|
return response.results.map((result) => ({
|
|
623
|
-
|
|
470
|
+
statusCode: result.statusCode ?? opcjsBase.StatusCode.Good,
|
|
624
471
|
value: result.outputArguments.map((arg) => arg.value)
|
|
625
472
|
}));
|
|
626
473
|
}
|
|
@@ -631,12 +478,18 @@ var MethodService = class extends ServiceBase {
|
|
|
631
478
|
|
|
632
479
|
// src/callMethodResult.ts
|
|
633
480
|
var CallMethodResult = class {
|
|
634
|
-
constructor(values,
|
|
481
|
+
constructor(values, statusCode) {
|
|
635
482
|
this.values = values;
|
|
636
|
-
this.
|
|
483
|
+
this.statusCode = statusCode;
|
|
637
484
|
}
|
|
638
485
|
};
|
|
639
486
|
var BrowseService = class extends ServiceBase {
|
|
487
|
+
logger = opcjsBase.getLogger("services.BrowseService");
|
|
488
|
+
/**
|
|
489
|
+
* Browses one or more Nodes and returns their References (OPC UA Part 4, Section 5.9.2).
|
|
490
|
+
* @param nodesToBrowse - Array of BrowseDescriptions specifying nodes and filter criteria.
|
|
491
|
+
* @returns Array of BrowseResult, one per requested node.
|
|
492
|
+
*/
|
|
640
493
|
async browse(nodesToBrowse) {
|
|
641
494
|
const view = new opcjsBase.ViewDescription();
|
|
642
495
|
view.viewId = opcjsBase.NodeId.newNumeric(0, 0);
|
|
@@ -647,15 +500,25 @@ var BrowseService = class extends ServiceBase {
|
|
|
647
500
|
request.view = view;
|
|
648
501
|
request.requestedMaxReferencesPerNode = 0;
|
|
649
502
|
request.nodesToBrowse = nodesToBrowse;
|
|
503
|
+
this.logger.debug("Sending BrowseRequest...");
|
|
650
504
|
const response = await this.secureChannel.issueServiceRequest(request);
|
|
505
|
+
this.checkServiceResult(response.responseHeader?.serviceResult, "BrowseRequest");
|
|
651
506
|
return response.results ?? [];
|
|
652
507
|
}
|
|
508
|
+
/**
|
|
509
|
+
* Continues a Browse operation using continuation points (OPC UA Part 4, Section 5.9.3).
|
|
510
|
+
* @param continuationPoints - Continuation points returned by a prior Browse or BrowseNext call.
|
|
511
|
+
* @param releaseContinuationPoints - If true, releases the continuation points without returning results.
|
|
512
|
+
* @returns Array of BrowseResult, one per continuation point.
|
|
513
|
+
*/
|
|
653
514
|
async browseNext(continuationPoints, releaseContinuationPoints) {
|
|
654
515
|
const request = new opcjsBase.BrowseNextRequest();
|
|
655
516
|
request.requestHeader = this.createRequestHeader();
|
|
656
517
|
request.releaseContinuationPoints = releaseContinuationPoints;
|
|
657
518
|
request.continuationPoints = continuationPoints;
|
|
519
|
+
this.logger.debug("Sending BrowseNextRequest...");
|
|
658
520
|
const response = await this.secureChannel.issueServiceRequest(request);
|
|
521
|
+
this.checkServiceResult(response.responseHeader?.serviceResult, "BrowseNextRequest");
|
|
659
522
|
return response.results ?? [];
|
|
660
523
|
}
|
|
661
524
|
constructor(authToken, secureChannel) {
|
|
@@ -692,12 +555,50 @@ var Client = class {
|
|
|
692
555
|
session;
|
|
693
556
|
subscriptionHandler;
|
|
694
557
|
logger;
|
|
558
|
+
// Stored after connect() so that refreshSession() can recreate services.
|
|
559
|
+
secureChannel;
|
|
560
|
+
sessionHandler;
|
|
695
561
|
getSession() {
|
|
696
562
|
if (!this.session) {
|
|
697
563
|
throw new Error("No session available");
|
|
698
564
|
}
|
|
699
565
|
return this.session;
|
|
700
566
|
}
|
|
567
|
+
/**
|
|
568
|
+
* (Re-)initialises all session-scoped services from the current `this.session`.
|
|
569
|
+
* Called both after the initial `connect()` and after a session refresh.
|
|
570
|
+
*/
|
|
571
|
+
initServices() {
|
|
572
|
+
const authToken = this.session.getAuthToken();
|
|
573
|
+
const sc = this.secureChannel;
|
|
574
|
+
this.attributeService = new AttributeService(authToken, sc);
|
|
575
|
+
this.methodService = new MethodService(authToken, sc);
|
|
576
|
+
this.browseService = new BrowseService(authToken, sc);
|
|
577
|
+
this.subscriptionHandler = new SubscriptionHandler(
|
|
578
|
+
new SubscriptionService(authToken, sc),
|
|
579
|
+
new MonitoredItemService(authToken, sc)
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Executes `fn` and, if it throws a `SessionInvalidError`, creates a fresh
|
|
584
|
+
* session and retries the operation exactly once.
|
|
585
|
+
*
|
|
586
|
+
* This covers the reactive case: a service call reveals that the server has
|
|
587
|
+
* already dropped the session (e.g. due to timeout). The new session is
|
|
588
|
+
* established transparently before re-running the original operation.
|
|
589
|
+
*/
|
|
590
|
+
async withSessionRefresh(fn) {
|
|
591
|
+
try {
|
|
592
|
+
return await fn();
|
|
593
|
+
} catch (err) {
|
|
594
|
+
if (!(err instanceof SessionInvalidError)) throw err;
|
|
595
|
+
this.logger.info(`Session invalid (${err.statusCode.toString(16)}), refreshing session...`);
|
|
596
|
+
this.session = await this.sessionHandler.createNewSession(this.identity);
|
|
597
|
+
this.initServices();
|
|
598
|
+
this.logger.info("Session refreshed, retrying operation.");
|
|
599
|
+
return await fn();
|
|
600
|
+
}
|
|
601
|
+
}
|
|
701
602
|
async connect() {
|
|
702
603
|
const wsOptions = { endpoint: this.endpointUrl };
|
|
703
604
|
const ws = new opcjsBase.WebSocketFascade(wsOptions);
|
|
@@ -742,24 +643,21 @@ var Client = class {
|
|
|
742
643
|
await sc.openSecureChannel();
|
|
743
644
|
this.logger.debug("Secure channel established.");
|
|
744
645
|
this.logger.debug("Creating session...");
|
|
745
|
-
|
|
746
|
-
this.
|
|
646
|
+
this.sessionHandler = new SessionHandler(sc, this.configuration);
|
|
647
|
+
this.secureChannel = sc;
|
|
648
|
+
this.session = await this.sessionHandler.createNewSession(this.identity);
|
|
747
649
|
this.logger.debug("Session created.");
|
|
748
650
|
this.logger.debug("Initializing services...");
|
|
749
|
-
this.
|
|
750
|
-
this.methodService = new MethodService(this.session.getAuthToken(), sc);
|
|
751
|
-
this.browseService = new BrowseService(this.session.getAuthToken(), sc);
|
|
752
|
-
this.subscriptionHandler = new SubscriptionHandler(
|
|
753
|
-
new SubscriptionService(this.session.getAuthToken(), sc),
|
|
754
|
-
new MonitoredItemService(this.session.getAuthToken(), sc)
|
|
755
|
-
);
|
|
651
|
+
this.initServices();
|
|
756
652
|
}
|
|
757
653
|
async disconnect() {
|
|
758
654
|
this.logger.info("Disconnecting from OPC UA server...");
|
|
759
655
|
}
|
|
760
656
|
async read(ids) {
|
|
761
|
-
|
|
762
|
-
|
|
657
|
+
return this.withSessionRefresh(async () => {
|
|
658
|
+
const result = await this.attributeService?.ReadValue(ids);
|
|
659
|
+
return result?.map((r) => new ReadValueResult(r.value, r.statusCode)) ?? [];
|
|
660
|
+
});
|
|
763
661
|
}
|
|
764
662
|
/**
|
|
765
663
|
* Method for calling a single method on the server.
|
|
@@ -769,17 +667,21 @@ var Client = class {
|
|
|
769
667
|
* @returns The CallMethodResult for the invoked method.
|
|
770
668
|
*/
|
|
771
669
|
async callMethod(objectId, methodId, inputArguments = []) {
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
670
|
+
return this.withSessionRefresh(async () => {
|
|
671
|
+
const request = new opcjsBase.CallMethodRequest();
|
|
672
|
+
request.objectId = objectId;
|
|
673
|
+
request.methodId = methodId;
|
|
674
|
+
request.inputArguments = inputArguments.map((arg) => opcjsBase.Variant.newFrom(arg));
|
|
675
|
+
const responses = await this.methodService.call([request]);
|
|
676
|
+
const response = responses[0];
|
|
677
|
+
return new CallMethodResult(response.value, response.statusCode);
|
|
678
|
+
});
|
|
779
679
|
}
|
|
780
680
|
async browse(nodeId, recursive = false) {
|
|
781
|
-
|
|
782
|
-
|
|
681
|
+
return this.withSessionRefresh(() => {
|
|
682
|
+
const visited = /* @__PURE__ */ new Set();
|
|
683
|
+
return this.browseRecursive(nodeId, recursive, visited);
|
|
684
|
+
});
|
|
783
685
|
}
|
|
784
686
|
async browseRecursive(nodeId, recursive, visited) {
|
|
785
687
|
const nodeKey = `${nodeId.namespace}:${nodeId.identifier}`;
|
|
@@ -928,6 +830,7 @@ var UserIdentity = class _UserIdentity {
|
|
|
928
830
|
exports.BrowseNodeResult = BrowseNodeResult;
|
|
929
831
|
exports.Client = Client;
|
|
930
832
|
exports.ConfigurationClient = ConfigurationClient;
|
|
833
|
+
exports.SessionInvalidError = SessionInvalidError;
|
|
931
834
|
exports.UserIdentity = UserIdentity;
|
|
932
835
|
//# sourceMappingURL=index.cjs.map
|
|
933
836
|
//# sourceMappingURL=index.cjs.map
|