node-opcua-server 2.53.0 → 2.56.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -20
- package/dist/base_server.js +12 -14
- package/dist/base_server.js.map +1 -1
- package/dist/factory.d.ts +4 -2
- package/dist/factory.js.map +1 -1
- package/dist/history_server_capabilities.js.map +1 -1
- package/dist/i_server_side_publish_engine.d.ts +1 -1
- package/dist/i_server_side_publish_engine.js +1 -1
- package/dist/i_server_side_publish_engine.js.map +1 -1
- package/dist/monitored_item.d.ts +3 -0
- package/dist/monitored_item.js +7 -14
- package/dist/monitored_item.js.map +1 -1
- package/dist/node_sampler.js +1 -1
- package/dist/node_sampler.js.map +1 -1
- package/dist/opcua_server.d.ts +29 -44
- package/dist/opcua_server.js +218 -262
- package/dist/opcua_server.js.map +1 -1
- package/dist/queue.js +1 -0
- package/dist/queue.js.map +1 -1
- package/dist/register_server_manager.d.ts +4 -1
- package/dist/register_server_manager.js +5 -5
- package/dist/register_server_manager.js.map +1 -1
- package/dist/register_server_manager_hidden.d.ts +1 -1
- package/dist/register_server_manager_hidden.js.map +1 -1
- package/dist/register_server_manager_mdns_only.d.ts +4 -1
- package/dist/register_server_manager_mdns_only.js +1 -1
- package/dist/register_server_manager_mdns_only.js.map +1 -1
- package/dist/server_capabilities.js.map +1 -1
- package/dist/server_end_point.d.ts +4 -1
- package/dist/server_end_point.js +10 -11
- package/dist/server_end_point.js.map +1 -1
- package/dist/server_engine.d.ts +11 -7
- package/dist/server_engine.js +72 -74
- package/dist/server_engine.js.map +1 -1
- package/dist/server_publish_engine.d.ts +4 -1
- package/dist/server_publish_engine.js +5 -5
- 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 +1 -1
- package/dist/server_session.js +24 -29
- package/dist/server_session.js.map +1 -1
- package/dist/server_subscription.d.ts +3 -1
- package/dist/server_subscription.js +6 -6
- package/dist/server_subscription.js.map +1 -1
- package/dist/sessions_compatible_for_transfer.js +2 -1
- package/dist/sessions_compatible_for_transfer.js.map +1 -1
- package/dist/validate_filter.js +4 -7
- package/dist/validate_filter.js.map +1 -1
- package/package.json +45 -44
- package/source/base_server.ts +19 -22
- package/source/factory.ts +5 -2
- package/source/history_server_capabilities.ts +3 -4
- package/source/i_channel_data.ts +4 -8
- package/source/i_register_server_manager.ts +0 -3
- package/source/i_server_side_publish_engine.ts +5 -6
- package/source/i_socket_data.ts +1 -1
- package/source/index.ts +14 -14
- package/source/monitored_item.ts +32 -44
- package/source/node_sampler.ts +82 -82
- package/source/opcua_server.ts +326 -357
- package/source/queue.ts +6 -7
- package/source/register_server_manager.ts +35 -23
- package/source/register_server_manager_hidden.ts +8 -10
- package/source/register_server_manager_mdns_only.ts +8 -13
- package/source/server_capabilities.ts +0 -5
- package/source/server_end_point.ts +28 -30
- package/source/server_engine.ts +122 -122
- package/source/server_publish_engine.ts +24 -21
- package/source/server_publish_engine_for_orphan_subscriptions.ts +26 -26
- package/source/server_session.ts +44 -49
- package/source/server_subscription.ts +23 -23
- package/source/sessions_compatible_for_transfer.ts +26 -25
- package/source/validate_filter.ts +8 -22
- package/test_helpers/create_certificates.js +1 -1
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* @module node-opcua-server
|
|
3
3
|
*/
|
|
4
4
|
// tslint:disable:no-console
|
|
5
|
-
import * as chalk from "chalk";
|
|
6
5
|
import { EventEmitter } from "events";
|
|
6
|
+
import * as chalk from "chalk";
|
|
7
7
|
import { partition, sortBy } from "lodash";
|
|
8
8
|
|
|
9
9
|
import { assert } from "node-opcua-assert";
|
|
@@ -25,7 +25,7 @@ function traceLog(...args: [any?, ...any[]]) {
|
|
|
25
25
|
}
|
|
26
26
|
const a: string[] = args.map((x?: any) => x!);
|
|
27
27
|
a.unshift(chalk.yellow(" TRACE "));
|
|
28
|
-
debugLog
|
|
28
|
+
debugLog(...a);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export interface ServerSidePublishEngineOptions {
|
|
@@ -79,7 +79,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
79
79
|
public static transferSubscriptionsToOrphan(
|
|
80
80
|
srcPublishEngine: ServerSidePublishEngine,
|
|
81
81
|
destPublishEngine: ServerSidePublishEngine
|
|
82
|
-
) {
|
|
82
|
+
): void {
|
|
83
83
|
debugLog(
|
|
84
84
|
chalk.yellow(
|
|
85
85
|
"ServerSidePublishEngine#transferSubscriptionsToOrphan! " + "start transferring long live subscriptions to orphan"
|
|
@@ -117,7 +117,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
117
117
|
destPublishEngine: ServerSidePublishEngine,
|
|
118
118
|
sendInitialValues: boolean
|
|
119
119
|
): Promise<void> {
|
|
120
|
-
const srcPublishEngine =
|
|
120
|
+
const srcPublishEngine = subscription.publishEngine as any as ServerSidePublishEngine;
|
|
121
121
|
|
|
122
122
|
assert(!destPublishEngine.getSubscriptionById(subscription.id));
|
|
123
123
|
assert(srcPublishEngine.getSubscriptionById(subscription.id));
|
|
@@ -160,8 +160,8 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
160
160
|
assert(!srcPublishEngine.getSubscriptionById(subscription.id));
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
public maxPublishRequestInQueue
|
|
164
|
-
public isSessionClosed
|
|
163
|
+
public maxPublishRequestInQueue = 0;
|
|
164
|
+
public isSessionClosed = false;
|
|
165
165
|
|
|
166
166
|
private _publish_request_queue: PublishData[] = [];
|
|
167
167
|
private _subscriptions: { [key: string]: Subscription };
|
|
@@ -197,10 +197,10 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
197
197
|
let str = "";
|
|
198
198
|
str += `maxPublishRequestInQueue ${this.maxPublishRequestInQueue}\n`;
|
|
199
199
|
str += `subscriptions ${Object.keys(this._subscriptions).join()}\n`;
|
|
200
|
-
str += `closed subscriptions ${this._closed_subscriptions.map((s)=> s.id).join()}\n`;
|
|
201
|
-
return str;
|
|
200
|
+
str += `closed subscriptions ${this._closed_subscriptions.map((s) => s.id).join()}\n`;
|
|
201
|
+
return str;
|
|
202
202
|
}
|
|
203
|
-
public dispose() {
|
|
203
|
+
public dispose(): void {
|
|
204
204
|
debugLog("ServerSidePublishEngine#dispose");
|
|
205
205
|
|
|
206
206
|
assert(Object.keys(this._subscriptions).length === 0, "self._subscriptions count!=0");
|
|
@@ -271,7 +271,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
271
271
|
|
|
272
272
|
/**
|
|
273
273
|
*/
|
|
274
|
-
public shutdown() {
|
|
274
|
+
public shutdown(): void {
|
|
275
275
|
if (this.subscriptionCount !== 0) {
|
|
276
276
|
debugLog(chalk.red("Shutting down pending subscription"));
|
|
277
277
|
this.subscriptions.map((subscription: Subscription) => subscription.terminate());
|
|
@@ -316,7 +316,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
316
316
|
return result;
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
-
public _purge_dangling_subscription(subscriptionId: number) {
|
|
319
|
+
public _purge_dangling_subscription(subscriptionId: number): void {
|
|
320
320
|
this._closed_subscriptions = this._closed_subscriptions.filter((s) => s.id !== subscriptionId);
|
|
321
321
|
}
|
|
322
322
|
|
|
@@ -365,18 +365,18 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
365
365
|
return this.findLateSubscriptions().length > 0;
|
|
366
366
|
}
|
|
367
367
|
|
|
368
|
-
public findLateSubscriptionsSortedByAge() {
|
|
368
|
+
public findLateSubscriptionsSortedByAge(): Subscription[] {
|
|
369
369
|
let late_subscriptions = this.findLateSubscriptions();
|
|
370
370
|
late_subscriptions = sortBy(late_subscriptions, "timeToExpiration");
|
|
371
371
|
|
|
372
372
|
return late_subscriptions;
|
|
373
373
|
}
|
|
374
374
|
|
|
375
|
-
public cancelPendingPublishRequestBeforeChannelChange() {
|
|
375
|
+
public cancelPendingPublishRequestBeforeChannelChange(): void {
|
|
376
376
|
this._cancelPendingPublishRequest(StatusCodes.BadSecureChannelClosed);
|
|
377
377
|
}
|
|
378
378
|
|
|
379
|
-
public onSessionClose() {
|
|
379
|
+
public onSessionClose(): void {
|
|
380
380
|
this.isSessionClosed = true;
|
|
381
381
|
this._cancelPendingPublishRequest(StatusCodes.BadSessionClosed);
|
|
382
382
|
}
|
|
@@ -384,7 +384,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
384
384
|
/**
|
|
385
385
|
* @private
|
|
386
386
|
*/
|
|
387
|
-
public cancelPendingPublishRequest() {
|
|
387
|
+
public cancelPendingPublishRequest(): void {
|
|
388
388
|
assert(this.subscriptionCount === 0);
|
|
389
389
|
this._cancelPendingPublishRequest(StatusCodes.BadNoSubscription);
|
|
390
390
|
}
|
|
@@ -396,7 +396,10 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
396
396
|
* @private
|
|
397
397
|
* @internal
|
|
398
398
|
*/
|
|
399
|
-
public _on_PublishRequest(
|
|
399
|
+
public _on_PublishRequest(
|
|
400
|
+
request: PublishRequest,
|
|
401
|
+
callback?: (request1: PublishRequest, response: PublishResponse) => void
|
|
402
|
+
): void {
|
|
400
403
|
callback = callback || dummy_function;
|
|
401
404
|
assert(typeof callback === "function");
|
|
402
405
|
|
|
@@ -425,8 +428,8 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
425
428
|
this._publish_request_queue.push(publishData);
|
|
426
429
|
|
|
427
430
|
const processed = this._feed_closed_subscription();
|
|
428
|
-
//xx ( may be subscription has expired by
|
|
429
|
-
//xx ( may be subscription has expired by
|
|
431
|
+
//xx ( may be subscription has expired by themselves) assert(verif === this._publish_request_queue.length);
|
|
432
|
+
//xx ( may be subscription has expired by themselves) assert(processed);
|
|
430
433
|
return;
|
|
431
434
|
}
|
|
432
435
|
traceLog("server has received a PublishRequest but has no subscription opened");
|
|
@@ -593,7 +596,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
593
596
|
if (this.pendingPublishRequestCount === 0 || subscription.hasPendingNotifications) {
|
|
594
597
|
// we cannot send the keep alive PublishResponse
|
|
595
598
|
traceLog(
|
|
596
|
-
"send_keep_alive_response => cannot send keep-
|
|
599
|
+
"send_keep_alive_response => cannot send keep-alive (no PublishRequest left) subscriptionId = ",
|
|
597
600
|
subscriptionId
|
|
598
601
|
);
|
|
599
602
|
return false;
|
|
@@ -614,7 +617,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
614
617
|
);
|
|
615
618
|
return true;
|
|
616
619
|
}
|
|
617
|
-
public _send_response(subscription: Subscription, response: PublishResponse) {
|
|
620
|
+
public _send_response(subscription: Subscription, response: PublishResponse): void {
|
|
618
621
|
assert(this.pendingPublishRequestCount > 0);
|
|
619
622
|
assert(response.subscriptionId !== 0xffffff);
|
|
620
623
|
const publishData = this._publish_request_queue.shift()!;
|
|
@@ -644,7 +647,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
644
647
|
}
|
|
645
648
|
}
|
|
646
649
|
|
|
647
|
-
public _send_response_for_request(publishData: PublishData, response: PublishResponse) {
|
|
650
|
+
public _send_response_for_request(publishData: PublishData, response: PublishResponse): void {
|
|
648
651
|
if (doDebug) {
|
|
649
652
|
debugLog("_send_response_for_request ", response.toString());
|
|
650
653
|
}
|
|
@@ -6,7 +6,7 @@ import * as chalk from "chalk";
|
|
|
6
6
|
|
|
7
7
|
import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
|
|
8
8
|
|
|
9
|
-
import { ServerSidePublishEngine } from "./server_publish_engine";
|
|
9
|
+
import { ServerSidePublishEngine, ServerSidePublishEngineOptions } from "./server_publish_engine";
|
|
10
10
|
import { Subscription } from "./server_subscription";
|
|
11
11
|
|
|
12
12
|
const debugLog = make_debugLog(__filename);
|
|
@@ -22,31 +22,31 @@ const doDebug = checkDebugFlag(__filename);
|
|
|
22
22
|
* @internal
|
|
23
23
|
*/
|
|
24
24
|
export class ServerSidePublishEngineForOrphanSubscription extends ServerSidePublishEngine {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
constructor(options: ServerSidePublishEngineOptions) {
|
|
26
|
+
super(options);
|
|
27
|
+
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
29
|
+
public add_subscription(subscription: Subscription): Subscription {
|
|
30
|
+
debugLog(chalk.bgCyan.yellow.bold(" adding live subscription with id="), subscription.id, " to orphan");
|
|
31
|
+
super.add_subscription(subscription);
|
|
32
|
+
// also add an event handler to detected when the subscription has ended
|
|
33
|
+
// so we can automatically remove it from the orphan table
|
|
34
|
+
(subscription as any)._expired_func = function (this: Subscription) {
|
|
35
|
+
debugLog(chalk.bgCyan.yellow(" Removing expired subscription with id="), this.id, " from orphan");
|
|
36
|
+
// make sure all monitored item have been deleted
|
|
37
|
+
// Xx subscription.terminate();
|
|
38
|
+
// xx publish_engine.detach_subscription(subscription);
|
|
39
|
+
// Xx subscription.dispose();
|
|
40
|
+
};
|
|
41
|
+
subscription.on("expired", (subscription as any)._expired_func);
|
|
42
|
+
return subscription;
|
|
43
|
+
}
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
public detach_subscription(subscription: Subscription): Subscription {
|
|
46
|
+
// un set the event handler
|
|
47
|
+
super.detach_subscription(subscription);
|
|
48
|
+
subscription.removeListener("expired", (subscription as any)._expired_func);
|
|
49
|
+
(subscription as any)._expired_func = null;
|
|
50
|
+
return subscription;
|
|
51
|
+
}
|
|
52
52
|
}
|
package/source/server_session.ts
CHANGED
|
@@ -95,13 +95,13 @@ interface SessionSecurityDiagnosticsDataTypeEx extends SessionSecurityDiagnostic
|
|
|
95
95
|
*/
|
|
96
96
|
export class ServerSession extends EventEmitter implements ISubscriber, ISessionBase, IServerSession {
|
|
97
97
|
public static registry = new ObjectRegistry();
|
|
98
|
-
public static maxPublishRequestInQueue
|
|
98
|
+
public static maxPublishRequestInQueue = 100;
|
|
99
99
|
|
|
100
|
-
public __status
|
|
100
|
+
public __status = "";
|
|
101
101
|
public parent: ServerEngine;
|
|
102
102
|
public authenticationToken: NodeId;
|
|
103
103
|
public nodeId: NodeId;
|
|
104
|
-
public sessionName
|
|
104
|
+
public sessionName = "";
|
|
105
105
|
|
|
106
106
|
public publishEngine: ServerSidePublishEngine;
|
|
107
107
|
public sessionObject: any;
|
|
@@ -190,12 +190,12 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
190
190
|
return this.endpoint!;
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
public dispose() {
|
|
193
|
+
public dispose(): void {
|
|
194
194
|
debugLog("ServerSession#dispose()");
|
|
195
195
|
|
|
196
196
|
assert(!this.sessionObject, " sessionObject has not been cleared !");
|
|
197
197
|
|
|
198
|
-
this.parent =
|
|
198
|
+
this.parent = null as any as ServerEngine;
|
|
199
199
|
this.authenticationToken = NodeId.nullNodeId;
|
|
200
200
|
|
|
201
201
|
if (this.publishEngine) {
|
|
@@ -215,11 +215,11 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
215
215
|
ServerSession.registry.unregister(this);
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
public get clientConnectionTime() {
|
|
218
|
+
public get clientConnectionTime(): Date {
|
|
219
219
|
return this.creationDate;
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
public get clientLastContactTime() {
|
|
222
|
+
public get clientLastContactTime(): number {
|
|
223
223
|
return this._watchDogData!.lastSeen;
|
|
224
224
|
}
|
|
225
225
|
|
|
@@ -245,13 +245,12 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
245
245
|
return this.publishEngine ? this.publishEngine.pendingPublishRequestCount : 0;
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
public updateClientLastContactTime() {
|
|
249
|
-
|
|
250
|
-
if (session._sessionDiagnostics && session._sessionDiagnostics.clientLastContactTime) {
|
|
248
|
+
public updateClientLastContactTime(): void {
|
|
249
|
+
if (this._sessionDiagnostics && this._sessionDiagnostics.clientLastContactTime) {
|
|
251
250
|
const currentTime = new Date();
|
|
252
251
|
// do not record all ticks as this may be overwhelming,
|
|
253
|
-
if (currentTime.getTime() - 250 >=
|
|
254
|
-
|
|
252
|
+
if (currentTime.getTime() - 250 >= this._sessionDiagnostics.clientLastContactTime.getTime()) {
|
|
253
|
+
this._sessionDiagnostics.clientLastContactTime = currentTime;
|
|
255
254
|
}
|
|
256
255
|
}
|
|
257
256
|
}
|
|
@@ -262,14 +261,14 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
262
261
|
* @param currentTime {DateTime}
|
|
263
262
|
* @private
|
|
264
263
|
*/
|
|
265
|
-
public onClientSeen() {
|
|
264
|
+
public onClientSeen(): void {
|
|
266
265
|
this.updateClientLastContactTime();
|
|
267
266
|
|
|
268
267
|
if (this._sessionDiagnostics) {
|
|
269
268
|
// see https://opcfoundation-onlineapplications.org/mantis/view.php?id=4111
|
|
270
|
-
assert(
|
|
271
|
-
assert(
|
|
272
|
-
assert(
|
|
269
|
+
assert(Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, "currentMonitoredItemsCount"));
|
|
270
|
+
assert(Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, "currentSubscriptionsCount"));
|
|
271
|
+
assert(Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, "currentPublishRequestsInQueue"));
|
|
273
272
|
|
|
274
273
|
// note : https://opcfoundation-onlineapplications.org/mantis/view.php?id=4111
|
|
275
274
|
// sessionDiagnostics extension object uses a different spelling
|
|
@@ -286,16 +285,16 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
286
285
|
}
|
|
287
286
|
}
|
|
288
287
|
|
|
289
|
-
public incrementTotalRequestCount() {
|
|
288
|
+
public incrementTotalRequestCount(): void {
|
|
290
289
|
if (this._sessionDiagnostics && this._sessionDiagnostics.totalRequestCount) {
|
|
291
290
|
this._sessionDiagnostics.totalRequestCount.totalCount += 1;
|
|
292
291
|
}
|
|
293
292
|
}
|
|
294
293
|
|
|
295
|
-
public incrementRequestTotalCounter(counterName: string) {
|
|
294
|
+
public incrementRequestTotalCounter(counterName: string): void {
|
|
296
295
|
if (this._sessionDiagnostics) {
|
|
297
296
|
const propName = lowerFirstLetter(counterName + "Count");
|
|
298
|
-
if (!
|
|
297
|
+
if (!Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, propName)) {
|
|
299
298
|
console.log(" cannot find", propName);
|
|
300
299
|
// xx return;
|
|
301
300
|
} else {
|
|
@@ -305,11 +304,11 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
305
304
|
}
|
|
306
305
|
}
|
|
307
306
|
|
|
308
|
-
public incrementRequestErrorCounter(counterName: string) {
|
|
307
|
+
public incrementRequestErrorCounter(counterName: string): void {
|
|
309
308
|
this.parent?.incrementRejectedRequestsCount();
|
|
310
309
|
if (this._sessionDiagnostics) {
|
|
311
310
|
const propName = lowerFirstLetter(counterName + "Count");
|
|
312
|
-
if (!
|
|
311
|
+
if (!Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, propName)) {
|
|
313
312
|
console.log(" cannot find", propName);
|
|
314
313
|
// xx return;
|
|
315
314
|
} else {
|
|
@@ -352,8 +351,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
352
351
|
* number of monitored items
|
|
353
352
|
*/
|
|
354
353
|
public get currentMonitoredItemCount(): number {
|
|
355
|
-
|
|
356
|
-
return self.publishEngine ? self.publishEngine.currentMonitoredItemCount : 0;
|
|
354
|
+
return this.publishEngine ? this.publishEngine.currentMonitoredItemCount : 0;
|
|
357
355
|
}
|
|
358
356
|
|
|
359
357
|
/**
|
|
@@ -382,8 +380,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
382
380
|
* @return {StatusCode}
|
|
383
381
|
*/
|
|
384
382
|
public deleteSubscription(subscriptionId: number): StatusCode {
|
|
385
|
-
const
|
|
386
|
-
const subscription = session.getSubscription(subscriptionId);
|
|
383
|
+
const subscription = this.getSubscription(subscriptionId);
|
|
387
384
|
if (!subscription) {
|
|
388
385
|
return StatusCodes.BadSubscriptionIdInvalid;
|
|
389
386
|
}
|
|
@@ -391,8 +388,8 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
391
388
|
// xx this.publishEngine.remove_subscription(subscription);
|
|
392
389
|
subscription.terminate();
|
|
393
390
|
|
|
394
|
-
if (
|
|
395
|
-
const local_publishEngine =
|
|
391
|
+
if (this.currentSubscriptionCount === 0) {
|
|
392
|
+
const local_publishEngine = this.publishEngine;
|
|
396
393
|
local_publishEngine.cancelPendingPublishRequest();
|
|
397
394
|
}
|
|
398
395
|
return StatusCodes.Good;
|
|
@@ -452,7 +449,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
452
449
|
|
|
453
450
|
assert(this.publishEngine.subscriptionCount === 0);
|
|
454
451
|
this.publishEngine.dispose();
|
|
455
|
-
this.publishEngine =
|
|
452
|
+
this.publishEngine = null as any as ServerSidePublishEngine;
|
|
456
453
|
}
|
|
457
454
|
|
|
458
455
|
this._removeSessionObjectFromAddressSpace();
|
|
@@ -461,9 +458,8 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
461
458
|
assert(!this.sessionObject, "ServerSession#_removeSessionObjectFromAddressSpace must be called");
|
|
462
459
|
}
|
|
463
460
|
|
|
464
|
-
public registerNode(nodeId: NodeId) {
|
|
461
|
+
public registerNode(nodeId: NodeId): NodeId {
|
|
465
462
|
assert(nodeId instanceof NodeId);
|
|
466
|
-
const session = this;
|
|
467
463
|
|
|
468
464
|
if (nodeId.namespace === 0 && nodeId.identifierType === NodeIdType.NUMERIC) {
|
|
469
465
|
return nodeId;
|
|
@@ -471,22 +467,22 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
471
467
|
|
|
472
468
|
const key = nodeId.toString();
|
|
473
469
|
|
|
474
|
-
const registeredNode =
|
|
470
|
+
const registeredNode = this._registeredNodes[key];
|
|
475
471
|
if (registeredNode) {
|
|
476
472
|
// already registered
|
|
477
473
|
return registeredNode;
|
|
478
474
|
}
|
|
479
475
|
|
|
480
|
-
const node =
|
|
476
|
+
const node = this.addressSpace!.findNode(nodeId);
|
|
481
477
|
if (!node) {
|
|
482
478
|
return nodeId;
|
|
483
479
|
}
|
|
484
480
|
|
|
485
|
-
|
|
481
|
+
this._registeredNodesCounter += 1;
|
|
486
482
|
|
|
487
|
-
const aliasNodeId = makeNodeId(
|
|
488
|
-
|
|
489
|
-
|
|
483
|
+
const aliasNodeId = makeNodeId(this._registeredNodesCounter, registeredNodeNameSpace);
|
|
484
|
+
this._registeredNodes[key] = aliasNodeId;
|
|
485
|
+
this._registeredNodesInv[aliasNodeId.toString()] = node;
|
|
490
486
|
return aliasNodeId;
|
|
491
487
|
}
|
|
492
488
|
|
|
@@ -495,14 +491,13 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
495
491
|
if (aliasNodeId.namespace !== registeredNodeNameSpace) {
|
|
496
492
|
return; // not a registered Node
|
|
497
493
|
}
|
|
498
|
-
const session = this;
|
|
499
494
|
|
|
500
|
-
const node =
|
|
495
|
+
const node = this._registeredNodesInv[aliasNodeId.toString()];
|
|
501
496
|
if (!node) {
|
|
502
497
|
return;
|
|
503
498
|
}
|
|
504
|
-
|
|
505
|
-
|
|
499
|
+
this._registeredNodesInv[aliasNodeId.toString()] = null;
|
|
500
|
+
this._registeredNodes[node.nodeId.toString()] = null;
|
|
506
501
|
}
|
|
507
502
|
|
|
508
503
|
public resolveRegisteredNode(aliasNodeId: NodeId): NodeId {
|
|
@@ -519,7 +514,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
519
514
|
/**
|
|
520
515
|
* true if the underlying channel has been closed or aborted...
|
|
521
516
|
*/
|
|
522
|
-
public get aborted() {
|
|
517
|
+
public get aborted(): boolean {
|
|
523
518
|
if (!this.channel) {
|
|
524
519
|
return true;
|
|
525
520
|
}
|
|
@@ -528,7 +523,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
528
523
|
|
|
529
524
|
public createSubscription(parameters: CreateSubscriptionRequestOptions): Subscription {
|
|
530
525
|
const subscription = this.parent._createSubscriptionOnSession(this, parameters);
|
|
531
|
-
assert(!
|
|
526
|
+
assert(!Object.prototype.hasOwnProperty.call(parameters, "id"));
|
|
532
527
|
this.assignSubscription(subscription);
|
|
533
528
|
assert(subscription.$session === this);
|
|
534
529
|
assert(subscription.sessionId instanceof NodeId);
|
|
@@ -536,12 +531,12 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
536
531
|
return subscription;
|
|
537
532
|
}
|
|
538
533
|
|
|
539
|
-
public _attach_channel(channel: ServerSecureChannelLayer) {
|
|
534
|
+
public _attach_channel(channel: ServerSecureChannelLayer): void {
|
|
540
535
|
assert(this.nonce && this.nonce instanceof Buffer);
|
|
541
536
|
this.channel = channel;
|
|
542
537
|
this.channelId = channel.channelId;
|
|
543
538
|
const key = this.authenticationToken.toString();
|
|
544
|
-
assert(!
|
|
539
|
+
assert(!Object.prototype.hasOwnProperty.call(channel.sessionTokens, key), "channel has already a session");
|
|
545
540
|
|
|
546
541
|
channel.sessionTokens[key] = this;
|
|
547
542
|
|
|
@@ -550,7 +545,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
550
545
|
channel.on("abort", this.channel_abort_event_handler);
|
|
551
546
|
}
|
|
552
547
|
|
|
553
|
-
public _detach_channel() {
|
|
548
|
+
public _detach_channel(): void {
|
|
554
549
|
const channel = this.channel;
|
|
555
550
|
if (!channel) {
|
|
556
551
|
throw new Error("expecting a valid channel");
|
|
@@ -558,7 +553,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
558
553
|
assert(this.nonce && this.nonce instanceof Buffer);
|
|
559
554
|
assert(this.authenticationToken);
|
|
560
555
|
const key = this.authenticationToken.toString();
|
|
561
|
-
assert(
|
|
556
|
+
assert(Object.prototype.hasOwnProperty.call(channel.sessionTokens, key));
|
|
562
557
|
assert(this.channel);
|
|
563
558
|
assert(typeof this.channel_abort_event_handler === "function");
|
|
564
559
|
channel.removeListener("abort", this.channel_abort_event_handler);
|
|
@@ -568,7 +563,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
568
563
|
this.channelId = undefined;
|
|
569
564
|
}
|
|
570
565
|
|
|
571
|
-
public _exposeSubscriptionDiagnostics(subscription: Subscription) {
|
|
566
|
+
public _exposeSubscriptionDiagnostics(subscription: Subscription): void {
|
|
572
567
|
debugLog("ServerSession#_exposeSubscriptionDiagnostics");
|
|
573
568
|
assert(subscription.$session === this);
|
|
574
569
|
const subscriptionDiagnosticsArray = this._getSubscriptionDiagnosticsArray();
|
|
@@ -581,7 +576,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
581
576
|
}
|
|
582
577
|
}
|
|
583
578
|
|
|
584
|
-
public _unexposeSubscriptionDiagnostics(subscription: Subscription) {
|
|
579
|
+
public _unexposeSubscriptionDiagnostics(subscription: Subscription): void {
|
|
585
580
|
const subscriptionDiagnosticsArray = this._getSubscriptionDiagnosticsArray();
|
|
586
581
|
const subscriptionDiagnostics = subscription.subscriptionDiagnostics;
|
|
587
582
|
assert(subscriptionDiagnostics instanceof SubscriptionDiagnosticsDataType);
|
|
@@ -597,7 +592,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
597
592
|
* used as a callback for the Watchdog
|
|
598
593
|
* @private
|
|
599
594
|
*/
|
|
600
|
-
public watchdogReset() {
|
|
595
|
+
public watchdogReset(): void {
|
|
601
596
|
debugLog("Session#watchdogReset: the server session has expired and must be removed from the server");
|
|
602
597
|
// the server session has expired and must be removed from the server
|
|
603
598
|
this.emit("timeout");
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
// tslint:disable:no-console
|
|
5
5
|
|
|
6
|
-
import { Queue } from "./queue";
|
|
7
|
-
import * as chalk from "chalk";
|
|
8
6
|
import { EventEmitter } from "events";
|
|
7
|
+
import * as chalk from "chalk";
|
|
9
8
|
|
|
10
9
|
import { AddressSpace, BaseNode, Duration, UAObjectType } from "node-opcua-address-space";
|
|
11
10
|
import { checkSelectClauses } from "node-opcua-address-space";
|
|
@@ -35,6 +34,7 @@ import {
|
|
|
35
34
|
} from "node-opcua-service-subscription";
|
|
36
35
|
import { StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
37
36
|
import { AggregateFilterResult, ContentFilterResult, EventFieldList, EventFilterResult, NotificationData } from "node-opcua-types";
|
|
37
|
+
import { Queue } from "./queue";
|
|
38
38
|
|
|
39
39
|
import { MonitoredItem, MonitoredItemOptions, QueueItem } from "./monitored_item";
|
|
40
40
|
import { ServerSession } from "./server_session";
|
|
@@ -439,12 +439,12 @@ export type DeleteMonitoredItemHook = (subscription: Subscription, monitoredItem
|
|
|
439
439
|
* The Subscription class used in the OPCUA server side.
|
|
440
440
|
*/
|
|
441
441
|
export class Subscription extends EventEmitter {
|
|
442
|
-
public static minimumPublishingInterval
|
|
443
|
-
public static defaultPublishingInterval
|
|
442
|
+
public static minimumPublishingInterval = 50; // fastest possible
|
|
443
|
+
public static defaultPublishingInterval = 1000; // one second
|
|
444
444
|
public static maximumPublishingInterval: number = 1000 * 60 * 60 * 24 * 15; // 15 days
|
|
445
|
-
public static maxNotificationPerPublishHighLimit
|
|
446
|
-
public static maxMonitoredItemCount
|
|
447
|
-
|
|
445
|
+
public static maxNotificationPerPublishHighLimit = 1000;
|
|
446
|
+
public static maxMonitoredItemCount = 20000;
|
|
447
|
+
|
|
448
448
|
public static registry = new ObjectRegistry();
|
|
449
449
|
|
|
450
450
|
public sessionId: NodeId;
|
|
@@ -499,13 +499,13 @@ export class Subscription extends EventEmitter {
|
|
|
499
499
|
public $session?: ServerSession;
|
|
500
500
|
|
|
501
501
|
private _life_time_counter: number;
|
|
502
|
-
private _keep_alive_counter
|
|
502
|
+
private _keep_alive_counter = 0;
|
|
503
503
|
private _pending_notifications: Queue<InternalNotification>;
|
|
504
504
|
private _sent_notification_messages: NotificationMessage[];
|
|
505
505
|
private readonly _sequence_number_generator: SequenceNumberGenerator;
|
|
506
506
|
private readonly monitoredItems: { [key: number]: MonitoredItem };
|
|
507
507
|
private timerId: any;
|
|
508
|
-
private _hasUncollectedMonitoredItemNotifications
|
|
508
|
+
private _hasUncollectedMonitoredItemNotifications = false;
|
|
509
509
|
|
|
510
510
|
constructor(options: SubscriptionOptions) {
|
|
511
511
|
super();
|
|
@@ -649,14 +649,14 @@ export class Subscription extends EventEmitter {
|
|
|
649
649
|
* the CreateSubscription Service( 5.13.2).
|
|
650
650
|
* @private
|
|
651
651
|
*/
|
|
652
|
-
public resetLifeTimeCounter() {
|
|
652
|
+
public resetLifeTimeCounter(): void {
|
|
653
653
|
this._life_time_counter = 0;
|
|
654
654
|
}
|
|
655
655
|
|
|
656
656
|
/**
|
|
657
657
|
* @private
|
|
658
658
|
*/
|
|
659
|
-
public increaseLifeTimeCounter() {
|
|
659
|
+
public increaseLifeTimeCounter(): void {
|
|
660
660
|
this._life_time_counter += 1;
|
|
661
661
|
}
|
|
662
662
|
|
|
@@ -685,7 +685,7 @@ export class Subscription extends EventEmitter {
|
|
|
685
685
|
* Calling this method will also remove any monitored items.
|
|
686
686
|
*
|
|
687
687
|
*/
|
|
688
|
-
public terminate() {
|
|
688
|
+
public terminate(): void {
|
|
689
689
|
assert(arguments.length === 0);
|
|
690
690
|
debugLog("Subscription#terminate status", SubscriptionState[this.state]);
|
|
691
691
|
|
|
@@ -774,7 +774,7 @@ export class Subscription extends EventEmitter {
|
|
|
774
774
|
removeResults
|
|
775
775
|
};
|
|
776
776
|
}
|
|
777
|
-
public dispose() {
|
|
777
|
+
public dispose(): void {
|
|
778
778
|
if (doDebug) {
|
|
779
779
|
debugLog("Subscription#dispose", this.id, this.monitoredItemCount);
|
|
780
780
|
}
|
|
@@ -830,7 +830,7 @@ export class Subscription extends EventEmitter {
|
|
|
830
830
|
/**
|
|
831
831
|
* @internal
|
|
832
832
|
*/
|
|
833
|
-
public _flushSentNotifications() {
|
|
833
|
+
public _flushSentNotifications(): NotificationMessage[] {
|
|
834
834
|
const tmp = this._sent_notification_messages;
|
|
835
835
|
this._sent_notification_messages = [];
|
|
836
836
|
return tmp;
|
|
@@ -864,7 +864,7 @@ export class Subscription extends EventEmitter {
|
|
|
864
864
|
* - otherwise the sampling is adjusted
|
|
865
865
|
* @private
|
|
866
866
|
*/
|
|
867
|
-
public adjustSamplingInterval(samplingInterval: number, node: BaseNode) {
|
|
867
|
+
public adjustSamplingInterval(samplingInterval: number, node: BaseNode): number {
|
|
868
868
|
if (samplingInterval < 0) {
|
|
869
869
|
// - The value -1 indicates that the default sampling interval defined by the publishing
|
|
870
870
|
// interval of the Subscription is requested.
|
|
@@ -1034,7 +1034,7 @@ export class Subscription extends EventEmitter {
|
|
|
1034
1034
|
*/
|
|
1035
1035
|
public removeMonitoredItem(monitoredItemId: number): StatusCode {
|
|
1036
1036
|
debugLog("Removing monitoredIem ", monitoredItemId);
|
|
1037
|
-
if (!
|
|
1037
|
+
if (!Object.prototype.hasOwnProperty.call(this.monitoredItems, monitoredItemId.toString())) {
|
|
1038
1038
|
return StatusCodes.BadMonitoredItemIdInvalid;
|
|
1039
1039
|
}
|
|
1040
1040
|
|
|
@@ -1079,7 +1079,7 @@ export class Subscription extends EventEmitter {
|
|
|
1079
1079
|
return false;
|
|
1080
1080
|
}
|
|
1081
1081
|
|
|
1082
|
-
public get subscriptionId() {
|
|
1082
|
+
public get subscriptionId(): number {
|
|
1083
1083
|
return this.id;
|
|
1084
1084
|
}
|
|
1085
1085
|
|
|
@@ -1092,8 +1092,8 @@ export class Subscription extends EventEmitter {
|
|
|
1092
1092
|
* returns true if the notification has expired
|
|
1093
1093
|
* @param notification
|
|
1094
1094
|
*/
|
|
1095
|
-
public notificationHasExpired(notification:
|
|
1096
|
-
assert(
|
|
1095
|
+
public notificationHasExpired(notification: { start_tick: number }): boolean {
|
|
1096
|
+
assert(Object.prototype.hasOwnProperty.call(notification, "start_tick"));
|
|
1097
1097
|
assert(isFinite(notification.start_tick + this.maxKeepAliveCount));
|
|
1098
1098
|
return notification.start_tick + this.maxKeepAliveCount < this.publishIntervalCount;
|
|
1099
1099
|
}
|
|
@@ -1213,7 +1213,7 @@ export class Subscription extends EventEmitter {
|
|
|
1213
1213
|
*
|
|
1214
1214
|
* @private
|
|
1215
1215
|
*/
|
|
1216
|
-
public resetLifeTimeAndKeepAliveCounters() {
|
|
1216
|
+
public resetLifeTimeAndKeepAliveCounters(): void {
|
|
1217
1217
|
this.resetLifeTimeCounter();
|
|
1218
1218
|
this.resetKeepAliveCounter();
|
|
1219
1219
|
}
|
|
@@ -1260,8 +1260,8 @@ export class Subscription extends EventEmitter {
|
|
|
1260
1260
|
// Update counters ....
|
|
1261
1261
|
this._updateCounters(notificationMessage);
|
|
1262
1262
|
|
|
1263
|
-
assert(
|
|
1264
|
-
assert(
|
|
1263
|
+
assert(Object.prototype.hasOwnProperty.call(notificationMessage, "sequenceNumber"));
|
|
1264
|
+
assert(Object.prototype.hasOwnProperty.call(notificationMessage, "notificationData"));
|
|
1265
1265
|
// update diagnostics
|
|
1266
1266
|
this.subscriptionDiagnostics.publishRequestCount += 1;
|
|
1267
1267
|
|
|
@@ -1310,7 +1310,7 @@ export class Subscription extends EventEmitter {
|
|
|
1310
1310
|
}
|
|
1311
1311
|
}
|
|
1312
1312
|
|
|
1313
|
-
public process_subscription() {
|
|
1313
|
+
public process_subscription(): void {
|
|
1314
1314
|
assert(this.publishEngine!.pendingPublishRequestCount > 0);
|
|
1315
1315
|
|
|
1316
1316
|
if (!this.publishingEnabled) {
|