node-opcua-server 2.167.0 → 2.168.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addressSpace_accessor.d.ts +6 -6
- package/dist/addressSpace_accessor.js +2 -2
- package/dist/addressSpace_accessor.js.map +1 -1
- package/dist/base_server.d.ts +14 -3
- package/dist/base_server.js +63 -41
- package/dist/base_server.js.map +1 -1
- package/dist/extract_password_from_blob.js +1 -3
- package/dist/extract_password_from_blob.js.map +1 -1
- package/dist/factory.d.ts +2 -3
- package/dist/factory.js.map +1 -1
- package/dist/filter/check_where_clause_on_address_space.d.ts +2 -2
- package/dist/filter/check_where_clause_on_address_space.js +1 -2
- package/dist/filter/check_where_clause_on_address_space.js.map +1 -1
- package/dist/filter/extract_event_fields.d.ts +3 -3
- package/dist/filter/extract_event_fields.js +1 -2
- package/dist/filter/extract_event_fields.js.map +1 -1
- package/dist/helper.d.ts +3 -3
- package/dist/helper.js +4 -8
- package/dist/helper.js.map +1 -1
- package/dist/i_address_space_accessor.d.ts +4 -4
- package/dist/i_channel_data.d.ts +1 -1
- package/dist/i_register_server_manager.d.ts +1 -1
- package/dist/i_server_side_publish_engine.d.ts +8 -6
- package/dist/i_server_side_publish_engine.js +7 -2
- package/dist/i_server_side_publish_engine.js.map +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.js +8 -7
- package/dist/index.js.map +1 -1
- package/dist/invalidate_server_certificate_cache.d.ts +16 -0
- package/dist/invalidate_server_certificate_cache.js +28 -0
- package/dist/invalidate_server_certificate_cache.js.map +1 -0
- package/dist/monitored_item.d.ts +10 -11
- package/dist/monitored_item.js +38 -39
- package/dist/monitored_item.js.map +1 -1
- package/dist/node_sampler.d.ts +1 -1
- package/dist/node_sampler.js +2 -4
- package/dist/node_sampler.js.map +1 -1
- package/dist/opcua_server.d.ts +57 -62
- package/dist/opcua_server.js +7 -7
- package/dist/opcua_server.js.map +1 -1
- package/dist/register_server_manager_hidden.d.ts +1 -1
- package/dist/register_server_manager_hidden.js +2 -4
- package/dist/register_server_manager_hidden.js.map +1 -1
- package/dist/register_server_manager_mdns_only.d.ts +1 -1
- package/dist/register_server_manager_mdns_only.js.map +1 -1
- package/dist/sampling_func.d.ts +2 -2
- package/dist/server_capabilities.d.ts +3 -3
- package/dist/server_capabilities.js.map +1 -1
- package/dist/server_end_point.d.ts +45 -2
- package/dist/server_end_point.js +130 -32
- package/dist/server_end_point.js.map +1 -1
- package/dist/server_engine.js +29 -25
- package/dist/server_engine.js.map +1 -1
- package/dist/server_publish_engine.d.ts +5 -5
- package/dist/server_publish_engine.js +29 -23
- package/dist/server_publish_engine.js.map +1 -1
- package/dist/server_publish_engine_for_orphan_subscriptions.d.ts +2 -2
- package/dist/server_publish_engine_for_orphan_subscriptions.js.map +1 -1
- package/dist/server_session.d.ts +9 -10
- package/dist/server_session.js +11 -12
- package/dist/server_session.js.map +1 -1
- package/dist/server_subscription.d.ts +13 -13
- package/dist/server_subscription.js +100 -79
- package/dist/server_subscription.js.map +1 -1
- package/dist/sessions_compatible_for_transfer.d.ts +1 -1
- package/dist/sessions_compatible_for_transfer.js +1 -1
- package/dist/sessions_compatible_for_transfer.js.map +1 -1
- package/dist/user_manager.d.ts +4 -4
- package/dist/user_manager.js +1 -1
- package/dist/user_manager.js.map +1 -1
- package/dist/user_manager_ua.d.ts +2 -2
- package/dist/user_manager_ua.js +2 -2
- package/dist/user_manager_ua.js.map +1 -1
- package/dist/validate_filter.d.ts +7 -4
- package/dist/validate_filter.js +5 -6
- package/dist/validate_filter.js.map +1 -1
- package/package.json +46 -46
- package/source/addressSpace_accessor.ts +24 -24
- package/source/base_server.ts +73 -59
- package/source/extract_password_from_blob.ts +3 -11
- package/source/factory.ts +2 -4
- package/source/filter/check_where_clause_on_address_space.ts +4 -7
- package/source/filter/extract_event_fields.ts +4 -5
- package/source/helper.ts +9 -13
- package/source/i_address_space_accessor.ts +13 -4
- package/source/i_channel_data.ts +1 -1
- package/source/i_register_server_manager.ts +2 -4
- package/source/i_server_side_publish_engine.ts +16 -9
- package/source/index.ts +10 -9
- package/source/invalidate_server_certificate_cache.ts +26 -0
- package/source/monitored_item.ts +44 -42
- package/source/node_sampler.ts +9 -11
- package/source/opcua_server.ts +68 -88
- package/source/register_server_manager_hidden.ts +3 -5
- package/source/register_server_manager_mdns_only.ts +1 -3
- package/source/sampling_func.ts +2 -2
- package/source/server_capabilities.ts +9 -6
- package/source/server_end_point.ts +142 -42
- package/source/server_engine.ts +22 -22
- package/source/server_publish_engine.ts +35 -30
- package/source/server_publish_engine_for_orphan_subscriptions.ts +3 -3
- package/source/server_session.ts +36 -33
- package/source/server_subscription.ts +182 -184
- package/source/sessions_compatible_for_transfer.ts +9 -9
- package/source/user_manager.ts +7 -7
- package/source/user_manager_ua.ts +3 -5
- package/source/validate_filter.ts +9 -11
package/source/base_server.ts
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
// tslint:disable:no-console
|
|
5
5
|
|
|
6
6
|
import fs from "node:fs";
|
|
7
|
+
import { isIP } from "node:net";
|
|
7
8
|
import os from "node:os";
|
|
8
9
|
import path from "node:path";
|
|
9
|
-
import { isIP } from "node:net";
|
|
10
10
|
import { withLock } from "@ster5/global-mutex";
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
import chalk from "chalk";
|
|
13
13
|
import { assert } from "node-opcua-assert";
|
|
14
14
|
import { getDefaultCertificateManager, makeSubject, type OPCUACertificateManager } from "node-opcua-certificate-manager";
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
ipv4ToHex,
|
|
27
27
|
resolveFullyQualifiedDomainName
|
|
28
28
|
} from "node-opcua-hostname";
|
|
29
|
-
import type { Message, Response, ServerSecureChannelLayer } from "node-opcua-secure-channel";
|
|
29
|
+
import type { Message, Request, Response, ServerSecureChannelLayer } from "node-opcua-secure-channel";
|
|
30
30
|
import { FindServersRequest, FindServersResponse } from "node-opcua-service-discovery";
|
|
31
31
|
import { ApplicationDescription, ApplicationType, GetEndpointsResponse } from "node-opcua-service-endpoints";
|
|
32
32
|
import { ServiceFault } from "node-opcua-service-secure-channel";
|
|
@@ -82,6 +82,11 @@ function cleanupEndpoint(endpoint: OPCUAServerEndPoint) {
|
|
|
82
82
|
endpoint.removeListener("openSecureChannelFailure", endpoint._on_openSecureChannelFailure);
|
|
83
83
|
endpoint._on_openSecureChannelFailure = undefined;
|
|
84
84
|
}
|
|
85
|
+
if (endpoint._on_channel_secured) {
|
|
86
|
+
assert(typeof endpoint._on_channel_secured === "function");
|
|
87
|
+
endpoint.removeListener("channelSecured", endpoint._on_channel_secured);
|
|
88
|
+
endpoint._on_channel_secured = undefined;
|
|
89
|
+
}
|
|
85
90
|
}
|
|
86
91
|
|
|
87
92
|
/**
|
|
@@ -102,7 +107,18 @@ const emptyCallback = () => {
|
|
|
102
107
|
/* empty */
|
|
103
108
|
};
|
|
104
109
|
|
|
105
|
-
export
|
|
110
|
+
export interface OPCUABaseServerEvents {
|
|
111
|
+
request: [request: Request, channel: ServerSecureChannelLayer];
|
|
112
|
+
response: [response: Response, channel: ServerSecureChannelLayer];
|
|
113
|
+
newChannel: [channel: ServerSecureChannelLayer, endpoint: OPCUAServerEndPoint];
|
|
114
|
+
channelSecured: [channel: ServerSecureChannelLayer, endpoint: OPCUAServerEndPoint];
|
|
115
|
+
closeChannel: [channel: ServerSecureChannelLayer, endpoint: OPCUAServerEndPoint];
|
|
116
|
+
connectionRefused: [socketData: ISocketData, endpoint: OPCUAServerEndPoint];
|
|
117
|
+
openSecureChannelFailure: [socketData: ISocketData, channelData: IChannelData, endpoint: OPCUAServerEndPoint];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// biome-ignore lint/suspicious/noExplicitAny: must propagate EventEmitter generic
|
|
121
|
+
export class OPCUABaseServer<T extends OPCUABaseServerEvents = any> extends OPCUASecureObject<T> {
|
|
106
122
|
public static makeServiceFault = makeServiceFault;
|
|
107
123
|
|
|
108
124
|
/**
|
|
@@ -208,7 +224,7 @@ export class OPCUABaseServer extends OPCUASecureObject {
|
|
|
208
224
|
return [];
|
|
209
225
|
}
|
|
210
226
|
|
|
211
|
-
|
|
227
|
+
public async createDefaultCertificate(): Promise<void> {
|
|
212
228
|
if (fs.existsSync(this.certificateFile)) {
|
|
213
229
|
return;
|
|
214
230
|
}
|
|
@@ -391,11 +407,23 @@ export class OPCUABaseServer extends OPCUASecureObject {
|
|
|
391
407
|
|
|
392
408
|
installPeriodicClockAdjustment();
|
|
393
409
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
394
|
-
const server = this;
|
|
410
|
+
const server: OPCUABaseServer<OPCUABaseServerEvents> = this;
|
|
395
411
|
const _on_new_channel = function (this: OPCUAServerEndPoint, channel: ServerSecureChannelLayer) {
|
|
396
412
|
server.emit("newChannel", channel, this);
|
|
397
413
|
};
|
|
398
414
|
|
|
415
|
+
const _on_channel_secured = function (this: OPCUAServerEndPoint, channel: ServerSecureChannelLayer) {
|
|
416
|
+
// Install a response interceptor once per channel so the
|
|
417
|
+
// server can emit "response" events for diagnostics.
|
|
418
|
+
// Done here (after OpenSecureChannel) rather than at
|
|
419
|
+
// newChannel time, so the interceptor can rely on
|
|
420
|
+
// securityPolicy/securityMode being populated.
|
|
421
|
+
channel.setResponseInterceptor((_msg, response1) => {
|
|
422
|
+
server.emit("response", response1, channel);
|
|
423
|
+
});
|
|
424
|
+
server.emit("channelSecured", channel, this);
|
|
425
|
+
};
|
|
426
|
+
|
|
399
427
|
const _on_close_channel = function (this: OPCUAServerEndPoint, channel: ServerSecureChannelLayer) {
|
|
400
428
|
server.emit("closeChannel", channel, this);
|
|
401
429
|
};
|
|
@@ -420,6 +448,9 @@ export class OPCUABaseServer extends OPCUASecureObject {
|
|
|
420
448
|
endpoint._on_new_channel = _on_new_channel;
|
|
421
449
|
endpoint.on("newChannel", endpoint._on_new_channel);
|
|
422
450
|
|
|
451
|
+
endpoint._on_channel_secured = _on_channel_secured;
|
|
452
|
+
endpoint.on("channelSecured", endpoint._on_channel_secured);
|
|
453
|
+
|
|
423
454
|
endpoint._on_close_channel = _on_close_channel;
|
|
424
455
|
endpoint.on("closeChannel", endpoint._on_close_channel);
|
|
425
456
|
|
|
@@ -442,17 +473,18 @@ export class OPCUABaseServer extends OPCUASecureObject {
|
|
|
442
473
|
uninstallPeriodicClockAdjustment();
|
|
443
474
|
this.serverCertificateManager.dispose().then(() => {
|
|
444
475
|
debugLog("OPCUABaseServer#shutdown starting");
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
(endpoint: OPCUAServerEndPoint, callback: (err?: Error) => void) => {
|
|
476
|
+
const promises = this.endpoints.map((endpoint) => {
|
|
477
|
+
return new Promise<void>((resolve, reject) => {
|
|
448
478
|
cleanupEndpoint(endpoint);
|
|
449
|
-
endpoint.shutdown(
|
|
450
|
-
}
|
|
451
|
-
|
|
479
|
+
endpoint.shutdown((err) => (err ? reject(err) : resolve()));
|
|
480
|
+
});
|
|
481
|
+
});
|
|
482
|
+
Promise.all(promises)
|
|
483
|
+
.then(() => {
|
|
452
484
|
debugLog("shutdown completed");
|
|
453
|
-
done(
|
|
454
|
-
}
|
|
455
|
-
|
|
485
|
+
done();
|
|
486
|
+
})
|
|
487
|
+
.catch((err) => done(err));
|
|
456
488
|
});
|
|
457
489
|
}
|
|
458
490
|
|
|
@@ -463,28 +495,16 @@ export class OPCUABaseServer extends OPCUASecureObject {
|
|
|
463
495
|
// c8 ignore next
|
|
464
496
|
if (!callback) throw new Error("thenify is not available");
|
|
465
497
|
debugLog("OPCUABaseServer#shutdownChannels");
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
(endpoint: OPCUAServerEndPoint, inner_callback: (err?: Error | null) => void) => {
|
|
498
|
+
const promises = this.endpoints.map((endpoint) => {
|
|
499
|
+
return new Promise<void>((resolve, reject) => {
|
|
469
500
|
debugLog(" shutting down endpoint ", endpoint.endpointDescriptions()[0].endpointUrl);
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
endpoint.shutdown(callback2);
|
|
478
|
-
}
|
|
479
|
-
// xx (callback2: (err?: Error| null) => void) => {
|
|
480
|
-
// xx endpoint.restoreConnection(callback2);
|
|
481
|
-
// xx }
|
|
482
|
-
],
|
|
483
|
-
inner_callback
|
|
484
|
-
);
|
|
485
|
-
},
|
|
486
|
-
callback
|
|
487
|
-
);
|
|
501
|
+
endpoint.abruptlyInterruptChannels();
|
|
502
|
+
endpoint.shutdown((err) => (err ? reject(err) : resolve()));
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
Promise.all(promises)
|
|
506
|
+
.then(() => callback())
|
|
507
|
+
.catch((err) => callback?.(err));
|
|
488
508
|
}
|
|
489
509
|
|
|
490
510
|
/**
|
|
@@ -495,13 +515,6 @@ export class OPCUABaseServer extends OPCUASecureObject {
|
|
|
495
515
|
assert(message.requestId !== 0);
|
|
496
516
|
const request = message.request;
|
|
497
517
|
|
|
498
|
-
// install channel._on_response so we can intercept its call and emit the "response" event.
|
|
499
|
-
if (!channel._on_response) {
|
|
500
|
-
channel._on_response = (_msg: string, response1: Response /*, inner_message: Message*/) => {
|
|
501
|
-
this.emit("response", response1, channel);
|
|
502
|
-
};
|
|
503
|
-
}
|
|
504
|
-
|
|
505
518
|
// prepare request
|
|
506
519
|
this.prepare(message, channel);
|
|
507
520
|
|
|
@@ -516,7 +529,7 @@ export class OPCUABaseServer extends OPCUASecureObject {
|
|
|
516
529
|
let errMessage: string;
|
|
517
530
|
let response: Response;
|
|
518
531
|
|
|
519
|
-
this.emit("request", request, channel);
|
|
532
|
+
(this as OPCUABaseServer<OPCUABaseServerEvents>).emit("request", request, channel);
|
|
520
533
|
|
|
521
534
|
try {
|
|
522
535
|
// handler must be named _on_ActionRequest()
|
|
@@ -606,24 +619,24 @@ export class OPCUABaseServer extends OPCUASecureObject {
|
|
|
606
619
|
if (!callback) {
|
|
607
620
|
throw new Error("Internal Error");
|
|
608
621
|
}
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
(ep: OPCUAServerEndPoint, _inner_callback) => {
|
|
622
|
+
const promises = this.endpoints.map((ep) => {
|
|
623
|
+
return new Promise<void>((resolve, reject) => {
|
|
612
624
|
/* c8 ignore next */
|
|
613
625
|
if (doDebug) {
|
|
614
626
|
debugLog("Suspending ", ep.endpointDescriptions()[0].endpointUrl);
|
|
615
627
|
}
|
|
616
|
-
|
|
617
628
|
ep.suspendConnection((err?: Error | null) => {
|
|
618
629
|
/* c8 ignore next */
|
|
619
630
|
if (doDebug) {
|
|
620
631
|
debugLog("Suspended ", ep.endpointDescriptions()[0].endpointUrl);
|
|
621
632
|
}
|
|
622
|
-
|
|
633
|
+
err ? reject(err) : resolve();
|
|
623
634
|
});
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
)
|
|
635
|
+
});
|
|
636
|
+
});
|
|
637
|
+
Promise.all(promises)
|
|
638
|
+
.then(() => callback())
|
|
639
|
+
.catch((err) => callback(err));
|
|
627
640
|
}
|
|
628
641
|
|
|
629
642
|
/**
|
|
@@ -636,13 +649,14 @@ export class OPCUABaseServer extends OPCUASecureObject {
|
|
|
636
649
|
public resumeEndPoints(callback?: (err?: Error | null) => void): void | Promise<void> {
|
|
637
650
|
// c8 ignore next
|
|
638
651
|
if (!callback) throw new Error("thenify is not available");
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
652
|
+
const promises = this.endpoints.map((ep) => {
|
|
653
|
+
return new Promise<void>((resolve, reject) => {
|
|
654
|
+
ep.restoreConnection((err) => (err ? reject(err) : resolve()));
|
|
655
|
+
});
|
|
656
|
+
});
|
|
657
|
+
Promise.all(promises)
|
|
658
|
+
.then(() => callback())
|
|
659
|
+
.catch((err) => callback(err));
|
|
646
660
|
}
|
|
647
661
|
|
|
648
662
|
protected prepare(_message: Message, _channel: ServerSecureChannelLayer): void {
|
|
@@ -28,10 +28,7 @@ export interface ExtractPasswordResult {
|
|
|
28
28
|
* @param serverNonce - the nonce that was sent during
|
|
29
29
|
* CreateSession / last ActivateSession
|
|
30
30
|
*/
|
|
31
|
-
export function extractPasswordFromDecryptedBlob(
|
|
32
|
-
decryptedBuffer: Buffer,
|
|
33
|
-
serverNonce: Nonce
|
|
34
|
-
): ExtractPasswordResult {
|
|
31
|
+
export function extractPasswordFromDecryptedBlob(decryptedBuffer: Buffer, serverNonce: Nonce): ExtractPasswordResult {
|
|
35
32
|
const invalidResult: ExtractPasswordResult = {
|
|
36
33
|
valid: false,
|
|
37
34
|
password: ""
|
|
@@ -56,16 +53,11 @@ export function extractPasswordFromDecryptedBlob(
|
|
|
56
53
|
return invalidResult;
|
|
57
54
|
}
|
|
58
55
|
|
|
59
|
-
const password = decryptedBuffer
|
|
60
|
-
.subarray(4, 4 + passwordLength)
|
|
61
|
-
.toString("utf-8");
|
|
56
|
+
const password = decryptedBuffer.subarray(4, 4 + passwordLength).toString("utf-8");
|
|
62
57
|
|
|
63
58
|
// verify that the trailing bytes match the server nonce
|
|
64
59
|
// (nonce binding — ensures session integrity)
|
|
65
|
-
const trailingNonce = decryptedBuffer.subarray(
|
|
66
|
-
4 + passwordLength,
|
|
67
|
-
4 + passwordLength + serverNonce.length
|
|
68
|
-
);
|
|
60
|
+
const trailingNonce = decryptedBuffer.subarray(4 + passwordLength, 4 + passwordLength + serverNonce.length);
|
|
69
61
|
if (!trailingNonce.equals(serverNonce)) {
|
|
70
62
|
return invalidResult;
|
|
71
63
|
}
|
package/source/factory.ts
CHANGED
|
@@ -5,11 +5,9 @@
|
|
|
5
5
|
import { assert } from "node-opcua-assert";
|
|
6
6
|
import { ExtensionObject } from "node-opcua-extension-object";
|
|
7
7
|
import { getStandardDataTypeFactory } from "node-opcua-factory";
|
|
8
|
-
import { ExpandedNodeId } from "node-opcua-nodeid";
|
|
8
|
+
import type { ExpandedNodeId } from "node-opcua-nodeid";
|
|
9
9
|
|
|
10
|
-
export
|
|
11
|
-
/** */
|
|
12
|
-
}
|
|
10
|
+
export type EngineForFactory = {};
|
|
13
11
|
export class Factory {
|
|
14
12
|
public engine: EngineForFactory;
|
|
15
13
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { IAddressSpace,
|
|
2
|
-
import { checkFilter } from "node-opcua-service-filter";
|
|
3
|
-
import {
|
|
4
|
-
import { ContentFilter } from "node-opcua-types";
|
|
1
|
+
import type { IAddressSpace, IEventData, ISessionContext } from "node-opcua-address-space-base";
|
|
2
|
+
import { checkFilter, FilterContextOnAddressSpace } from "node-opcua-service-filter";
|
|
3
|
+
import type { ContentFilter } from "node-opcua-types";
|
|
5
4
|
|
|
6
5
|
export function checkWhereClauseOnAdressSpace(
|
|
7
6
|
addressSpace: IAddressSpace,
|
|
@@ -9,8 +8,6 @@ export function checkWhereClauseOnAdressSpace(
|
|
|
9
8
|
whereClause: ContentFilter,
|
|
10
9
|
eventData: IEventData
|
|
11
10
|
): boolean {
|
|
12
|
-
|
|
13
|
-
|
|
14
11
|
// const filterContext: FilterContext = {
|
|
15
12
|
// addressSpace,
|
|
16
13
|
// sessionContext,
|
|
@@ -24,6 +21,6 @@ export function checkWhereClauseOnAdressSpace(
|
|
|
24
21
|
// }
|
|
25
22
|
// };
|
|
26
23
|
const filterContext = new FilterContextOnAddressSpace(sessionContext, eventData);
|
|
27
|
-
|
|
24
|
+
|
|
28
25
|
return checkFilter(filterContext, whereClause);
|
|
29
26
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { IEventData, ISessionContext } from "node-opcua-address-space-base";
|
|
2
|
-
import { extractEventFieldsBase } from "node-opcua-service-filter";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { Variant } from "node-opcua-variant";
|
|
1
|
+
import type { IEventData, ISessionContext } from "node-opcua-address-space-base";
|
|
2
|
+
import { extractEventFieldsBase, FilterContextOnAddressSpace } from "node-opcua-service-filter";
|
|
3
|
+
import type { SimpleAttributeOperand } from "node-opcua-types";
|
|
4
|
+
import type { Variant } from "node-opcua-variant";
|
|
6
5
|
//
|
|
7
6
|
|
|
8
7
|
/**
|
package/source/helper.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import util from "util";
|
|
2
|
-
import { OPCUAServer } from "./opcua_server";
|
|
3
|
-
import { ServerEngine } from "./server_engine";
|
|
4
|
-
import { ServerSession } from "./server_session";
|
|
5
|
-
import { Subscription, SubscriptionState } from "./server_subscription";
|
|
2
|
+
import type { OPCUAServer } from "./opcua_server";
|
|
3
|
+
import type { ServerEngine } from "./server_engine";
|
|
4
|
+
import type { ServerSession } from "./server_session";
|
|
5
|
+
import { type Subscription, SubscriptionState } from "./server_subscription";
|
|
6
6
|
|
|
7
7
|
const consolelog = (...args: any) => {
|
|
8
8
|
const d = new Date();
|
|
@@ -25,13 +25,9 @@ const info = (subscription: Subscription) => {
|
|
|
25
25
|
SubscriptionState[subscription.state].padEnd(9),
|
|
26
26
|
subscription.state,
|
|
27
27
|
"kac=",
|
|
28
|
-
subscription.currentKeepAliveCount.toString().padStart(3)+
|
|
29
|
-
"/"+
|
|
30
|
-
subscription.maxKeepAliveCount.toString().padStart(3),
|
|
28
|
+
subscription.currentKeepAliveCount.toString().padStart(3) + "/" + subscription.maxKeepAliveCount.toString().padStart(3),
|
|
31
29
|
"ltc=",
|
|
32
|
-
subscription.currentLifetimeCount.toString().padStart(3)+
|
|
33
|
-
"/"+
|
|
34
|
-
subscription.lifeTimeCount.toString().padStart(3),
|
|
30
|
+
subscription.currentLifetimeCount.toString().padStart(3) + "/" + subscription.lifeTimeCount.toString().padStart(3),
|
|
35
31
|
"prc=",
|
|
36
32
|
subscription.publishEngine?.pendingPublishRequestCount.toString().padStart(3),
|
|
37
33
|
"pi=",
|
|
@@ -65,14 +61,14 @@ export function installSubscriptionMonitoring(subscription: Subscription) {
|
|
|
65
61
|
export function installSessionLoggingOnEngine(serverEngine: ServerEngine) {
|
|
66
62
|
function on_create_session(session: ServerSession) {
|
|
67
63
|
try {
|
|
68
|
-
session.on("activate_session",
|
|
64
|
+
session.on("activate_session", () => {
|
|
69
65
|
consolelog("activate_session");
|
|
70
66
|
});
|
|
71
67
|
|
|
72
68
|
session.on("statusChanged", (status) => {
|
|
73
69
|
consolelog("session status changed: ", status);
|
|
74
70
|
});
|
|
75
|
-
session.on("new_subscription",
|
|
71
|
+
session.on("new_subscription", (subscription) => {
|
|
76
72
|
installSubscriptionMonitoring(subscription);
|
|
77
73
|
});
|
|
78
74
|
} catch (err) {
|
|
@@ -80,7 +76,7 @@ export function installSessionLoggingOnEngine(serverEngine: ServerEngine) {
|
|
|
80
76
|
}
|
|
81
77
|
}
|
|
82
78
|
serverEngine.on("create_session", on_create_session);
|
|
83
|
-
serverEngine.once("session_closed",
|
|
79
|
+
serverEngine.once("session_closed", (session) => {
|
|
84
80
|
consolelog("session is closed");
|
|
85
81
|
serverEngine.removeListener("create_session", on_create_session);
|
|
86
82
|
});
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import { ISessionContext } from "node-opcua-address-space-base";
|
|
2
|
-
import { DataValue } from "node-opcua-data-value";
|
|
3
|
-
import { StatusCode } from "node-opcua-status-code";
|
|
4
|
-
import {
|
|
1
|
+
import type { ISessionContext } from "node-opcua-address-space-base";
|
|
2
|
+
import type { DataValue } from "node-opcua-data-value";
|
|
3
|
+
import type { StatusCode } from "node-opcua-status-code";
|
|
4
|
+
import type {
|
|
5
|
+
BrowseDescriptionOptions,
|
|
6
|
+
BrowseResult,
|
|
7
|
+
CallMethodRequest,
|
|
8
|
+
CallMethodResultOptions,
|
|
9
|
+
HistoryReadRequest,
|
|
10
|
+
HistoryReadResult,
|
|
11
|
+
ReadRequestOptions,
|
|
12
|
+
WriteValue
|
|
13
|
+
} from "node-opcua-types";
|
|
5
14
|
|
|
6
15
|
export interface IAddressSpaceAccessor {
|
|
7
16
|
browse(context: ISessionContext, nodesToBrowse: BrowseDescriptionOptions[]): Promise<BrowseResult[]>;
|
package/source/i_channel_data.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module node-opcua-server
|
|
3
3
|
*/
|
|
4
|
-
import { EventEmitter } from "events";
|
|
4
|
+
import type { EventEmitter } from "events";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Finite State Machine for RegisterServerManager.
|
|
@@ -46,12 +46,10 @@ export enum RegisterServerManagerStatus {
|
|
|
46
46
|
UNREGISTERING = 7,
|
|
47
47
|
UNREGISTERED = 8,
|
|
48
48
|
NOT_APPLICABLE = -1,
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
DISPOSING = 9
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
53
|
export interface IRegisterServerManager extends EventEmitter {
|
|
56
54
|
/** The URL of the discovery server the manager is configured to connect to. */
|
|
57
55
|
discoveryServerEndpointUrl: string;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { PublishResponseOptions, PublishResponse, StatusChangeNotification } from "node-opcua-types";
|
|
2
1
|
import assert from "node-opcua-assert";
|
|
3
|
-
import {
|
|
2
|
+
import type { ExtensionObject } from "node-opcua-extension-object";
|
|
3
|
+
import type { SequenceNumberGenerator } from "node-opcua-secure-channel";
|
|
4
|
+
import { PublishResponse, type PublishResponseOptions, type StatusChangeNotification } from "node-opcua-types";
|
|
5
|
+
import type { Subscription } from "./server_subscription";
|
|
4
6
|
|
|
5
7
|
export interface INotifMsg {
|
|
6
8
|
subscriptionId: number;
|
|
7
9
|
sequenceNumber: number;
|
|
8
|
-
notificationData:
|
|
10
|
+
notificationData: (ExtensionObject | null)[] | null;
|
|
9
11
|
moreNotifications: boolean;
|
|
10
12
|
}
|
|
11
13
|
|
|
@@ -25,10 +27,10 @@ export interface IClosedOrTransferredSubscription {
|
|
|
25
27
|
}
|
|
26
28
|
export class TransferredSubscription implements IClosedOrTransferredSubscription {
|
|
27
29
|
public id: number;
|
|
28
|
-
public publishEngine:
|
|
30
|
+
public publishEngine: IServerSidePublishEngine | null;
|
|
29
31
|
public _pending_notification?: StatusChangeNotification;
|
|
30
|
-
private _sequence_number_generator:
|
|
31
|
-
constructor(options: { id: number; generator:
|
|
32
|
+
private _sequence_number_generator: SequenceNumberGenerator | null;
|
|
33
|
+
constructor(options: { id: number; generator: SequenceNumberGenerator; publishEngine: IServerSidePublishEngine }) {
|
|
32
34
|
this.id = options.id;
|
|
33
35
|
this._sequence_number_generator = options.generator;
|
|
34
36
|
this.publishEngine = options.publishEngine;
|
|
@@ -41,8 +43,10 @@ export class TransferredSubscription implements IClosedOrTransferredSubscription
|
|
|
41
43
|
this.publishEngine = null;
|
|
42
44
|
}
|
|
43
45
|
_publish_pending_notifications(): void {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
if (!this._pending_notification) {
|
|
47
|
+
throw new Error("Internal Error: no pending notification");
|
|
48
|
+
}
|
|
49
|
+
const notificationMessage = this._pending_notification;
|
|
46
50
|
this._pending_notification = undefined;
|
|
47
51
|
const moreNotifications = false;
|
|
48
52
|
const subscriptionId = this.id;
|
|
@@ -68,7 +72,10 @@ export class TransferredSubscription implements IClosedOrTransferredSubscription
|
|
|
68
72
|
availableSequenceNumbers[availableSequenceNumbers.length - 1] === response.notificationMessage.sequenceNumber
|
|
69
73
|
);
|
|
70
74
|
response.availableSequenceNumbers = availableSequenceNumbers;
|
|
71
|
-
this.publishEngine
|
|
75
|
+
if (!this.publishEngine) {
|
|
76
|
+
throw new Error("Internal Error: publishEngine is null");
|
|
77
|
+
}
|
|
78
|
+
this.publishEngine._send_response(this as unknown as Subscription, response);
|
|
72
79
|
}
|
|
73
80
|
private _get_next_sequence_number(): number {
|
|
74
81
|
return this._sequence_number_generator ? this._sequence_number_generator.next() : 0;
|
package/source/index.ts
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
10
10
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
11
11
|
* subject to the following conditions:
|
|
12
|
-
*
|
|
12
|
+
*
|
|
13
13
|
* The above copyright notice and this permission notice shall be included in all
|
|
14
14
|
* copies or substantial portions of the Software.
|
|
15
|
-
*
|
|
15
|
+
*
|
|
16
16
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
17
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
18
18
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
@@ -24,15 +24,16 @@
|
|
|
24
24
|
* @module node-opcua-server
|
|
25
25
|
*/
|
|
26
26
|
export * from "./base_server";
|
|
27
|
-
export * from "./
|
|
27
|
+
export * from "./helper";
|
|
28
|
+
export * from "./invalidate_server_certificate_cache";
|
|
29
|
+
export * from "./monitored_item";
|
|
30
|
+
export * from "./opcua_server";
|
|
28
31
|
export * from "./register_server_manager";
|
|
29
32
|
export * from "./register_server_manager_mdns_only";
|
|
30
|
-
export * from "./server_publish_engine";
|
|
31
|
-
export * from "./server_subscription";
|
|
32
|
-
export * from "./server_session";
|
|
33
33
|
export * from "./server_capabilities";
|
|
34
|
+
export * from "./server_end_point";
|
|
34
35
|
export * from "./server_engine";
|
|
35
|
-
export * from "./
|
|
36
|
-
export * from "./
|
|
36
|
+
export * from "./server_publish_engine";
|
|
37
|
+
export * from "./server_session";
|
|
38
|
+
export * from "./server_subscription";
|
|
37
39
|
export * from "./user_manager";
|
|
38
|
-
export * from "./helper";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module node-opcua-server
|
|
3
|
+
*/
|
|
4
|
+
import { invalidateCachedSecrets } from "node-opcua-common";
|
|
5
|
+
import type { OPCUABaseServer } from "./base_server";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Invalidate all cached certificates on a running server so that
|
|
9
|
+
* subsequent GetEndpoints / OpenSecureChannel calls reflect the
|
|
10
|
+
* current on-disk certificate.
|
|
11
|
+
*
|
|
12
|
+
* Call this after replacing the server's certificate PEM file.
|
|
13
|
+
* Works with or without push certificate management.
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* // 1. write new cert to disk (e.g. via CertificateManager)
|
|
17
|
+
* // 2. tell the server to pick it up:
|
|
18
|
+
* invalidateServerCertificateCache(server);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function invalidateServerCertificateCache(server: OPCUABaseServer): void {
|
|
22
|
+
invalidateCachedSecrets(server);
|
|
23
|
+
for (const ep of server.endpoints) {
|
|
24
|
+
ep.invalidateCertificates();
|
|
25
|
+
}
|
|
26
|
+
}
|