node-opcua-server 2.73.1 → 2.76.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.
Files changed (72) hide show
  1. package/LICENSE +3 -1
  2. package/dist/base_server.d.ts +110 -110
  3. package/dist/base_server.js +473 -473
  4. package/dist/factory.d.ts +12 -12
  5. package/dist/factory.js +23 -23
  6. package/dist/filter/check_where_clause_on_address_space.d.ts +3 -0
  7. package/dist/filter/check_where_clause_on_address_space.js +23 -0
  8. package/dist/filter/check_where_clause_on_address_space.js.map +1 -0
  9. package/dist/filter/extract_event_fields.d.ts +10 -0
  10. package/dist/filter/extract_event_fields.js +18 -0
  11. package/dist/filter/extract_event_fields.js.map +1 -0
  12. package/dist/helper.d.ts +10 -10
  13. package/dist/helper.js +75 -75
  14. package/dist/history_server_capabilities.d.ts +35 -35
  15. package/dist/history_server_capabilities.js +43 -43
  16. package/dist/i_channel_data.d.ts +13 -13
  17. package/dist/i_channel_data.js +2 -2
  18. package/dist/i_register_server_manager.d.ts +16 -16
  19. package/dist/i_register_server_manager.js +2 -2
  20. package/dist/i_server_side_publish_engine.d.ts +36 -36
  21. package/dist/i_server_side_publish_engine.js +49 -49
  22. package/dist/i_socket_data.d.ts +11 -11
  23. package/dist/i_socket_data.js +2 -2
  24. package/dist/index.d.ts +16 -16
  25. package/dist/index.js +32 -32
  26. package/dist/monitored_item.d.ts +177 -177
  27. package/dist/monitored_item.js +1001 -999
  28. package/dist/monitored_item.js.map +1 -1
  29. package/dist/node_sampler.d.ts +3 -3
  30. package/dist/node_sampler.js +75 -75
  31. package/dist/opcua_server.d.ts +747 -650
  32. package/dist/opcua_server.js +2431 -2394
  33. package/dist/opcua_server.js.map +1 -1
  34. package/dist/queue.d.ts +11 -11
  35. package/dist/queue.js +71 -71
  36. package/dist/register_server_manager.d.ts +96 -96
  37. package/dist/register_server_manager.js +584 -584
  38. package/dist/register_server_manager_hidden.d.ts +17 -17
  39. package/dist/register_server_manager_hidden.js +27 -27
  40. package/dist/register_server_manager_mdns_only.d.ts +22 -22
  41. package/dist/register_server_manager_mdns_only.js +55 -55
  42. package/dist/server_capabilities.d.ts +148 -148
  43. package/dist/server_capabilities.js +92 -92
  44. package/dist/server_end_point.d.ts +183 -183
  45. package/dist/server_end_point.js +817 -817
  46. package/dist/server_engine.d.ts +317 -317
  47. package/dist/server_engine.js +1716 -1716
  48. package/dist/server_publish_engine.d.ts +113 -112
  49. package/dist/server_publish_engine.js +541 -535
  50. package/dist/server_publish_engine.js.map +1 -1
  51. package/dist/server_publish_engine_for_orphan_subscriptions.d.ts +16 -16
  52. package/dist/server_publish_engine_for_orphan_subscriptions.js +51 -51
  53. package/dist/server_session.d.ts +182 -182
  54. package/dist/server_session.js +739 -739
  55. package/dist/server_subscription.d.ts +421 -421
  56. package/dist/server_subscription.js +1346 -1345
  57. package/dist/server_subscription.js.map +1 -1
  58. package/dist/sessions_compatible_for_transfer.d.ts +2 -2
  59. package/dist/sessions_compatible_for_transfer.js +39 -39
  60. package/dist/user_manager.d.ts +32 -32
  61. package/dist/user_manager.js +74 -74
  62. package/dist/user_manager_ua.d.ts +3 -3
  63. package/dist/user_manager_ua.js +39 -39
  64. package/dist/validate_filter.d.ts +5 -5
  65. package/dist/validate_filter.js +60 -60
  66. package/package.json +50 -51
  67. package/source/filter/check_where_clause_on_address_space.ts +29 -0
  68. package/source/filter/extract_event_fields.ts +21 -0
  69. package/source/monitored_item.ts +5 -11
  70. package/source/opcua_server.ts +175 -36
  71. package/source/server_publish_engine.ts +24 -19
  72. package/source/server_subscription.ts +11 -10
@@ -1,740 +1,740 @@
1
- "use strict";
2
- /**
3
- * @module node-opcua-server
4
- */
5
- // tslint:disable:no-console
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.ServerSession = void 0;
8
- const crypto = require("crypto");
9
- const events_1 = require("events");
10
- const node_opcua_address_space_1 = require("node-opcua-address-space");
11
- const node_opcua_assert_1 = require("node-opcua-assert");
12
- const node_opcua_basic_types_1 = require("node-opcua-basic-types");
13
- const node_opcua_common_1 = require("node-opcua-common");
14
- const node_opcua_data_model_1 = require("node-opcua-data-model");
15
- const node_opcua_debug_1 = require("node-opcua-debug");
16
- const node_opcua_nodeid_1 = require("node-opcua-nodeid");
17
- const node_opcua_object_registry_1 = require("node-opcua-object-registry");
18
- const node_opcua_status_code_1 = require("node-opcua-status-code");
19
- const node_opcua_utils_1 = require("node-opcua-utils");
20
- const node_opcua_utils_2 = require("node-opcua-utils");
21
- const server_publish_engine_1 = require("./server_publish_engine");
22
- const server_subscription_1 = require("./server_subscription");
23
- const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
24
- const errorLog = (0, node_opcua_debug_1.make_errorLog)(__filename);
25
- const doDebug = (0, node_opcua_debug_1.checkDebugFlag)(__filename);
26
- const theWatchDog = new node_opcua_utils_1.WatchDog();
27
- const registeredNodeNameSpace = 9999;
28
- function compareSessionId(sessionDiagnostics1, sessionDiagnostics2) {
29
- return sessionDiagnostics1.sessionId.toString() === sessionDiagnostics2.sessionId.toString();
30
- }
31
- function on_channel_abort() {
32
- debugLog("ON CHANNEL ABORT ON SESSION!!!");
33
- /**
34
- * @event channel_aborted
35
- */
36
- this.emit("channel_aborted");
37
- }
38
- /**
39
- *
40
- * A Server session object.
41
- *
42
- * **from OPCUA Spec 1.02:**
43
- *
44
- * * Sessions are created to be independent of the underlying communications connection. Therefore, if a communication
45
- * connection fails, the Session is not immediately affected. The exact mechanism to recover from an underlying
46
- * communication connection error depends on the SecureChannel mapping as described in Part 6.
47
- *
48
- * * Sessions are terminated by the Server automatically if the Client fails to issue a Service request on the Session
49
- * within the timeout period negotiated by the Server in the CreateSession Service response. This protects the Server
50
- * against Client failures and against situations where a failed underlying connection cannot be re-established.
51
- *
52
- * * Clients shall be prepared to submit requests in a timely manner to prevent the Session from closing automatically.
53
- *
54
- * * Clients may explicitly terminate Sessions using the CloseSession Service.
55
- *
56
- * * When a Session is terminated, all outstanding requests on the Session are aborted and BadSessionClosed StatusCodes
57
- * are returned to the Client. In addition, the Server deletes the entry for the Client from its
58
- * SessionDiagnosticsArray Variable and notifies any other Clients who were subscribed to this entry.
59
- *
60
- */
61
- class ServerSession extends events_1.EventEmitter {
62
- constructor(parent, sessionTimeout) {
63
- super();
64
- this.__status = "new";
65
- this.sessionName = "";
66
- this.keepAlive = node_opcua_utils_1.WatchDog.emptyKeepAlive;
67
- this.parent = parent; // SessionEngine
68
- ServerSession.registry.register(this);
69
- (0, node_opcua_assert_1.assert)(isFinite(sessionTimeout));
70
- (0, node_opcua_assert_1.assert)(sessionTimeout >= 0, " sessionTimeout");
71
- this.sessionTimeout = sessionTimeout;
72
- const authenticationTokenBuf = crypto.randomBytes(16);
73
- this.authenticationToken = new node_opcua_nodeid_1.NodeId(node_opcua_nodeid_1.NodeIdType.BYTESTRING, authenticationTokenBuf);
74
- // the sessionId
75
- const ownNamespaceIndex = 1; // addressSpace.getOwnNamespace().index;
76
- this.nodeId = new node_opcua_nodeid_1.NodeId(node_opcua_nodeid_1.NodeIdType.GUID, (0, node_opcua_basic_types_1.randomGuid)(), ownNamespaceIndex);
77
- (0, node_opcua_assert_1.assert)(this.authenticationToken instanceof node_opcua_nodeid_1.NodeId);
78
- (0, node_opcua_assert_1.assert)(this.nodeId instanceof node_opcua_nodeid_1.NodeId);
79
- this._cumulatedSubscriptionCount = 0;
80
- this.publishEngine = new server_publish_engine_1.ServerSidePublishEngine({
81
- maxPublishRequestInQueue: ServerSession.maxPublishRequestInQueue
82
- });
83
- this.publishEngine.setMaxListeners(100);
84
- theWatchDog.addSubscriber(this, this.sessionTimeout);
85
- this.__status = "new";
86
- /**
87
- * the continuation point manager for this session
88
- * @property continuationPointManager
89
- * @type {ContinuationPointManager}
90
- */
91
- this.continuationPointManager = new node_opcua_address_space_1.ContinuationPointManager();
92
- /**
93
- * @property creationDate
94
- * @type {Date}
95
- */
96
- this.creationDate = new Date();
97
- this._registeredNodesCounter = 0;
98
- this._registeredNodes = {};
99
- this._registeredNodesInv = {};
100
- }
101
- getSessionId() {
102
- return this.nodeId;
103
- }
104
- getEndpointDescription() {
105
- return this.endpoint;
106
- }
107
- dispose() {
108
- debugLog("ServerSession#dispose()");
109
- (0, node_opcua_assert_1.assert)(!this.sessionObject, " sessionObject has not been cleared !");
110
- this.parent = null;
111
- this.authenticationToken = new node_opcua_nodeid_1.NodeId();
112
- if (this.publishEngine) {
113
- this.publishEngine.dispose();
114
- this.publishEngine = null;
115
- }
116
- this._sessionDiagnostics = undefined;
117
- this._registeredNodesCounter = 0;
118
- this._registeredNodes = null;
119
- this._registeredNodesInv = null;
120
- this.continuationPointManager = null;
121
- this.removeAllListeners();
122
- this.__status = "disposed";
123
- ServerSession.registry.unregister(this);
124
- }
125
- get clientConnectionTime() {
126
- return this.creationDate;
127
- }
128
- /**
129
- * return the number of milisecond since last session transaction occurs from client
130
- * the first transaction is the creation of the session
131
- */
132
- get clientLastContactTime() {
133
- const lastSeen = this._watchDogData ? this._watchDogData.lastSeen : node_opcua_basic_types_1.minOPCUADate.getTime();
134
- return node_opcua_utils_1.WatchDog.lastSeenToDuration(lastSeen);
135
- }
136
- get status() {
137
- return this.__status;
138
- }
139
- set status(value) {
140
- if (value === "active") {
141
- this._createSessionObjectInAddressSpace();
142
- }
143
- if (this.__status !== value) {
144
- this.emit("statusChanged", value);
145
- }
146
- this.__status = value;
147
- }
148
- get addressSpace() {
149
- if (this.parent && this.parent.addressSpace) {
150
- return this.parent.addressSpace;
151
- }
152
- return null;
153
- }
154
- get currentPublishRequestInQueue() {
155
- return this.publishEngine ? this.publishEngine.pendingPublishRequestCount : 0;
156
- }
157
- updateClientLastContactTime() {
158
- if (this._sessionDiagnostics && this._sessionDiagnostics.clientLastContactTime) {
159
- const currentTime = new Date();
160
- // do not record all ticks as this may be overwhelming,
161
- if (currentTime.getTime() - 250 >= this._sessionDiagnostics.clientLastContactTime.getTime()) {
162
- this._sessionDiagnostics.clientLastContactTime = currentTime;
163
- }
164
- }
165
- }
166
- /**
167
- * @method onClientSeen
168
- * required for watch dog
169
- * @param currentTime {DateTime}
170
- * @private
171
- */
172
- onClientSeen() {
173
- this.updateClientLastContactTime();
174
- if (this._sessionDiagnostics) {
175
- // see https://opcfoundation-onlineapplications.org/mantis/view.php?id=4111
176
- (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, "currentMonitoredItemsCount"));
177
- (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, "currentSubscriptionsCount"));
178
- (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, "currentPublishRequestsInQueue"));
179
- // note : https://opcfoundation-onlineapplications.org/mantis/view.php?id=4111
180
- // sessionDiagnostics extension object uses a different spelling
181
- // here with an S !!!!
182
- if (this._sessionDiagnostics.currentMonitoredItemsCount !== this.currentMonitoredItemCount) {
183
- this._sessionDiagnostics.currentMonitoredItemsCount = this.currentMonitoredItemCount;
184
- }
185
- if (this._sessionDiagnostics.currentSubscriptionsCount !== this.currentSubscriptionCount) {
186
- this._sessionDiagnostics.currentSubscriptionsCount = this.currentSubscriptionCount;
187
- }
188
- if (this._sessionDiagnostics.currentPublishRequestsInQueue !== this.currentPublishRequestInQueue) {
189
- this._sessionDiagnostics.currentPublishRequestsInQueue = this.currentPublishRequestInQueue;
190
- }
191
- }
192
- }
193
- incrementTotalRequestCount() {
194
- if (this._sessionDiagnostics && this._sessionDiagnostics.totalRequestCount) {
195
- this._sessionDiagnostics.totalRequestCount.totalCount += 1;
196
- }
197
- }
198
- incrementRequestTotalCounter(counterName) {
199
- if (this._sessionDiagnostics) {
200
- const propName = (0, node_opcua_utils_2.lowerFirstLetter)(counterName + "Count");
201
- // istanbul ignore next
202
- if (!Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, propName)) {
203
- errorLog("incrementRequestTotalCounter: cannot find", propName);
204
- // xx return;
205
- }
206
- else {
207
- this._sessionDiagnostics[propName].totalCount += 1;
208
- }
209
- }
210
- }
211
- incrementRequestErrorCounter(counterName) {
212
- var _a;
213
- (_a = this.parent) === null || _a === void 0 ? void 0 : _a.incrementRejectedRequestsCount();
214
- if (this._sessionDiagnostics) {
215
- const propName = (0, node_opcua_utils_2.lowerFirstLetter)(counterName + "Count");
216
- // istanbul ignore next
217
- if (!Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, propName)) {
218
- errorLog("incrementRequestErrorCounter: cannot find", propName);
219
- // xx return;
220
- }
221
- else {
222
- this._sessionDiagnostics[propName].errorCount += 1;
223
- }
224
- }
225
- }
226
- /**
227
- * returns rootFolder.objects.server.serverDiagnostics.sessionsDiagnosticsSummary.sessionDiagnosticsArray
228
- */
229
- getSessionDiagnosticsArray() {
230
- const server = this.addressSpace.rootFolder.objects.server;
231
- return server.serverDiagnostics.sessionsDiagnosticsSummary.sessionDiagnosticsArray;
232
- }
233
- /**
234
- * returns rootFolder.objects.server.serverDiagnostics.sessionsDiagnosticsSummary.sessionSecurityDiagnosticsArray
235
- */
236
- getSessionSecurityDiagnosticsArray() {
237
- const server = this.addressSpace.rootFolder.objects.server;
238
- return server.serverDiagnostics.sessionsDiagnosticsSummary.sessionSecurityDiagnosticsArray;
239
- }
240
- /**
241
- * number of active subscriptions
242
- */
243
- get currentSubscriptionCount() {
244
- return this.publishEngine ? this.publishEngine.subscriptionCount : 0;
245
- }
246
- /**
247
- * number of subscriptions ever created since this object is live
248
- */
249
- get cumulatedSubscriptionCount() {
250
- return this._cumulatedSubscriptionCount;
251
- }
252
- /**
253
- * number of monitored items
254
- */
255
- get currentMonitoredItemCount() {
256
- return this.publishEngine ? this.publishEngine.currentMonitoredItemCount : 0;
257
- }
258
- /**
259
- * retrieve an existing subscription by subscriptionId
260
- * @method getSubscription
261
- * @param subscriptionId {Number}
262
- * @return {Subscription}
263
- */
264
- getSubscription(subscriptionId) {
265
- const subscription = this.publishEngine.getSubscriptionById(subscriptionId);
266
- if (subscription && subscription.state === server_subscription_1.SubscriptionState.CLOSED) {
267
- // subscription is CLOSED but has not been notified yet
268
- // it should be considered as excluded
269
- return null;
270
- }
271
- (0, node_opcua_assert_1.assert)(!subscription || subscription.state !== server_subscription_1.SubscriptionState.CLOSED, "CLOSED subscription shall not be managed by publish engine anymore");
272
- return subscription;
273
- }
274
- /**
275
- * @method deleteSubscription
276
- * @param subscriptionId {Number}
277
- * @return {StatusCode}
278
- */
279
- deleteSubscription(subscriptionId) {
280
- const subscription = this.getSubscription(subscriptionId);
281
- if (!subscription) {
282
- return node_opcua_status_code_1.StatusCodes.BadSubscriptionIdInvalid;
283
- }
284
- // xx this.publishEngine.remove_subscription(subscription);
285
- subscription.terminate();
286
- if (this.currentSubscriptionCount === 0) {
287
- const local_publishEngine = this.publishEngine;
288
- local_publishEngine.cancelPendingPublishRequest();
289
- }
290
- return node_opcua_status_code_1.StatusCodes.Good;
291
- }
292
- /**
293
- * close a ServerSession, this will also delete the subscriptions if the flag is set.
294
- *
295
- * Spec extract:
296
- *
297
- * If a Client invokes the CloseSession Service then all Subscriptions associated with the Session are also deleted
298
- * if the deleteSubscriptions flag is set to TRUE. If a Server terminates a Session for any other reason,
299
- * Subscriptions associated with the Session, are not deleted. Each Subscription has its own lifetime to protect
300
- * against data loss in the case of a Session termination. In these cases, the Subscription can be reassigned to
301
- * another Client before its lifetime expires.
302
- *
303
- * @method close
304
- * @param deleteSubscriptions : should we delete subscription ?
305
- * @param [reason = "CloseSession"] the reason for closing the session
306
- * (shall be "Timeout", "Terminated" or "CloseSession")
307
- *
308
- */
309
- close(deleteSubscriptions, reason) {
310
- debugLog(" closing session deleteSubscriptions = ", deleteSubscriptions);
311
- if (this.publishEngine) {
312
- this.publishEngine.onSessionClose();
313
- }
314
- theWatchDog.removeSubscriber(this);
315
- // --------------- delete associated subscriptions ---------------------
316
- if (!deleteSubscriptions && this.currentSubscriptionCount !== 0) {
317
- // I don't know what to do yet if deleteSubscriptions is false
318
- errorLog("TO DO : Closing session without deleting subscription not yet implemented");
319
- // to do: Put subscriptions in safe place for future transfer if any
320
- }
321
- this._deleteSubscriptions();
322
- (0, node_opcua_assert_1.assert)(this.currentSubscriptionCount === 0);
323
- // Post-Conditions
324
- (0, node_opcua_assert_1.assert)(this.currentSubscriptionCount === 0);
325
- this.status = "closed";
326
- this._detach_channel();
327
- /**
328
- * @event session_closed
329
- * @param deleteSubscriptions {Boolean}
330
- * @param reason {String}
331
- */
332
- this.emit("session_closed", this, deleteSubscriptions, reason);
333
- // ---------------- shut down publish engine
334
- if (this.publishEngine) {
335
- // remove subscription
336
- this.publishEngine.shutdown();
337
- (0, node_opcua_assert_1.assert)(this.publishEngine.subscriptionCount === 0);
338
- this.publishEngine.dispose();
339
- this.publishEngine = null;
340
- }
341
- this._removeSessionObjectFromAddressSpace();
342
- (0, node_opcua_assert_1.assert)(!this.sessionDiagnostics, "ServerSession#_removeSessionObjectFromAddressSpace must be called");
343
- (0, node_opcua_assert_1.assert)(!this.sessionObject, "ServerSession#_removeSessionObjectFromAddressSpace must be called");
344
- }
345
- registerNode(nodeId) {
346
- (0, node_opcua_assert_1.assert)(nodeId instanceof node_opcua_nodeid_1.NodeId);
347
- if (nodeId.namespace === 0 && nodeId.identifierType === node_opcua_nodeid_1.NodeIdType.NUMERIC) {
348
- return nodeId;
349
- }
350
- const key = nodeId.toString();
351
- const registeredNode = this._registeredNodes[key];
352
- if (registeredNode) {
353
- // already registered
354
- return registeredNode;
355
- }
356
- const node = this.addressSpace.findNode(nodeId);
357
- if (!node) {
358
- return nodeId;
359
- }
360
- this._registeredNodesCounter += 1;
361
- const aliasNodeId = (0, node_opcua_nodeid_1.makeNodeId)(this._registeredNodesCounter, registeredNodeNameSpace);
362
- this._registeredNodes[key] = aliasNodeId;
363
- this._registeredNodesInv[aliasNodeId.toString()] = node;
364
- return aliasNodeId;
365
- }
366
- unRegisterNode(aliasNodeId) {
367
- (0, node_opcua_assert_1.assert)(aliasNodeId instanceof node_opcua_nodeid_1.NodeId);
368
- if (aliasNodeId.namespace !== registeredNodeNameSpace) {
369
- return; // not a registered Node
370
- }
371
- const node = this._registeredNodesInv[aliasNodeId.toString()];
372
- if (!node) {
373
- return;
374
- }
375
- this._registeredNodesInv[aliasNodeId.toString()] = null;
376
- this._registeredNodes[node.nodeId.toString()] = null;
377
- }
378
- resolveRegisteredNode(aliasNodeId) {
379
- if (aliasNodeId.namespace !== registeredNodeNameSpace) {
380
- return aliasNodeId; // not a registered Node
381
- }
382
- const node = this._registeredNodesInv[aliasNodeId.toString()];
383
- if (!node) {
384
- return aliasNodeId;
385
- }
386
- return node.nodeId;
387
- }
388
- /**
389
- * true if the underlying channel has been closed or aborted...
390
- */
391
- get aborted() {
392
- if (!this.channel) {
393
- return true;
394
- }
395
- return this.channel.aborted;
396
- }
397
- createSubscription(parameters) {
398
- const subscription = this.parent._createSubscriptionOnSession(this, parameters);
399
- (0, node_opcua_assert_1.assert)(!Object.prototype.hasOwnProperty.call(parameters, "id"));
400
- this.assignSubscription(subscription);
401
- (0, node_opcua_assert_1.assert)(subscription.$session === this);
402
- (0, node_opcua_assert_1.assert)(subscription.sessionId instanceof node_opcua_nodeid_1.NodeId);
403
- (0, node_opcua_assert_1.assert)((0, node_opcua_nodeid_1.sameNodeId)(subscription.sessionId, this.nodeId));
404
- return subscription;
405
- }
406
- _attach_channel(channel) {
407
- (0, node_opcua_assert_1.assert)(this.nonce && this.nonce instanceof Buffer);
408
- this.channel = channel;
409
- this.channelId = channel.channelId;
410
- const key = this.authenticationToken.toString();
411
- (0, node_opcua_assert_1.assert)(!Object.prototype.hasOwnProperty.call(channel.sessionTokens, key), "channel has already a session");
412
- channel.sessionTokens[key] = this;
413
- // when channel is aborting
414
- this.channel_abort_event_handler = on_channel_abort.bind(this);
415
- channel.on("abort", this.channel_abort_event_handler);
416
- }
417
- _detach_channel() {
418
- const channel = this.channel;
419
- // istanbul ignore next
420
- if (!channel) {
421
- return;
422
- // already detached !
423
- // throw new Error("expecting a valid channel");
424
- }
425
- (0, node_opcua_assert_1.assert)(this.nonce && this.nonce instanceof Buffer);
426
- (0, node_opcua_assert_1.assert)(this.authenticationToken);
427
- const key = this.authenticationToken.toString();
428
- (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(channel.sessionTokens, key));
429
- (0, node_opcua_assert_1.assert)(this.channel);
430
- (0, node_opcua_assert_1.assert)(typeof this.channel_abort_event_handler === "function");
431
- channel.removeListener("abort", this.channel_abort_event_handler);
432
- delete channel.sessionTokens[key];
433
- this.channel = undefined;
434
- this.channelId = undefined;
435
- }
436
- _exposeSubscriptionDiagnostics(subscription) {
437
- debugLog("ServerSession#_exposeSubscriptionDiagnostics");
438
- (0, node_opcua_assert_1.assert)(subscription.$session === this);
439
- const subscriptionDiagnosticsArray = this._getSubscriptionDiagnosticsArray();
440
- const subscriptionDiagnostics = subscription.subscriptionDiagnostics;
441
- (0, node_opcua_assert_1.assert)(subscriptionDiagnostics.$subscription === subscription);
442
- if (subscriptionDiagnostics && subscriptionDiagnosticsArray) {
443
- // subscription.id,"on session", session.nodeId.toString());
444
- (0, node_opcua_address_space_1.addElement)(subscriptionDiagnostics, subscriptionDiagnosticsArray);
445
- }
446
- }
447
- _unexposeSubscriptionDiagnostics(subscription) {
448
- const subscriptionDiagnosticsArray = this._getSubscriptionDiagnosticsArray();
449
- const subscriptionDiagnostics = subscription.subscriptionDiagnostics;
450
- (0, node_opcua_assert_1.assert)(subscriptionDiagnostics instanceof node_opcua_common_1.SubscriptionDiagnosticsDataType);
451
- if (subscriptionDiagnostics && subscriptionDiagnosticsArray) {
452
- // subscription.id,"on session", session.nodeId.toString());
453
- (0, node_opcua_address_space_1.removeElement)(subscriptionDiagnosticsArray, subscriptionDiagnostics);
454
- }
455
- debugLog("ServerSession#_unexposeSubscriptionDiagnostics");
456
- }
457
- /**
458
- * @method watchdogReset
459
- * used as a callback for the Watchdog
460
- * @private
461
- */
462
- watchdogReset() {
463
- debugLog("Session#watchdogReset: the server session has expired and must be removed from the server");
464
- // the server session has expired and must be removed from the server
465
- this.emit("timeout");
466
- }
467
- _createSessionObjectInAddressSpace() {
468
- if (this.sessionObject) {
469
- return;
470
- }
471
- (0, node_opcua_assert_1.assert)(!this.sessionObject, "ServerSession#_createSessionObjectInAddressSpace already called ?");
472
- this.sessionObject = null;
473
- if (!this.addressSpace) {
474
- debugLog("ServerSession#_createSessionObjectInAddressSpace : no addressSpace");
475
- return; // no addressSpace
476
- }
477
- const root = this.addressSpace.rootFolder;
478
- (0, node_opcua_assert_1.assert)(root, "expecting a root object");
479
- if (!root.objects) {
480
- debugLog("ServerSession#_createSessionObjectInAddressSpace : no object folder");
481
- return false;
482
- }
483
- if (!root.objects.server) {
484
- debugLog("ServerSession#_createSessionObjectInAddressSpace : no server object");
485
- return false;
486
- }
487
- // self.addressSpace.findNode(makeNodeId(ObjectIds.Server_ServerDiagnostics));
488
- const serverDiagnosticsNode = root.objects.server.serverDiagnostics;
489
- if (!serverDiagnosticsNode || !serverDiagnosticsNode.sessionsDiagnosticsSummary) {
490
- debugLog("ServerSession#_createSessionObjectInAddressSpace :" + " no serverDiagnostics.sessionsDiagnosticsSummary");
491
- return false;
492
- }
493
- const sessionDiagnosticsObjectType = this.addressSpace.findObjectType("SessionDiagnosticsObjectType");
494
- const sessionDiagnosticsDataType = this.addressSpace.findDataType("SessionDiagnosticsDataType");
495
- const sessionDiagnosticsVariableType = this.addressSpace.findVariableType("SessionDiagnosticsVariableType");
496
- const sessionSecurityDiagnosticsDataType = this.addressSpace.findDataType("SessionSecurityDiagnosticsDataType");
497
- const sessionSecurityDiagnosticsType = this.addressSpace.findVariableType("SessionSecurityDiagnosticsType");
498
- const namespace = this.addressSpace.getOwnNamespace();
499
- function createSessionDiagnosticsStuff() {
500
- if (sessionDiagnosticsDataType && sessionDiagnosticsVariableType) {
501
- // the extension object
502
- this._sessionDiagnostics = this.addressSpace.constructExtensionObject(sessionDiagnosticsDataType, {});
503
- this._sessionDiagnostics.$session = this;
504
- // install property getter on property that are unlikely to change
505
- if (this.parent.clientDescription) {
506
- this._sessionDiagnostics.clientDescription = this.parent.clientDescription;
507
- }
508
- Object.defineProperty(this._sessionDiagnostics, "clientConnectionTime", {
509
- get() {
510
- return this.$session.clientConnectionTime;
511
- }
512
- });
513
- Object.defineProperty(this._sessionDiagnostics, "actualSessionTimeout", {
514
- get() {
515
- var _a;
516
- return (_a = this.$session) === null || _a === void 0 ? void 0 : _a.sessionTimeout;
517
- }
518
- });
519
- Object.defineProperty(this._sessionDiagnostics, "sessionId", {
520
- get() {
521
- return this.$session ? this.$session.nodeId : node_opcua_nodeid_1.NodeId.nullNodeId;
522
- }
523
- });
524
- Object.defineProperty(this._sessionDiagnostics, "sessionName", {
525
- get() {
526
- return this.$session ? this.$session.sessionName.toString() : "";
527
- }
528
- });
529
- this.sessionDiagnostics = sessionDiagnosticsVariableType.instantiate({
530
- browseName: new node_opcua_data_model_1.QualifiedName({ name: "SessionDiagnostics", namespaceIndex: 0 }),
531
- componentOf: this.sessionObject,
532
- extensionObject: this._sessionDiagnostics,
533
- minimumSamplingInterval: 2000 // 2 seconds
534
- });
535
- this._sessionDiagnostics = this.sessionDiagnostics.$extensionObject;
536
- (0, node_opcua_assert_1.assert)(this._sessionDiagnostics.$session === this);
537
- const sessionDiagnosticsArray = this.getSessionDiagnosticsArray();
538
- // add sessionDiagnostics into sessionDiagnosticsArray
539
- (0, node_opcua_address_space_1.addElement)(this._sessionDiagnostics, sessionDiagnosticsArray);
540
- }
541
- }
542
- function createSessionSecurityDiagnosticsStuff() {
543
- if (sessionSecurityDiagnosticsDataType && sessionSecurityDiagnosticsType) {
544
- // the extension object
545
- this._sessionSecurityDiagnostics = this.addressSpace.constructExtensionObject(sessionSecurityDiagnosticsDataType, {});
546
- this._sessionSecurityDiagnostics.$session = this;
547
- /*
548
- sessionId: NodeId;
549
- clientUserIdOfSession: UAString;
550
- clientUserIdHistory: UAString[] | null;
551
- authenticationMechanism: UAString;
552
- encoding: UAString;
553
- transportProtocol: UAString;
554
- securityMode: MessageSecurityMode;
555
- securityPolicyUri: UAString;
556
- clientCertificate: ByteString;
557
- */
558
- Object.defineProperty(this._sessionSecurityDiagnostics, "sessionId", {
559
- get() {
560
- var _a;
561
- return (_a = this.$session) === null || _a === void 0 ? void 0 : _a.nodeId;
562
- }
563
- });
564
- Object.defineProperty(this._sessionSecurityDiagnostics, "clientUserIdOfSession", {
565
- get() {
566
- return ""; // UAString // TO DO : implement
567
- }
568
- });
569
- Object.defineProperty(this._sessionSecurityDiagnostics, "clientUserIdHistory", {
570
- get() {
571
- return []; // UAString[] | null
572
- }
573
- });
574
- Object.defineProperty(this._sessionSecurityDiagnostics, "authenticationMechanism", {
575
- get() {
576
- return "";
577
- }
578
- });
579
- Object.defineProperty(this._sessionSecurityDiagnostics, "encoding", {
580
- get() {
581
- return "";
582
- }
583
- });
584
- Object.defineProperty(this._sessionSecurityDiagnostics, "transportProtocol", {
585
- get() {
586
- return "opc.tcp";
587
- }
588
- });
589
- Object.defineProperty(this._sessionSecurityDiagnostics, "securityMode", {
590
- get() {
591
- var _a;
592
- const session = this.$session;
593
- return (_a = session === null || session === void 0 ? void 0 : session.channel) === null || _a === void 0 ? void 0 : _a.securityMode;
594
- }
595
- });
596
- Object.defineProperty(this._sessionSecurityDiagnostics, "securityPolicyUri", {
597
- get() {
598
- var _a;
599
- const session = this.$session;
600
- return (_a = session === null || session === void 0 ? void 0 : session.channel) === null || _a === void 0 ? void 0 : _a.securityPolicy;
601
- }
602
- });
603
- Object.defineProperty(this._sessionSecurityDiagnostics, "clientCertificate", {
604
- get() {
605
- const session = this.$session;
606
- return session === null || session === void 0 ? void 0 : session.channel.clientCertificate;
607
- }
608
- });
609
- this.sessionSecurityDiagnostics = sessionSecurityDiagnosticsType.instantiate({
610
- browseName: new node_opcua_data_model_1.QualifiedName({ name: "SessionSecurityDiagnostics", namespaceIndex: 0 }),
611
- componentOf: this.sessionObject,
612
- extensionObject: this._sessionSecurityDiagnostics,
613
- minimumSamplingInterval: 2000 // 2 seconds
614
- });
615
- (0, node_opcua_address_space_1.ensureObjectIsSecure)(this.sessionSecurityDiagnostics);
616
- this._sessionSecurityDiagnostics = this.sessionSecurityDiagnostics
617
- .$extensionObject;
618
- (0, node_opcua_assert_1.assert)(this._sessionSecurityDiagnostics.$session === this);
619
- const sessionSecurityDiagnosticsArray = this.getSessionSecurityDiagnosticsArray();
620
- // add sessionDiagnostics into sessionDiagnosticsArray
621
- const node = (0, node_opcua_address_space_1.addElement)(this._sessionSecurityDiagnostics, sessionSecurityDiagnosticsArray);
622
- (0, node_opcua_address_space_1.ensureObjectIsSecure)(node);
623
- }
624
- }
625
- function createSessionDiagnosticSummaryUAObject() {
626
- const references = [];
627
- if (sessionDiagnosticsObjectType) {
628
- references.push({
629
- isForward: true,
630
- nodeId: sessionDiagnosticsObjectType,
631
- referenceType: "HasTypeDefinition"
632
- });
633
- }
634
- this.sessionObject = namespace.createNode({
635
- browseName: this.sessionName || "Session-" + this.nodeId.toString(),
636
- componentOf: serverDiagnosticsNode.sessionsDiagnosticsSummary,
637
- nodeClass: node_opcua_data_model_1.NodeClass.Object,
638
- nodeId: this.nodeId,
639
- references,
640
- typeDefinition: sessionDiagnosticsObjectType
641
- });
642
- createSessionDiagnosticsStuff.call(this);
643
- createSessionSecurityDiagnosticsStuff.call(this);
644
- }
645
- function createSubscriptionDiagnosticsArray() {
646
- const subscriptionDiagnosticsArrayType = this.addressSpace.findVariableType("SubscriptionDiagnosticsArrayType");
647
- (0, node_opcua_assert_1.assert)(subscriptionDiagnosticsArrayType.nodeId.toString() === "ns=0;i=2171");
648
- this.subscriptionDiagnosticsArray = (0, node_opcua_address_space_1.createExtObjArrayNode)(this.sessionObject, {
649
- browseName: { namespaceIndex: 0, name: "SubscriptionDiagnosticsArray" },
650
- complexVariableType: "SubscriptionDiagnosticsArrayType",
651
- indexPropertyName: "subscriptionId",
652
- minimumSamplingInterval: 2000,
653
- variableType: "SubscriptionDiagnosticsType"
654
- });
655
- }
656
- createSessionDiagnosticSummaryUAObject.call(this);
657
- createSubscriptionDiagnosticsArray.call(this);
658
- return this.sessionObject;
659
- }
660
- /**
661
- *
662
- * @private
663
- */
664
- _removeSessionObjectFromAddressSpace() {
665
- // todo : dump session statistics in a file or somewhere for deeper diagnostic analysis on closed session
666
- if (!this.addressSpace) {
667
- return;
668
- }
669
- if (this.sessionDiagnostics) {
670
- const sessionDiagnosticsArray = this.getSessionDiagnosticsArray();
671
- (0, node_opcua_address_space_1.removeElement)(sessionDiagnosticsArray, this.sessionDiagnostics.$extensionObject);
672
- this.addressSpace.deleteNode(this.sessionDiagnostics);
673
- (0, node_opcua_assert_1.assert)(this._sessionDiagnostics.$session === this);
674
- this._sessionDiagnostics.$session = null;
675
- this._sessionDiagnostics = undefined;
676
- this.sessionDiagnostics = undefined;
677
- }
678
- if (this.sessionSecurityDiagnostics) {
679
- const sessionSecurityDiagnosticsArray = this.getSessionSecurityDiagnosticsArray();
680
- (0, node_opcua_address_space_1.removeElement)(sessionSecurityDiagnosticsArray, this.sessionSecurityDiagnostics.$extensionObject);
681
- this.addressSpace.deleteNode(this.sessionSecurityDiagnostics);
682
- (0, node_opcua_assert_1.assert)(this._sessionSecurityDiagnostics.$session === this);
683
- this._sessionSecurityDiagnostics.$session = null;
684
- this._sessionSecurityDiagnostics = undefined;
685
- this.sessionSecurityDiagnostics = undefined;
686
- }
687
- if (this.sessionObject) {
688
- this.addressSpace.deleteNode(this.sessionObject);
689
- this.sessionObject = null;
690
- }
691
- }
692
- /**
693
- *
694
- * @private
695
- */
696
- _getSubscriptionDiagnosticsArray() {
697
- if (!this.addressSpace) {
698
- if (doDebug) {
699
- console.warn("ServerSession#_getSubscriptionDiagnosticsArray : no addressSpace");
700
- }
701
- return null; // no addressSpace
702
- }
703
- const subscriptionDiagnosticsArray = this.subscriptionDiagnosticsArray;
704
- if (!subscriptionDiagnosticsArray) {
705
- return null; // no subscriptionDiagnosticsArray
706
- }
707
- (0, node_opcua_assert_1.assert)(subscriptionDiagnosticsArray.browseName.toString() === "SubscriptionDiagnosticsArray");
708
- return subscriptionDiagnosticsArray;
709
- }
710
- assignSubscription(subscription) {
711
- (0, node_opcua_assert_1.assert)(!subscription.$session);
712
- (0, node_opcua_assert_1.assert)(this.nodeId instanceof node_opcua_nodeid_1.NodeId);
713
- subscription.$session = this;
714
- (0, node_opcua_assert_1.assert)(subscription.sessionId === this.nodeId);
715
- this._cumulatedSubscriptionCount += 1;
716
- // Notify the owner that a new subscription has been created
717
- // @event new_subscription
718
- // @param {Subscription} subscription
719
- this.emit("new_subscription", subscription);
720
- // add subscription diagnostics to SubscriptionDiagnosticsArray
721
- this._exposeSubscriptionDiagnostics(subscription);
722
- subscription.once("terminated", () => {
723
- // Notify the owner that a new subscription has been terminated
724
- // @event subscription_terminated
725
- // @param {Subscription} subscription
726
- this.emit("subscription_terminated", subscription);
727
- });
728
- }
729
- _deleteSubscriptions() {
730
- (0, node_opcua_assert_1.assert)(this.publishEngine);
731
- const subscriptions = this.publishEngine.subscriptions;
732
- for (const subscription of subscriptions) {
733
- this.deleteSubscription(subscription.id);
734
- }
735
- }
736
- }
737
- exports.ServerSession = ServerSession;
738
- ServerSession.registry = new node_opcua_object_registry_1.ObjectRegistry();
739
- ServerSession.maxPublishRequestInQueue = 100;
1
+ "use strict";
2
+ /**
3
+ * @module node-opcua-server
4
+ */
5
+ // tslint:disable:no-console
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ServerSession = void 0;
8
+ const crypto = require("crypto");
9
+ const events_1 = require("events");
10
+ const node_opcua_address_space_1 = require("node-opcua-address-space");
11
+ const node_opcua_assert_1 = require("node-opcua-assert");
12
+ const node_opcua_basic_types_1 = require("node-opcua-basic-types");
13
+ const node_opcua_common_1 = require("node-opcua-common");
14
+ const node_opcua_data_model_1 = require("node-opcua-data-model");
15
+ const node_opcua_debug_1 = require("node-opcua-debug");
16
+ const node_opcua_nodeid_1 = require("node-opcua-nodeid");
17
+ const node_opcua_object_registry_1 = require("node-opcua-object-registry");
18
+ const node_opcua_status_code_1 = require("node-opcua-status-code");
19
+ const node_opcua_utils_1 = require("node-opcua-utils");
20
+ const node_opcua_utils_2 = require("node-opcua-utils");
21
+ const server_publish_engine_1 = require("./server_publish_engine");
22
+ const server_subscription_1 = require("./server_subscription");
23
+ const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
24
+ const errorLog = (0, node_opcua_debug_1.make_errorLog)(__filename);
25
+ const doDebug = (0, node_opcua_debug_1.checkDebugFlag)(__filename);
26
+ const theWatchDog = new node_opcua_utils_1.WatchDog();
27
+ const registeredNodeNameSpace = 9999;
28
+ function compareSessionId(sessionDiagnostics1, sessionDiagnostics2) {
29
+ return sessionDiagnostics1.sessionId.toString() === sessionDiagnostics2.sessionId.toString();
30
+ }
31
+ function on_channel_abort() {
32
+ debugLog("ON CHANNEL ABORT ON SESSION!!!");
33
+ /**
34
+ * @event channel_aborted
35
+ */
36
+ this.emit("channel_aborted");
37
+ }
38
+ /**
39
+ *
40
+ * A Server session object.
41
+ *
42
+ * **from OPCUA Spec 1.02:**
43
+ *
44
+ * * Sessions are created to be independent of the underlying communications connection. Therefore, if a communication
45
+ * connection fails, the Session is not immediately affected. The exact mechanism to recover from an underlying
46
+ * communication connection error depends on the SecureChannel mapping as described in Part 6.
47
+ *
48
+ * * Sessions are terminated by the Server automatically if the Client fails to issue a Service request on the Session
49
+ * within the timeout period negotiated by the Server in the CreateSession Service response. This protects the Server
50
+ * against Client failures and against situations where a failed underlying connection cannot be re-established.
51
+ *
52
+ * * Clients shall be prepared to submit requests in a timely manner to prevent the Session from closing automatically.
53
+ *
54
+ * * Clients may explicitly terminate Sessions using the CloseSession Service.
55
+ *
56
+ * * When a Session is terminated, all outstanding requests on the Session are aborted and BadSessionClosed StatusCodes
57
+ * are returned to the Client. In addition, the Server deletes the entry for the Client from its
58
+ * SessionDiagnosticsArray Variable and notifies any other Clients who were subscribed to this entry.
59
+ *
60
+ */
61
+ class ServerSession extends events_1.EventEmitter {
62
+ constructor(parent, sessionTimeout) {
63
+ super();
64
+ this.__status = "new";
65
+ this.sessionName = "";
66
+ this.keepAlive = node_opcua_utils_1.WatchDog.emptyKeepAlive;
67
+ this.parent = parent; // SessionEngine
68
+ ServerSession.registry.register(this);
69
+ (0, node_opcua_assert_1.assert)(isFinite(sessionTimeout));
70
+ (0, node_opcua_assert_1.assert)(sessionTimeout >= 0, " sessionTimeout");
71
+ this.sessionTimeout = sessionTimeout;
72
+ const authenticationTokenBuf = crypto.randomBytes(16);
73
+ this.authenticationToken = new node_opcua_nodeid_1.NodeId(node_opcua_nodeid_1.NodeIdType.BYTESTRING, authenticationTokenBuf);
74
+ // the sessionId
75
+ const ownNamespaceIndex = 1; // addressSpace.getOwnNamespace().index;
76
+ this.nodeId = new node_opcua_nodeid_1.NodeId(node_opcua_nodeid_1.NodeIdType.GUID, (0, node_opcua_basic_types_1.randomGuid)(), ownNamespaceIndex);
77
+ (0, node_opcua_assert_1.assert)(this.authenticationToken instanceof node_opcua_nodeid_1.NodeId);
78
+ (0, node_opcua_assert_1.assert)(this.nodeId instanceof node_opcua_nodeid_1.NodeId);
79
+ this._cumulatedSubscriptionCount = 0;
80
+ this.publishEngine = new server_publish_engine_1.ServerSidePublishEngine({
81
+ maxPublishRequestInQueue: ServerSession.maxPublishRequestInQueue
82
+ });
83
+ this.publishEngine.setMaxListeners(100);
84
+ theWatchDog.addSubscriber(this, this.sessionTimeout);
85
+ this.__status = "new";
86
+ /**
87
+ * the continuation point manager for this session
88
+ * @property continuationPointManager
89
+ * @type {ContinuationPointManager}
90
+ */
91
+ this.continuationPointManager = new node_opcua_address_space_1.ContinuationPointManager();
92
+ /**
93
+ * @property creationDate
94
+ * @type {Date}
95
+ */
96
+ this.creationDate = new Date();
97
+ this._registeredNodesCounter = 0;
98
+ this._registeredNodes = {};
99
+ this._registeredNodesInv = {};
100
+ }
101
+ getSessionId() {
102
+ return this.nodeId;
103
+ }
104
+ getEndpointDescription() {
105
+ return this.endpoint;
106
+ }
107
+ dispose() {
108
+ debugLog("ServerSession#dispose()");
109
+ (0, node_opcua_assert_1.assert)(!this.sessionObject, " sessionObject has not been cleared !");
110
+ this.parent = null;
111
+ this.authenticationToken = new node_opcua_nodeid_1.NodeId();
112
+ if (this.publishEngine) {
113
+ this.publishEngine.dispose();
114
+ this.publishEngine = null;
115
+ }
116
+ this._sessionDiagnostics = undefined;
117
+ this._registeredNodesCounter = 0;
118
+ this._registeredNodes = null;
119
+ this._registeredNodesInv = null;
120
+ this.continuationPointManager = null;
121
+ this.removeAllListeners();
122
+ this.__status = "disposed";
123
+ ServerSession.registry.unregister(this);
124
+ }
125
+ get clientConnectionTime() {
126
+ return this.creationDate;
127
+ }
128
+ /**
129
+ * return the number of milisecond since last session transaction occurs from client
130
+ * the first transaction is the creation of the session
131
+ */
132
+ get clientLastContactTime() {
133
+ const lastSeen = this._watchDogData ? this._watchDogData.lastSeen : node_opcua_basic_types_1.minOPCUADate.getTime();
134
+ return node_opcua_utils_1.WatchDog.lastSeenToDuration(lastSeen);
135
+ }
136
+ get status() {
137
+ return this.__status;
138
+ }
139
+ set status(value) {
140
+ if (value === "active") {
141
+ this._createSessionObjectInAddressSpace();
142
+ }
143
+ if (this.__status !== value) {
144
+ this.emit("statusChanged", value);
145
+ }
146
+ this.__status = value;
147
+ }
148
+ get addressSpace() {
149
+ if (this.parent && this.parent.addressSpace) {
150
+ return this.parent.addressSpace;
151
+ }
152
+ return null;
153
+ }
154
+ get currentPublishRequestInQueue() {
155
+ return this.publishEngine ? this.publishEngine.pendingPublishRequestCount : 0;
156
+ }
157
+ updateClientLastContactTime() {
158
+ if (this._sessionDiagnostics && this._sessionDiagnostics.clientLastContactTime) {
159
+ const currentTime = new Date();
160
+ // do not record all ticks as this may be overwhelming,
161
+ if (currentTime.getTime() - 250 >= this._sessionDiagnostics.clientLastContactTime.getTime()) {
162
+ this._sessionDiagnostics.clientLastContactTime = currentTime;
163
+ }
164
+ }
165
+ }
166
+ /**
167
+ * @method onClientSeen
168
+ * required for watch dog
169
+ * @param currentTime {DateTime}
170
+ * @private
171
+ */
172
+ onClientSeen() {
173
+ this.updateClientLastContactTime();
174
+ if (this._sessionDiagnostics) {
175
+ // see https://opcfoundation-onlineapplications.org/mantis/view.php?id=4111
176
+ (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, "currentMonitoredItemsCount"));
177
+ (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, "currentSubscriptionsCount"));
178
+ (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, "currentPublishRequestsInQueue"));
179
+ // note : https://opcfoundation-onlineapplications.org/mantis/view.php?id=4111
180
+ // sessionDiagnostics extension object uses a different spelling
181
+ // here with an S !!!!
182
+ if (this._sessionDiagnostics.currentMonitoredItemsCount !== this.currentMonitoredItemCount) {
183
+ this._sessionDiagnostics.currentMonitoredItemsCount = this.currentMonitoredItemCount;
184
+ }
185
+ if (this._sessionDiagnostics.currentSubscriptionsCount !== this.currentSubscriptionCount) {
186
+ this._sessionDiagnostics.currentSubscriptionsCount = this.currentSubscriptionCount;
187
+ }
188
+ if (this._sessionDiagnostics.currentPublishRequestsInQueue !== this.currentPublishRequestInQueue) {
189
+ this._sessionDiagnostics.currentPublishRequestsInQueue = this.currentPublishRequestInQueue;
190
+ }
191
+ }
192
+ }
193
+ incrementTotalRequestCount() {
194
+ if (this._sessionDiagnostics && this._sessionDiagnostics.totalRequestCount) {
195
+ this._sessionDiagnostics.totalRequestCount.totalCount += 1;
196
+ }
197
+ }
198
+ incrementRequestTotalCounter(counterName) {
199
+ if (this._sessionDiagnostics) {
200
+ const propName = (0, node_opcua_utils_2.lowerFirstLetter)(counterName + "Count");
201
+ // istanbul ignore next
202
+ if (!Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, propName)) {
203
+ errorLog("incrementRequestTotalCounter: cannot find", propName);
204
+ // xx return;
205
+ }
206
+ else {
207
+ this._sessionDiagnostics[propName].totalCount += 1;
208
+ }
209
+ }
210
+ }
211
+ incrementRequestErrorCounter(counterName) {
212
+ var _a;
213
+ (_a = this.parent) === null || _a === void 0 ? void 0 : _a.incrementRejectedRequestsCount();
214
+ if (this._sessionDiagnostics) {
215
+ const propName = (0, node_opcua_utils_2.lowerFirstLetter)(counterName + "Count");
216
+ // istanbul ignore next
217
+ if (!Object.prototype.hasOwnProperty.call(this._sessionDiagnostics, propName)) {
218
+ errorLog("incrementRequestErrorCounter: cannot find", propName);
219
+ // xx return;
220
+ }
221
+ else {
222
+ this._sessionDiagnostics[propName].errorCount += 1;
223
+ }
224
+ }
225
+ }
226
+ /**
227
+ * returns rootFolder.objects.server.serverDiagnostics.sessionsDiagnosticsSummary.sessionDiagnosticsArray
228
+ */
229
+ getSessionDiagnosticsArray() {
230
+ const server = this.addressSpace.rootFolder.objects.server;
231
+ return server.serverDiagnostics.sessionsDiagnosticsSummary.sessionDiagnosticsArray;
232
+ }
233
+ /**
234
+ * returns rootFolder.objects.server.serverDiagnostics.sessionsDiagnosticsSummary.sessionSecurityDiagnosticsArray
235
+ */
236
+ getSessionSecurityDiagnosticsArray() {
237
+ const server = this.addressSpace.rootFolder.objects.server;
238
+ return server.serverDiagnostics.sessionsDiagnosticsSummary.sessionSecurityDiagnosticsArray;
239
+ }
240
+ /**
241
+ * number of active subscriptions
242
+ */
243
+ get currentSubscriptionCount() {
244
+ return this.publishEngine ? this.publishEngine.subscriptionCount : 0;
245
+ }
246
+ /**
247
+ * number of subscriptions ever created since this object is live
248
+ */
249
+ get cumulatedSubscriptionCount() {
250
+ return this._cumulatedSubscriptionCount;
251
+ }
252
+ /**
253
+ * number of monitored items
254
+ */
255
+ get currentMonitoredItemCount() {
256
+ return this.publishEngine ? this.publishEngine.currentMonitoredItemCount : 0;
257
+ }
258
+ /**
259
+ * retrieve an existing subscription by subscriptionId
260
+ * @method getSubscription
261
+ * @param subscriptionId {Number}
262
+ * @return {Subscription}
263
+ */
264
+ getSubscription(subscriptionId) {
265
+ const subscription = this.publishEngine.getSubscriptionById(subscriptionId);
266
+ if (subscription && subscription.state === server_subscription_1.SubscriptionState.CLOSED) {
267
+ // subscription is CLOSED but has not been notified yet
268
+ // it should be considered as excluded
269
+ return null;
270
+ }
271
+ (0, node_opcua_assert_1.assert)(!subscription || subscription.state !== server_subscription_1.SubscriptionState.CLOSED, "CLOSED subscription shall not be managed by publish engine anymore");
272
+ return subscription;
273
+ }
274
+ /**
275
+ * @method deleteSubscription
276
+ * @param subscriptionId {Number}
277
+ * @return {StatusCode}
278
+ */
279
+ deleteSubscription(subscriptionId) {
280
+ const subscription = this.getSubscription(subscriptionId);
281
+ if (!subscription) {
282
+ return node_opcua_status_code_1.StatusCodes.BadSubscriptionIdInvalid;
283
+ }
284
+ // xx this.publishEngine.remove_subscription(subscription);
285
+ subscription.terminate();
286
+ if (this.currentSubscriptionCount === 0) {
287
+ const local_publishEngine = this.publishEngine;
288
+ local_publishEngine.cancelPendingPublishRequest();
289
+ }
290
+ return node_opcua_status_code_1.StatusCodes.Good;
291
+ }
292
+ /**
293
+ * close a ServerSession, this will also delete the subscriptions if the flag is set.
294
+ *
295
+ * Spec extract:
296
+ *
297
+ * If a Client invokes the CloseSession Service then all Subscriptions associated with the Session are also deleted
298
+ * if the deleteSubscriptions flag is set to TRUE. If a Server terminates a Session for any other reason,
299
+ * Subscriptions associated with the Session, are not deleted. Each Subscription has its own lifetime to protect
300
+ * against data loss in the case of a Session termination. In these cases, the Subscription can be reassigned to
301
+ * another Client before its lifetime expires.
302
+ *
303
+ * @method close
304
+ * @param deleteSubscriptions : should we delete subscription ?
305
+ * @param [reason = "CloseSession"] the reason for closing the session
306
+ * (shall be "Timeout", "Terminated" or "CloseSession")
307
+ *
308
+ */
309
+ close(deleteSubscriptions, reason) {
310
+ debugLog(" closing session deleteSubscriptions = ", deleteSubscriptions);
311
+ if (this.publishEngine) {
312
+ this.publishEngine.onSessionClose();
313
+ }
314
+ theWatchDog.removeSubscriber(this);
315
+ // --------------- delete associated subscriptions ---------------------
316
+ if (!deleteSubscriptions && this.currentSubscriptionCount !== 0) {
317
+ // I don't know what to do yet if deleteSubscriptions is false
318
+ errorLog("TO DO : Closing session without deleting subscription not yet implemented");
319
+ // to do: Put subscriptions in safe place for future transfer if any
320
+ }
321
+ this._deleteSubscriptions();
322
+ (0, node_opcua_assert_1.assert)(this.currentSubscriptionCount === 0);
323
+ // Post-Conditions
324
+ (0, node_opcua_assert_1.assert)(this.currentSubscriptionCount === 0);
325
+ this.status = "closed";
326
+ this._detach_channel();
327
+ /**
328
+ * @event session_closed
329
+ * @param deleteSubscriptions {Boolean}
330
+ * @param reason {String}
331
+ */
332
+ this.emit("session_closed", this, deleteSubscriptions, reason);
333
+ // ---------------- shut down publish engine
334
+ if (this.publishEngine) {
335
+ // remove subscription
336
+ this.publishEngine.shutdown();
337
+ (0, node_opcua_assert_1.assert)(this.publishEngine.subscriptionCount === 0);
338
+ this.publishEngine.dispose();
339
+ this.publishEngine = null;
340
+ }
341
+ this._removeSessionObjectFromAddressSpace();
342
+ (0, node_opcua_assert_1.assert)(!this.sessionDiagnostics, "ServerSession#_removeSessionObjectFromAddressSpace must be called");
343
+ (0, node_opcua_assert_1.assert)(!this.sessionObject, "ServerSession#_removeSessionObjectFromAddressSpace must be called");
344
+ }
345
+ registerNode(nodeId) {
346
+ (0, node_opcua_assert_1.assert)(nodeId instanceof node_opcua_nodeid_1.NodeId);
347
+ if (nodeId.namespace === 0 && nodeId.identifierType === node_opcua_nodeid_1.NodeIdType.NUMERIC) {
348
+ return nodeId;
349
+ }
350
+ const key = nodeId.toString();
351
+ const registeredNode = this._registeredNodes[key];
352
+ if (registeredNode) {
353
+ // already registered
354
+ return registeredNode;
355
+ }
356
+ const node = this.addressSpace.findNode(nodeId);
357
+ if (!node) {
358
+ return nodeId;
359
+ }
360
+ this._registeredNodesCounter += 1;
361
+ const aliasNodeId = (0, node_opcua_nodeid_1.makeNodeId)(this._registeredNodesCounter, registeredNodeNameSpace);
362
+ this._registeredNodes[key] = aliasNodeId;
363
+ this._registeredNodesInv[aliasNodeId.toString()] = node;
364
+ return aliasNodeId;
365
+ }
366
+ unRegisterNode(aliasNodeId) {
367
+ (0, node_opcua_assert_1.assert)(aliasNodeId instanceof node_opcua_nodeid_1.NodeId);
368
+ if (aliasNodeId.namespace !== registeredNodeNameSpace) {
369
+ return; // not a registered Node
370
+ }
371
+ const node = this._registeredNodesInv[aliasNodeId.toString()];
372
+ if (!node) {
373
+ return;
374
+ }
375
+ this._registeredNodesInv[aliasNodeId.toString()] = null;
376
+ this._registeredNodes[node.nodeId.toString()] = null;
377
+ }
378
+ resolveRegisteredNode(aliasNodeId) {
379
+ if (aliasNodeId.namespace !== registeredNodeNameSpace) {
380
+ return aliasNodeId; // not a registered Node
381
+ }
382
+ const node = this._registeredNodesInv[aliasNodeId.toString()];
383
+ if (!node) {
384
+ return aliasNodeId;
385
+ }
386
+ return node.nodeId;
387
+ }
388
+ /**
389
+ * true if the underlying channel has been closed or aborted...
390
+ */
391
+ get aborted() {
392
+ if (!this.channel) {
393
+ return true;
394
+ }
395
+ return this.channel.aborted;
396
+ }
397
+ createSubscription(parameters) {
398
+ const subscription = this.parent._createSubscriptionOnSession(this, parameters);
399
+ (0, node_opcua_assert_1.assert)(!Object.prototype.hasOwnProperty.call(parameters, "id"));
400
+ this.assignSubscription(subscription);
401
+ (0, node_opcua_assert_1.assert)(subscription.$session === this);
402
+ (0, node_opcua_assert_1.assert)(subscription.sessionId instanceof node_opcua_nodeid_1.NodeId);
403
+ (0, node_opcua_assert_1.assert)((0, node_opcua_nodeid_1.sameNodeId)(subscription.sessionId, this.nodeId));
404
+ return subscription;
405
+ }
406
+ _attach_channel(channel) {
407
+ (0, node_opcua_assert_1.assert)(this.nonce && this.nonce instanceof Buffer);
408
+ this.channel = channel;
409
+ this.channelId = channel.channelId;
410
+ const key = this.authenticationToken.toString();
411
+ (0, node_opcua_assert_1.assert)(!Object.prototype.hasOwnProperty.call(channel.sessionTokens, key), "channel has already a session");
412
+ channel.sessionTokens[key] = this;
413
+ // when channel is aborting
414
+ this.channel_abort_event_handler = on_channel_abort.bind(this);
415
+ channel.on("abort", this.channel_abort_event_handler);
416
+ }
417
+ _detach_channel() {
418
+ const channel = this.channel;
419
+ // istanbul ignore next
420
+ if (!channel) {
421
+ return;
422
+ // already detached !
423
+ // throw new Error("expecting a valid channel");
424
+ }
425
+ (0, node_opcua_assert_1.assert)(this.nonce && this.nonce instanceof Buffer);
426
+ (0, node_opcua_assert_1.assert)(this.authenticationToken);
427
+ const key = this.authenticationToken.toString();
428
+ (0, node_opcua_assert_1.assert)(Object.prototype.hasOwnProperty.call(channel.sessionTokens, key));
429
+ (0, node_opcua_assert_1.assert)(this.channel);
430
+ (0, node_opcua_assert_1.assert)(typeof this.channel_abort_event_handler === "function");
431
+ channel.removeListener("abort", this.channel_abort_event_handler);
432
+ delete channel.sessionTokens[key];
433
+ this.channel = undefined;
434
+ this.channelId = undefined;
435
+ }
436
+ _exposeSubscriptionDiagnostics(subscription) {
437
+ debugLog("ServerSession#_exposeSubscriptionDiagnostics");
438
+ (0, node_opcua_assert_1.assert)(subscription.$session === this);
439
+ const subscriptionDiagnosticsArray = this._getSubscriptionDiagnosticsArray();
440
+ const subscriptionDiagnostics = subscription.subscriptionDiagnostics;
441
+ (0, node_opcua_assert_1.assert)(subscriptionDiagnostics.$subscription === subscription);
442
+ if (subscriptionDiagnostics && subscriptionDiagnosticsArray) {
443
+ // subscription.id,"on session", session.nodeId.toString());
444
+ (0, node_opcua_address_space_1.addElement)(subscriptionDiagnostics, subscriptionDiagnosticsArray);
445
+ }
446
+ }
447
+ _unexposeSubscriptionDiagnostics(subscription) {
448
+ const subscriptionDiagnosticsArray = this._getSubscriptionDiagnosticsArray();
449
+ const subscriptionDiagnostics = subscription.subscriptionDiagnostics;
450
+ (0, node_opcua_assert_1.assert)(subscriptionDiagnostics instanceof node_opcua_common_1.SubscriptionDiagnosticsDataType);
451
+ if (subscriptionDiagnostics && subscriptionDiagnosticsArray) {
452
+ // subscription.id,"on session", session.nodeId.toString());
453
+ (0, node_opcua_address_space_1.removeElement)(subscriptionDiagnosticsArray, subscriptionDiagnostics);
454
+ }
455
+ debugLog("ServerSession#_unexposeSubscriptionDiagnostics");
456
+ }
457
+ /**
458
+ * @method watchdogReset
459
+ * used as a callback for the Watchdog
460
+ * @private
461
+ */
462
+ watchdogReset() {
463
+ debugLog("Session#watchdogReset: the server session has expired and must be removed from the server");
464
+ // the server session has expired and must be removed from the server
465
+ this.emit("timeout");
466
+ }
467
+ _createSessionObjectInAddressSpace() {
468
+ if (this.sessionObject) {
469
+ return;
470
+ }
471
+ (0, node_opcua_assert_1.assert)(!this.sessionObject, "ServerSession#_createSessionObjectInAddressSpace already called ?");
472
+ this.sessionObject = null;
473
+ if (!this.addressSpace) {
474
+ debugLog("ServerSession#_createSessionObjectInAddressSpace : no addressSpace");
475
+ return; // no addressSpace
476
+ }
477
+ const root = this.addressSpace.rootFolder;
478
+ (0, node_opcua_assert_1.assert)(root, "expecting a root object");
479
+ if (!root.objects) {
480
+ debugLog("ServerSession#_createSessionObjectInAddressSpace : no object folder");
481
+ return false;
482
+ }
483
+ if (!root.objects.server) {
484
+ debugLog("ServerSession#_createSessionObjectInAddressSpace : no server object");
485
+ return false;
486
+ }
487
+ // self.addressSpace.findNode(makeNodeId(ObjectIds.Server_ServerDiagnostics));
488
+ const serverDiagnosticsNode = root.objects.server.serverDiagnostics;
489
+ if (!serverDiagnosticsNode || !serverDiagnosticsNode.sessionsDiagnosticsSummary) {
490
+ debugLog("ServerSession#_createSessionObjectInAddressSpace :" + " no serverDiagnostics.sessionsDiagnosticsSummary");
491
+ return false;
492
+ }
493
+ const sessionDiagnosticsObjectType = this.addressSpace.findObjectType("SessionDiagnosticsObjectType");
494
+ const sessionDiagnosticsDataType = this.addressSpace.findDataType("SessionDiagnosticsDataType");
495
+ const sessionDiagnosticsVariableType = this.addressSpace.findVariableType("SessionDiagnosticsVariableType");
496
+ const sessionSecurityDiagnosticsDataType = this.addressSpace.findDataType("SessionSecurityDiagnosticsDataType");
497
+ const sessionSecurityDiagnosticsType = this.addressSpace.findVariableType("SessionSecurityDiagnosticsType");
498
+ const namespace = this.addressSpace.getOwnNamespace();
499
+ function createSessionDiagnosticsStuff() {
500
+ if (sessionDiagnosticsDataType && sessionDiagnosticsVariableType) {
501
+ // the extension object
502
+ this._sessionDiagnostics = this.addressSpace.constructExtensionObject(sessionDiagnosticsDataType, {});
503
+ this._sessionDiagnostics.$session = this;
504
+ // install property getter on property that are unlikely to change
505
+ if (this.parent.clientDescription) {
506
+ this._sessionDiagnostics.clientDescription = this.parent.clientDescription;
507
+ }
508
+ Object.defineProperty(this._sessionDiagnostics, "clientConnectionTime", {
509
+ get() {
510
+ return this.$session.clientConnectionTime;
511
+ }
512
+ });
513
+ Object.defineProperty(this._sessionDiagnostics, "actualSessionTimeout", {
514
+ get() {
515
+ var _a;
516
+ return (_a = this.$session) === null || _a === void 0 ? void 0 : _a.sessionTimeout;
517
+ }
518
+ });
519
+ Object.defineProperty(this._sessionDiagnostics, "sessionId", {
520
+ get() {
521
+ return this.$session ? this.$session.nodeId : node_opcua_nodeid_1.NodeId.nullNodeId;
522
+ }
523
+ });
524
+ Object.defineProperty(this._sessionDiagnostics, "sessionName", {
525
+ get() {
526
+ return this.$session ? this.$session.sessionName.toString() : "";
527
+ }
528
+ });
529
+ this.sessionDiagnostics = sessionDiagnosticsVariableType.instantiate({
530
+ browseName: new node_opcua_data_model_1.QualifiedName({ name: "SessionDiagnostics", namespaceIndex: 0 }),
531
+ componentOf: this.sessionObject,
532
+ extensionObject: this._sessionDiagnostics,
533
+ minimumSamplingInterval: 2000 // 2 seconds
534
+ });
535
+ this._sessionDiagnostics = this.sessionDiagnostics.$extensionObject;
536
+ (0, node_opcua_assert_1.assert)(this._sessionDiagnostics.$session === this);
537
+ const sessionDiagnosticsArray = this.getSessionDiagnosticsArray();
538
+ // add sessionDiagnostics into sessionDiagnosticsArray
539
+ (0, node_opcua_address_space_1.addElement)(this._sessionDiagnostics, sessionDiagnosticsArray);
540
+ }
541
+ }
542
+ function createSessionSecurityDiagnosticsStuff() {
543
+ if (sessionSecurityDiagnosticsDataType && sessionSecurityDiagnosticsType) {
544
+ // the extension object
545
+ this._sessionSecurityDiagnostics = this.addressSpace.constructExtensionObject(sessionSecurityDiagnosticsDataType, {});
546
+ this._sessionSecurityDiagnostics.$session = this;
547
+ /*
548
+ sessionId: NodeId;
549
+ clientUserIdOfSession: UAString;
550
+ clientUserIdHistory: UAString[] | null;
551
+ authenticationMechanism: UAString;
552
+ encoding: UAString;
553
+ transportProtocol: UAString;
554
+ securityMode: MessageSecurityMode;
555
+ securityPolicyUri: UAString;
556
+ clientCertificate: ByteString;
557
+ */
558
+ Object.defineProperty(this._sessionSecurityDiagnostics, "sessionId", {
559
+ get() {
560
+ var _a;
561
+ return (_a = this.$session) === null || _a === void 0 ? void 0 : _a.nodeId;
562
+ }
563
+ });
564
+ Object.defineProperty(this._sessionSecurityDiagnostics, "clientUserIdOfSession", {
565
+ get() {
566
+ return ""; // UAString // TO DO : implement
567
+ }
568
+ });
569
+ Object.defineProperty(this._sessionSecurityDiagnostics, "clientUserIdHistory", {
570
+ get() {
571
+ return []; // UAString[] | null
572
+ }
573
+ });
574
+ Object.defineProperty(this._sessionSecurityDiagnostics, "authenticationMechanism", {
575
+ get() {
576
+ return "";
577
+ }
578
+ });
579
+ Object.defineProperty(this._sessionSecurityDiagnostics, "encoding", {
580
+ get() {
581
+ return "";
582
+ }
583
+ });
584
+ Object.defineProperty(this._sessionSecurityDiagnostics, "transportProtocol", {
585
+ get() {
586
+ return "opc.tcp";
587
+ }
588
+ });
589
+ Object.defineProperty(this._sessionSecurityDiagnostics, "securityMode", {
590
+ get() {
591
+ var _a;
592
+ const session = this.$session;
593
+ return (_a = session === null || session === void 0 ? void 0 : session.channel) === null || _a === void 0 ? void 0 : _a.securityMode;
594
+ }
595
+ });
596
+ Object.defineProperty(this._sessionSecurityDiagnostics, "securityPolicyUri", {
597
+ get() {
598
+ var _a;
599
+ const session = this.$session;
600
+ return (_a = session === null || session === void 0 ? void 0 : session.channel) === null || _a === void 0 ? void 0 : _a.securityPolicy;
601
+ }
602
+ });
603
+ Object.defineProperty(this._sessionSecurityDiagnostics, "clientCertificate", {
604
+ get() {
605
+ const session = this.$session;
606
+ return session === null || session === void 0 ? void 0 : session.channel.clientCertificate;
607
+ }
608
+ });
609
+ this.sessionSecurityDiagnostics = sessionSecurityDiagnosticsType.instantiate({
610
+ browseName: new node_opcua_data_model_1.QualifiedName({ name: "SessionSecurityDiagnostics", namespaceIndex: 0 }),
611
+ componentOf: this.sessionObject,
612
+ extensionObject: this._sessionSecurityDiagnostics,
613
+ minimumSamplingInterval: 2000 // 2 seconds
614
+ });
615
+ (0, node_opcua_address_space_1.ensureObjectIsSecure)(this.sessionSecurityDiagnostics);
616
+ this._sessionSecurityDiagnostics = this.sessionSecurityDiagnostics
617
+ .$extensionObject;
618
+ (0, node_opcua_assert_1.assert)(this._sessionSecurityDiagnostics.$session === this);
619
+ const sessionSecurityDiagnosticsArray = this.getSessionSecurityDiagnosticsArray();
620
+ // add sessionDiagnostics into sessionDiagnosticsArray
621
+ const node = (0, node_opcua_address_space_1.addElement)(this._sessionSecurityDiagnostics, sessionSecurityDiagnosticsArray);
622
+ (0, node_opcua_address_space_1.ensureObjectIsSecure)(node);
623
+ }
624
+ }
625
+ function createSessionDiagnosticSummaryUAObject() {
626
+ const references = [];
627
+ if (sessionDiagnosticsObjectType) {
628
+ references.push({
629
+ isForward: true,
630
+ nodeId: sessionDiagnosticsObjectType,
631
+ referenceType: "HasTypeDefinition"
632
+ });
633
+ }
634
+ this.sessionObject = namespace.createNode({
635
+ browseName: this.sessionName || "Session-" + this.nodeId.toString(),
636
+ componentOf: serverDiagnosticsNode.sessionsDiagnosticsSummary,
637
+ nodeClass: node_opcua_data_model_1.NodeClass.Object,
638
+ nodeId: this.nodeId,
639
+ references,
640
+ typeDefinition: sessionDiagnosticsObjectType
641
+ });
642
+ createSessionDiagnosticsStuff.call(this);
643
+ createSessionSecurityDiagnosticsStuff.call(this);
644
+ }
645
+ function createSubscriptionDiagnosticsArray() {
646
+ const subscriptionDiagnosticsArrayType = this.addressSpace.findVariableType("SubscriptionDiagnosticsArrayType");
647
+ (0, node_opcua_assert_1.assert)(subscriptionDiagnosticsArrayType.nodeId.toString() === "ns=0;i=2171");
648
+ this.subscriptionDiagnosticsArray = (0, node_opcua_address_space_1.createExtObjArrayNode)(this.sessionObject, {
649
+ browseName: { namespaceIndex: 0, name: "SubscriptionDiagnosticsArray" },
650
+ complexVariableType: "SubscriptionDiagnosticsArrayType",
651
+ indexPropertyName: "subscriptionId",
652
+ minimumSamplingInterval: 2000,
653
+ variableType: "SubscriptionDiagnosticsType"
654
+ });
655
+ }
656
+ createSessionDiagnosticSummaryUAObject.call(this);
657
+ createSubscriptionDiagnosticsArray.call(this);
658
+ return this.sessionObject;
659
+ }
660
+ /**
661
+ *
662
+ * @private
663
+ */
664
+ _removeSessionObjectFromAddressSpace() {
665
+ // todo : dump session statistics in a file or somewhere for deeper diagnostic analysis on closed session
666
+ if (!this.addressSpace) {
667
+ return;
668
+ }
669
+ if (this.sessionDiagnostics) {
670
+ const sessionDiagnosticsArray = this.getSessionDiagnosticsArray();
671
+ (0, node_opcua_address_space_1.removeElement)(sessionDiagnosticsArray, this.sessionDiagnostics.$extensionObject);
672
+ this.addressSpace.deleteNode(this.sessionDiagnostics);
673
+ (0, node_opcua_assert_1.assert)(this._sessionDiagnostics.$session === this);
674
+ this._sessionDiagnostics.$session = null;
675
+ this._sessionDiagnostics = undefined;
676
+ this.sessionDiagnostics = undefined;
677
+ }
678
+ if (this.sessionSecurityDiagnostics) {
679
+ const sessionSecurityDiagnosticsArray = this.getSessionSecurityDiagnosticsArray();
680
+ (0, node_opcua_address_space_1.removeElement)(sessionSecurityDiagnosticsArray, this.sessionSecurityDiagnostics.$extensionObject);
681
+ this.addressSpace.deleteNode(this.sessionSecurityDiagnostics);
682
+ (0, node_opcua_assert_1.assert)(this._sessionSecurityDiagnostics.$session === this);
683
+ this._sessionSecurityDiagnostics.$session = null;
684
+ this._sessionSecurityDiagnostics = undefined;
685
+ this.sessionSecurityDiagnostics = undefined;
686
+ }
687
+ if (this.sessionObject) {
688
+ this.addressSpace.deleteNode(this.sessionObject);
689
+ this.sessionObject = null;
690
+ }
691
+ }
692
+ /**
693
+ *
694
+ * @private
695
+ */
696
+ _getSubscriptionDiagnosticsArray() {
697
+ if (!this.addressSpace) {
698
+ if (doDebug) {
699
+ console.warn("ServerSession#_getSubscriptionDiagnosticsArray : no addressSpace");
700
+ }
701
+ return null; // no addressSpace
702
+ }
703
+ const subscriptionDiagnosticsArray = this.subscriptionDiagnosticsArray;
704
+ if (!subscriptionDiagnosticsArray) {
705
+ return null; // no subscriptionDiagnosticsArray
706
+ }
707
+ (0, node_opcua_assert_1.assert)(subscriptionDiagnosticsArray.browseName.toString() === "SubscriptionDiagnosticsArray");
708
+ return subscriptionDiagnosticsArray;
709
+ }
710
+ assignSubscription(subscription) {
711
+ (0, node_opcua_assert_1.assert)(!subscription.$session);
712
+ (0, node_opcua_assert_1.assert)(this.nodeId instanceof node_opcua_nodeid_1.NodeId);
713
+ subscription.$session = this;
714
+ (0, node_opcua_assert_1.assert)(subscription.sessionId === this.nodeId);
715
+ this._cumulatedSubscriptionCount += 1;
716
+ // Notify the owner that a new subscription has been created
717
+ // @event new_subscription
718
+ // @param {Subscription} subscription
719
+ this.emit("new_subscription", subscription);
720
+ // add subscription diagnostics to SubscriptionDiagnosticsArray
721
+ this._exposeSubscriptionDiagnostics(subscription);
722
+ subscription.once("terminated", () => {
723
+ // Notify the owner that a new subscription has been terminated
724
+ // @event subscription_terminated
725
+ // @param {Subscription} subscription
726
+ this.emit("subscription_terminated", subscription);
727
+ });
728
+ }
729
+ _deleteSubscriptions() {
730
+ (0, node_opcua_assert_1.assert)(this.publishEngine);
731
+ const subscriptions = this.publishEngine.subscriptions;
732
+ for (const subscription of subscriptions) {
733
+ this.deleteSubscription(subscription.id);
734
+ }
735
+ }
736
+ }
737
+ exports.ServerSession = ServerSession;
738
+ ServerSession.registry = new node_opcua_object_registry_1.ObjectRegistry();
739
+ ServerSession.maxPublishRequestInQueue = 100;
740
740
  //# sourceMappingURL=server_session.js.map