node-opcua-server 2.72.2 → 2.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +3 -1
- package/dist/helper.d.ts +10 -0
- package/dist/helper.js +76 -0
- package/dist/helper.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/monitored_item.js +2 -1
- package/dist/monitored_item.js.map +1 -1
- package/dist/opcua_server.js +26 -22
- package/dist/opcua_server.js.map +1 -1
- package/dist/server_capabilities.js +5 -4
- package/dist/server_capabilities.js.map +1 -1
- package/dist/server_engine.d.ts +1 -1
- package/dist/server_engine.js +25 -25
- package/dist/server_engine.js.map +1 -1
- package/dist/server_publish_engine.d.ts +6 -5
- package/dist/server_publish_engine.js +22 -11
- package/dist/server_publish_engine.js.map +1 -1
- package/dist/server_publish_engine_for_orphan_subscriptions.js +3 -1
- package/dist/server_publish_engine_for_orphan_subscriptions.js.map +1 -1
- package/dist/server_session.d.ts +4 -3
- package/dist/server_session.js +7 -6
- package/dist/server_session.js.map +1 -1
- package/dist/server_subscription.d.ts +8 -2
- package/dist/server_subscription.js +75 -62
- 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 +3 -0
- package/dist/sessions_compatible_for_transfer.js.map +1 -1
- package/package.json +48 -47
- package/source/helper.ts +87 -0
- package/source/index.ts +2 -1
- package/source/monitored_item.ts +3 -2
- package/source/opcua_server.ts +27 -26
- package/source/server_capabilities.ts +5 -4
- package/source/server_engine.ts +29 -27
- package/source/server_publish_engine.ts +34 -21
- package/source/server_publish_engine_for_orphan_subscriptions.ts +6 -1
- package/source/server_session.ts +15 -13
- package/source/server_subscription.ts +89 -72
- package/source/sessions_compatible_for_transfer.ts +5 -1
|
@@ -11,7 +11,7 @@ import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
|
|
|
11
11
|
import { ObjectRegistry } from "node-opcua-object-registry";
|
|
12
12
|
import { StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
13
13
|
|
|
14
|
-
import { PublishRequest, PublishResponse, SubscriptionAcknowledgement } from "node-opcua-types";
|
|
14
|
+
import { PublishRequest, PublishResponse, ServiceFault, SubscriptionAcknowledgement } from "node-opcua-types";
|
|
15
15
|
import { Subscription } from "./server_subscription";
|
|
16
16
|
import { SubscriptionState } from "./server_subscription";
|
|
17
17
|
import { IServerSidePublishEngine, INotifMsg, IClosedOrTransferredSubscription } from "./i_server_side_publish_engine";
|
|
@@ -36,7 +36,7 @@ interface PublishData {
|
|
|
36
36
|
request: PublishRequest;
|
|
37
37
|
serverTimeWhenReceived: number;
|
|
38
38
|
results: StatusCode[];
|
|
39
|
-
callback: (request: PublishRequest, response: PublishResponse) => void;
|
|
39
|
+
callback: (request: PublishRequest, response: PublishResponse | ServiceFault) => void;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
function _assertValidPublishData(publishData: PublishData) {
|
|
@@ -116,7 +116,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
116
116
|
subscription: Subscription,
|
|
117
117
|
destPublishEngine: ServerSidePublishEngine,
|
|
118
118
|
sendInitialValues: boolean
|
|
119
|
-
): Promise<
|
|
119
|
+
): Promise<Subscription> {
|
|
120
120
|
const srcPublishEngine = subscription.publishEngine as any as ServerSidePublishEngine;
|
|
121
121
|
|
|
122
122
|
assert(!destPublishEngine.getSubscriptionById(subscription.id));
|
|
@@ -135,7 +135,9 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
135
135
|
// to the old Session.
|
|
136
136
|
subscription.notifyTransfer();
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
const tmp = srcPublishEngine.detach_subscription(subscription);
|
|
139
|
+
destPublishEngine.add_subscription(tmp);
|
|
140
|
+
|
|
139
141
|
subscription.resetLifeTimeCounter();
|
|
140
142
|
if (sendInitialValues) {
|
|
141
143
|
/* A Boolean parameter with the following values:
|
|
@@ -158,6 +160,8 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
158
160
|
|
|
159
161
|
assert(destPublishEngine.getSubscriptionById(subscription.id));
|
|
160
162
|
assert(!srcPublishEngine.getSubscriptionById(subscription.id));
|
|
163
|
+
|
|
164
|
+
return subscription;
|
|
161
165
|
}
|
|
162
166
|
|
|
163
167
|
public maxPublishRequestInQueue = 0;
|
|
@@ -321,16 +325,17 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
321
325
|
}
|
|
322
326
|
|
|
323
327
|
public on_close_subscription(subscription: IClosedOrTransferredSubscription): void {
|
|
324
|
-
debugLog("ServerSidePublishEngine#on_close_subscription", subscription.id);
|
|
328
|
+
doDebug && debugLog("ServerSidePublishEngine#on_close_subscription", subscription.id);
|
|
325
329
|
if (subscription.hasPendingNotifications) {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
330
|
+
doDebug &&
|
|
331
|
+
debugLog(
|
|
332
|
+
"ServerSidePublishEngine#on_close_subscription storing subscription",
|
|
333
|
+
subscription.id,
|
|
334
|
+
" to _closed_subscriptions because it has pending notification"
|
|
335
|
+
);
|
|
331
336
|
this._closed_subscriptions.push(subscription);
|
|
332
337
|
} else {
|
|
333
|
-
debugLog("ServerSidePublishEngine#on_close_subscription disposing subscription", subscription.id);
|
|
338
|
+
doDebug && debugLog("ServerSidePublishEngine#on_close_subscription disposing subscription", subscription.id);
|
|
334
339
|
// subscription is no longer needed
|
|
335
340
|
subscription.dispose();
|
|
336
341
|
}
|
|
@@ -357,7 +362,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
357
362
|
public findLateSubscriptions(): Subscription[] {
|
|
358
363
|
const subscriptions = Object.values(this._subscriptions);
|
|
359
364
|
return subscriptions.filter((subscription: Subscription) => {
|
|
360
|
-
return subscription.state === SubscriptionState.LATE && subscription.publishingEnabled;
|
|
365
|
+
return (subscription.state === SubscriptionState.LATE || !subscription.messageSent) && subscription.publishingEnabled;
|
|
361
366
|
});
|
|
362
367
|
}
|
|
363
368
|
|
|
@@ -398,7 +403,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
398
403
|
*/
|
|
399
404
|
public _on_PublishRequest(
|
|
400
405
|
request: PublishRequest,
|
|
401
|
-
callback?: (request1: PublishRequest, response: PublishResponse) => void
|
|
406
|
+
callback?: (request1: PublishRequest, response: PublishResponse| ServiceFault) => void
|
|
402
407
|
): void {
|
|
403
408
|
callback = callback || dummy_function;
|
|
404
409
|
assert(typeof callback === "function");
|
|
@@ -479,6 +484,10 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
479
484
|
s.timeToKeepAlive +
|
|
480
485
|
" m?=" +
|
|
481
486
|
s.hasUncollectedMonitoredItemNotifications +
|
|
487
|
+
" " +
|
|
488
|
+
SubscriptionState[s.state] +
|
|
489
|
+
" " +
|
|
490
|
+
s.messageSent +
|
|
482
491
|
"]"
|
|
483
492
|
)
|
|
484
493
|
.join(" \n")
|
|
@@ -493,6 +502,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
493
502
|
const starving_subscription = /* this.findSubscriptionWaitingForFirstPublish() || */ findLateSubscriptionSortedByPriority();
|
|
494
503
|
return starving_subscription;
|
|
495
504
|
}
|
|
505
|
+
|
|
496
506
|
private _feed_late_subscription() {
|
|
497
507
|
setImmediate(() => {
|
|
498
508
|
if (!this.pendingPublishRequestCount) {
|
|
@@ -500,7 +510,8 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
500
510
|
}
|
|
501
511
|
const starving_subscription = this._find_starving_subscription();
|
|
502
512
|
if (starving_subscription) {
|
|
503
|
-
|
|
513
|
+
doDebug &&
|
|
514
|
+
debugLog(chalk.bgWhite.red("feeding most late subscription subscriptionId = "), starving_subscription.id);
|
|
504
515
|
starving_subscription.process_subscription();
|
|
505
516
|
}
|
|
506
517
|
});
|
|
@@ -529,10 +540,10 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
529
540
|
|
|
530
541
|
private _send_error_for_request(publishData: PublishData, statusCode: StatusCode): void {
|
|
531
542
|
_assertValidPublishData(publishData);
|
|
532
|
-
const
|
|
543
|
+
const response = new ServiceFault({
|
|
533
544
|
responseHeader: { serviceResult: statusCode }
|
|
534
545
|
});
|
|
535
|
-
this._send_response_for_request(publishData,
|
|
546
|
+
this._send_response_for_request(publishData, response);
|
|
536
547
|
}
|
|
537
548
|
|
|
538
549
|
private _cancelPendingPublishRequest(statusCode: StatusCode): void {
|
|
@@ -621,7 +632,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
621
632
|
assert(this.pendingPublishRequestCount > 0);
|
|
622
633
|
assert(response.subscriptionId !== 0xffffff);
|
|
623
634
|
const publishData = this._publish_request_queue.shift()!;
|
|
624
|
-
this.
|
|
635
|
+
this._send_valid_response_for_request(publishData, response);
|
|
625
636
|
}
|
|
626
637
|
|
|
627
638
|
public _on_tick(): void {
|
|
@@ -646,15 +657,17 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
|
|
|
646
657
|
this._send_error_for_request(publishData, StatusCodes.BadTimeout);
|
|
647
658
|
}
|
|
648
659
|
}
|
|
649
|
-
|
|
650
|
-
|
|
660
|
+
public _send_response_for_request(publishData: PublishData, response: PublishResponse | ServiceFault): void {
|
|
661
|
+
response.responseHeader.requestHandle = publishData.request.requestHeader.requestHandle;
|
|
662
|
+
publishData.callback(publishData.request, response);
|
|
663
|
+
}
|
|
664
|
+
public _send_valid_response_for_request(publishData: PublishData, response: PublishResponse): void {
|
|
651
665
|
if (doDebug) {
|
|
652
666
|
debugLog("_send_response_for_request ", response.toString());
|
|
653
667
|
}
|
|
654
668
|
_assertValidPublishData(publishData);
|
|
655
669
|
// xx assert(response.responseHeader.requestHandle !== 0,"expecting a valid requestHandle");
|
|
656
670
|
response.results = publishData.results;
|
|
657
|
-
|
|
658
|
-
publishData.callback(publishData.request, response);
|
|
671
|
+
this._send_response_for_request(publishData, response);
|
|
659
672
|
}
|
|
660
673
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import * as chalk from "chalk";
|
|
6
6
|
|
|
7
7
|
import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
|
|
8
|
+
import { NodeId } from "node-opcua-nodeid";
|
|
8
9
|
|
|
9
10
|
import { ServerSidePublishEngine, ServerSidePublishEngineOptions } from "./server_publish_engine";
|
|
10
11
|
import { Subscription } from "./server_subscription";
|
|
@@ -28,6 +29,10 @@ export class ServerSidePublishEngineForOrphanSubscription extends ServerSidePubl
|
|
|
28
29
|
|
|
29
30
|
public add_subscription(subscription: Subscription): Subscription {
|
|
30
31
|
debugLog(chalk.bgCyan.yellow.bold(" adding live subscription with id="), subscription.id, " to orphan");
|
|
32
|
+
|
|
33
|
+
// detach subscription from old seession
|
|
34
|
+
subscription.$session = undefined;
|
|
35
|
+
|
|
31
36
|
super.add_subscription(subscription);
|
|
32
37
|
// also add an event handler to detected when the subscription has ended
|
|
33
38
|
// so we can automatically remove it from the orphan table
|
|
@@ -38,7 +43,7 @@ export class ServerSidePublishEngineForOrphanSubscription extends ServerSidePubl
|
|
|
38
43
|
// xx publish_engine.detach_subscription(subscription);
|
|
39
44
|
// Xx subscription.dispose();
|
|
40
45
|
};
|
|
41
|
-
subscription.
|
|
46
|
+
subscription.once("expired", (subscription as any)._expired_func);
|
|
42
47
|
return subscription;
|
|
43
48
|
}
|
|
44
49
|
|
package/source/server_session.ts
CHANGED
|
@@ -72,6 +72,7 @@ interface SessionSecurityDiagnosticsDataTypeEx extends SessionSecurityDiagnostic
|
|
|
72
72
|
$session: any;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
export type SessionStatus = "new" | "active" | "screwed" | "disposed" | "closed";
|
|
75
76
|
/**
|
|
76
77
|
*
|
|
77
78
|
* A Server session object.
|
|
@@ -99,13 +100,12 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
99
100
|
public static registry = new ObjectRegistry();
|
|
100
101
|
public static maxPublishRequestInQueue = 100;
|
|
101
102
|
|
|
102
|
-
public __status = "";
|
|
103
|
+
public __status: SessionStatus = "new";
|
|
103
104
|
public parent: ServerEngine;
|
|
104
105
|
public authenticationToken: NodeId;
|
|
105
106
|
public nodeId: NodeId;
|
|
106
107
|
public sessionName = "";
|
|
107
108
|
|
|
108
|
-
|
|
109
109
|
public publishEngine: ServerSidePublishEngine;
|
|
110
110
|
public sessionObject: any;
|
|
111
111
|
public readonly creationDate: Date;
|
|
@@ -227,18 +227,21 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
227
227
|
* the first transaction is the creation of the session
|
|
228
228
|
*/
|
|
229
229
|
public get clientLastContactTime(): number {
|
|
230
|
-
const lastSeen =
|
|
230
|
+
const lastSeen = this._watchDogData ? this._watchDogData.lastSeen : minOPCUADate.getTime();
|
|
231
231
|
return WatchDog.lastSeenToDuration(lastSeen);
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
public get status():
|
|
234
|
+
public get status(): SessionStatus {
|
|
235
235
|
return this.__status;
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
public set status(value:
|
|
238
|
+
public set status(value: SessionStatus) {
|
|
239
239
|
if (value === "active") {
|
|
240
240
|
this._createSessionObjectInAddressSpace();
|
|
241
241
|
}
|
|
242
|
+
if (this.__status !== value) {
|
|
243
|
+
this.emit("statusChanged", value);
|
|
244
|
+
}
|
|
242
245
|
this.__status = value;
|
|
243
246
|
}
|
|
244
247
|
|
|
@@ -304,7 +307,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
304
307
|
const propName = lowerFirstLetter(counterName + "Count");
|
|
305
308
|
// istanbul ignore next
|
|
306
309
|
if (!Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, propName)) {
|
|
307
|
-
|
|
310
|
+
errorLog("incrementRequestTotalCounter: cannot find", propName);
|
|
308
311
|
// xx return;
|
|
309
312
|
} else {
|
|
310
313
|
(this._sessionDiagnostics as any)[propName].totalCount += 1;
|
|
@@ -444,7 +447,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
444
447
|
assert(this.currentSubscriptionCount === 0);
|
|
445
448
|
|
|
446
449
|
this.status = "closed";
|
|
447
|
-
|
|
450
|
+
|
|
448
451
|
this._detach_channel();
|
|
449
452
|
|
|
450
453
|
/**
|
|
@@ -559,10 +562,10 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
559
562
|
|
|
560
563
|
public _detach_channel(): void {
|
|
561
564
|
const channel = this.channel;
|
|
562
|
-
|
|
565
|
+
|
|
563
566
|
// istanbul ignore next
|
|
564
567
|
if (!channel) {
|
|
565
|
-
return;
|
|
568
|
+
return;
|
|
566
569
|
// already detached !
|
|
567
570
|
// throw new Error("expecting a valid channel");
|
|
568
571
|
}
|
|
@@ -682,13 +685,13 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
682
685
|
|
|
683
686
|
Object.defineProperty(this._sessionDiagnostics, "sessionId", {
|
|
684
687
|
get(this: SessionDiagnosticsDataTypeEx) {
|
|
685
|
-
return this.$session
|
|
688
|
+
return this.$session ? this.$session.nodeId : NodeId.nullNodeId;
|
|
686
689
|
}
|
|
687
690
|
});
|
|
688
691
|
|
|
689
692
|
Object.defineProperty(this._sessionDiagnostics, "sessionName", {
|
|
690
693
|
get(this: SessionDiagnosticsDataTypeEx) {
|
|
691
|
-
return this.$session
|
|
694
|
+
return this.$session ? this.$session.sessionName.toString() : "";
|
|
692
695
|
}
|
|
693
696
|
});
|
|
694
697
|
|
|
@@ -910,8 +913,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
|
|
|
910
913
|
assert(this.nodeId instanceof NodeId);
|
|
911
914
|
|
|
912
915
|
subscription.$session = this;
|
|
913
|
-
|
|
914
|
-
subscription.sessionId = this.nodeId;
|
|
916
|
+
assert(subscription.sessionId === this.nodeId);
|
|
915
917
|
|
|
916
918
|
this._cumulatedSubscriptionCount += 1;
|
|
917
919
|
|