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