@vitormnm/node-red-simple-opcua 1.4.3 → 1.6.2

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 (34) hide show
  1. package/client/icons/opcua.svg +132 -132
  2. package/client/lib/opcua-client-browser.js +368 -330
  3. package/client/lib/opcua-client-method-service.js +88 -88
  4. package/client/lib/opcua-client-read-service.js +27 -15
  5. package/client/lib/opcua-client-subscription-id-service.js +24 -24
  6. package/client/lib/opcua-client-subscription-service.js +175 -170
  7. package/client/lib/opcua-client-write-service.js +146 -146
  8. package/client/opcua-client-config.html +80 -80
  9. package/client/opcua-client-utils.js +217 -22
  10. package/client/opcua-client.html +140 -140
  11. package/client/view/opcua-client.js +1144 -1140
  12. package/examples/flows_simple_opc.json +1 -2851
  13. package/icons/opcua.svg +132 -132
  14. package/icons/opcua2.svg +132 -132
  15. package/package.json +3 -3
  16. package/server/icons/opcua.svg +132 -132
  17. package/server/lib/opcua-address-space-alarm.js +341 -341
  18. package/server/lib/opcua-address-space-builder.js +1797 -1485
  19. package/server/lib/opcua-config.js +800 -546
  20. package/server/lib/opcua-constants.js +120 -109
  21. package/server/lib/opcua-server-events-child.js +139 -139
  22. package/server/lib/opcua-server-methods.js +2 -0
  23. package/server/lib/opcua-server-runtime-child.js +874 -819
  24. package/server/lib/opcua-server-runtime.js +385 -311
  25. package/server/lib/opcua-server-status-child.js +187 -187
  26. package/server/lib/server-node-utils.js +16 -16
  27. package/server/opcua-server-io.html +346 -346
  28. package/server/opcua-server-io.js +497 -496
  29. package/server/opcua-server-registry.js +270 -270
  30. package/server/opcua-server.css +265 -265
  31. package/server/opcua-server.html +158 -1643
  32. package/server/opcua-server.js +24 -13
  33. package/server/view/opcua-server.css +496 -0
  34. package/server/view/opcua-server.js +1585 -0
@@ -1,311 +1,385 @@
1
- "use strict";
2
-
3
-
4
-
5
- const {
6
- OPCUAServer,
7
- UserTokenType,
8
- buildApplicationUri
9
- } = require("./opcua-constants");
10
- const { OpcUaAddressSpaceBuilder } = require("./opcua-address-space-builder");
11
- const { OpcUaServerMethods } = require("./opcua-server-methods");
12
-
13
- class OpcUaServerRuntime {
14
- constructor(options) {
15
- this.node = options.node;
16
- this.registry = options.registry;
17
- this.id = options.settings.id;
18
- this.name = options.settings.name;
19
- this.serverName = options.settings.serverName;
20
- this.port = options.settings.port;
21
- this.maxConnections = options.settings.maxConnections;
22
- this.namespaceUri = options.settings.namespaceUri;
23
- this.resourcePath = options.settings.resourcePath;
24
- this.allowAnonymous = options.settings.allowAnonymous;
25
- this.users = options.settings.users;
26
- this.securityPolicy = options.settings.securityPolicy;
27
- this.securityMode = options.settings.securityMode;
28
- this.treeConfig = options.settings.treeConfig;
29
-
30
- this.server = null;
31
- this.namespace = null;
32
- this.namespaces = new Map();
33
- this.namespaceDefinitions = new Map();
34
- this.addressSpaceBuilder = null;
35
-
36
-
37
- }
38
-
39
- async start() {
40
- if (this.server) {
41
- return;
42
- }
43
-
44
- this.server = new OPCUAServer(this.buildServerOptions());
45
- await this.server.initialize();
46
-
47
- const addressSpace = this.server.engine.addressSpace;
48
-
49
- this.initializeNamespaces(this.treeConfig);
50
-
51
- this.addressSpaceBuilder = new OpcUaAddressSpaceBuilder({
52
- namespace: this.namespace,
53
- namespaces: this.namespaces,
54
- server: this.server,
55
- registry: this.registry,
56
- node: this.node,
57
- serverName: this.serverName,
58
- addressSpace: this.addressSpace
59
- });
60
-
61
-
62
- this.addressSpaceBuilder.rebuild(this.treeConfig);
63
- await this.server.start();
64
- this.registry.registerServer(this);
65
-
66
- //Methods
67
- const ServerMethods = new OpcUaServerMethods({
68
- addressSpace: addressSpace,
69
- registry: this.registry,
70
- node: this.node
71
- })
72
-
73
- ServerMethods.start();
74
-
75
-
76
- }
77
-
78
- async stop() {
79
- if (!this.server) {
80
- this.node.status({ fill: "grey", shape: "ring", text: "stopped" });
81
- return;
82
- }
83
-
84
- try {
85
- if (this.addressSpaceBuilder) {
86
- this.addressSpaceBuilder.clearDynamicNodes();
87
- this.addressSpaceBuilder.variableStore.clear();
88
- }
89
-
90
- await this.server.shutdown(1000);
91
- } finally {
92
- this.registry.unregisterServer(this.id);
93
- this.addressSpaceBuilder = null;
94
- this.namespace = null;
95
- this.namespaces = new Map();
96
- this.namespaceDefinitions = new Map();
97
- this.server = null;
98
- this.node.status({ fill: "grey", shape: "ring", text: "stopped" });
99
- }
100
- }
101
-
102
- ensureReady() {
103
- if (!this.server || !this.namespace || !this.addressSpaceBuilder) {
104
- throw new Error("OPC UA server is not available");
105
- }
106
- }
107
-
108
-
109
-
110
- async updateTree(treeConfig) {
111
- this.ensureReady();
112
- this.syncNamespaces(treeConfig);
113
- this.treeConfig = treeConfig;
114
- this.addressSpaceBuilder.sync(treeConfig);
115
- }
116
-
117
- readValueByPath(path) {
118
- this.ensureReady();
119
- return this.addressSpaceBuilder.readValueByPath(path);
120
- }
121
-
122
- readValueByNodeId(nodeId) {
123
- this.ensureReady();
124
- return this.addressSpaceBuilder.readValueByNodeId(nodeId);
125
- }
126
-
127
- readValue(identifierType, identifier) {
128
- this.ensureReady();
129
- return this.addressSpaceBuilder.readValue(identifierType, identifier);
130
- }
131
-
132
- writeEventByPath(valuesPayload) {
133
- this.ensureReady();
134
- return this.addressSpaceBuilder.eventValueByPath(valuesPayload);
135
- }
136
-
137
- writeValueByPath(path, value) {
138
- this.ensureReady();
139
- return this.addressSpaceBuilder.writeValueByPath(path, value);
140
- }
141
-
142
- writeValueByNodeId(nodeId, value) {
143
- this.ensureReady();
144
- return this.addressSpaceBuilder.writeValueByNodeId(nodeId, value);
145
- }
146
-
147
- writeValue(identifierType, identifier, value) {
148
- this.ensureReady();
149
- return this.addressSpaceBuilder.writeValue(identifierType, identifier, value);
150
- }
151
-
152
- getEndpointUrl() {
153
- if (!this.server || !Array.isArray(this.server.endpoints)) {
154
- return "";
155
- }
156
-
157
- for (let index = 0; index < this.server.endpoints.length; index += 1) {
158
- const endpoint = this.server.endpoints[index];
159
- if (!endpoint || typeof endpoint.endpointDescriptions !== "function") {
160
- continue;
161
- }
162
-
163
- const descriptions = endpoint.endpointDescriptions();
164
- if (Array.isArray(descriptions) && descriptions.length && descriptions[0].endpointUrl) {
165
- return descriptions[0].endpointUrl;
166
- }
167
- }
168
-
169
- return "opc.tcp://localhost:" + this.port + this.resourcePath;
170
- }
171
-
172
- buildServerOptions() {
173
- const activeUsers = Array.isArray(this.users) ? this.users : [];
174
- const userTokenPolicies = [];
175
-
176
- if (this.allowAnonymous) {
177
- userTokenPolicies.push({
178
- policyId: "anonymous",
179
- tokenType: UserTokenType.Anonymous
180
- });
181
- }
182
-
183
- if (activeUsers.length) {
184
- userTokenPolicies.push({
185
- policyId: "username",
186
- tokenType: UserTokenType.UserName
187
- });
188
- }
189
-
190
- return {
191
- port: this.port,
192
- resourcePath: this.resourcePath,
193
- buildInfo: {
194
- productName: "opc-ua-server",
195
- buildNumber: "1",
196
- buildDate: new Date()
197
- },
198
- // serverCertificateManager: {
199
- // automaticallyAcceptUnknownCertificate: true
200
- // },
201
- serverCapabilities: {
202
- maxSessions: this.maxConnections
203
- },
204
- serverInfo: {
205
- applicationName: { text: this.serverName },
206
- applicationUri: buildApplicationUri(this.serverName),
207
- productUri: "urn:node-red:opc-ua-server"
208
- },
209
- securityPolicies: [this.securityPolicy],
210
- securityModes: [this.securityMode],
211
- allowAnonymous: this.allowAnonymous,
212
- userManager: {
213
- isValidUser: (username, password) => this.isValidUser(username, password)
214
- },
215
- userTokenPolicies
216
- };
217
- }
218
-
219
- isValidUser(username, password) {
220
- return this.users.some((user) => {
221
- if (user.username !== username) {
222
- return false;
223
- }
224
-
225
- if (user.password && user.password === password) {
226
- return true;
227
- }
228
-
229
- if (user.passwordHash) {
230
- try {
231
- return bcrypt.compareSync(password, user.passwordHash);
232
- } catch (error) {
233
- this.node.warn("Failed to validate password hash for user " + username + ": " + error.message);
234
- return false;
235
- }
236
- }
237
-
238
- return false;
239
- });
240
- }
241
-
242
- initializeNamespaces(treeConfig) {
243
- const addressSpace = this.server.engine.addressSpace;
244
- const configuredNamespaces = this.buildNamespaceDefinitions(treeConfig);
245
-
246
- this.namespaces = new Map();
247
- this.namespaceDefinitions = configuredNamespaces;
248
-
249
- configuredNamespaces.forEach((uri, namespaceId) => {
250
- const namespace = addressSpace.getNamespace(uri) || addressSpace.registerNamespace(uri);
251
- this.namespaces.set(namespaceId, namespace);
252
- });
253
-
254
- this.namespace = this.namespaces.get(2);
255
- }
256
-
257
- syncNamespaces(treeConfig) {
258
- const addressSpace = this.server.engine.addressSpace;
259
- const nextDefinitions = this.buildNamespaceDefinitions(treeConfig);
260
-
261
- this.namespaceDefinitions.forEach((uri, namespaceId) => {
262
- const nextUri = nextDefinitions.get(namespaceId);
263
- if (nextUri && nextUri !== uri) {
264
- throw new Error("Namespace URI changes require a redeploy: namespace " + namespaceId);
265
- }
266
-
267
- if (!nextUri) {
268
- throw new Error("Removing namespaces requires a redeploy: namespace " + namespaceId);
269
- }
270
- });
271
-
272
- nextDefinitions.forEach((uri, namespaceId) => {
273
- if (this.namespaces.has(namespaceId)) {
274
- return;
275
- }
276
-
277
- const namespace = addressSpace.getNamespace(uri) || addressSpace.registerNamespace(uri);
278
- this.namespaces.set(namespaceId, namespace);
279
- });
280
-
281
- this.namespaceDefinitions = nextDefinitions;
282
- this.namespace = this.namespaces.get(2);
283
- }
284
-
285
- buildNamespaceDefinitions(treeConfig) {
286
- const definitions = new Map();
287
- const configuredNamespaces = Array.isArray(treeConfig && treeConfig.nameSpaces) ? treeConfig.nameSpaces : [];
288
- let defaultNamespaceUri = this.namespaceUri;
289
-
290
- configuredNamespaces.forEach((namespaceConfig) => {
291
- if (namespaceConfig.id === 2) {
292
- defaultNamespaceUri = namespaceConfig.name;
293
- }
294
- });
295
-
296
- definitions.set(2, defaultNamespaceUri);
297
-
298
- configuredNamespaces
299
- .slice()
300
- .sort((left, right) => left.id - right.id)
301
- .forEach((namespaceConfig) => {
302
- definitions.set(namespaceConfig.id, namespaceConfig.name);
303
- });
304
-
305
- return definitions;
306
- }
307
- }
308
-
309
- module.exports = {
310
- OpcUaServerRuntime
311
- };
1
+ "use strict";
2
+
3
+
4
+
5
+ const {
6
+ OPCUAServer,
7
+ UserTokenType,
8
+ buildApplicationUri,
9
+ makeRoles,
10
+ WellKnownRoles,
11
+ resolveNodeId
12
+ } = require("./opcua-constants");
13
+ const { OpcUaAddressSpaceBuilder } = require("./opcua-address-space-builder");
14
+ const { OpcUaServerMethods } = require("./opcua-server-methods");
15
+ let bcrypt = null;
16
+
17
+ try {
18
+ bcrypt = require("bcryptjs");
19
+ } catch (error) {
20
+ bcrypt = null;
21
+ }
22
+
23
+ class OpcUaServerRuntime {
24
+ constructor(options) {
25
+ this.node = options.node;
26
+ this.registry = options.registry;
27
+ this.id = options.settings.id;
28
+ this.name = options.settings.name;
29
+ this.serverName = options.settings.serverName;
30
+ this.port = options.settings.port;
31
+ this.maxConnections = options.settings.maxConnections;
32
+ this.namespaceUri = options.settings.namespaceUri;
33
+ this.resourcePath = options.settings.resourcePath;
34
+ this.allowAnonymous = options.settings.allowAnonymous;
35
+ this.groups = options.settings.groups;
36
+ this.users = options.settings.users;
37
+ this.securityPolicy = options.settings.securityPolicy;
38
+ this.securityMode = options.settings.securityMode;
39
+ this.treeConfig = options.settings.treeConfig;
40
+
41
+ this.server = null;
42
+ this.namespace = null;
43
+ this.namespaces = new Map();
44
+ this.namespaceDefinitions = new Map();
45
+ this.addressSpaceBuilder = null;
46
+
47
+
48
+ }
49
+
50
+ async start() {
51
+ if (this.server) {
52
+ return;
53
+ }
54
+
55
+ this.server = new OPCUAServer(this.buildServerOptions());
56
+ await this.server.initialize();
57
+
58
+ const addressSpace = this.server.engine.addressSpace;
59
+
60
+ this.initializeNamespaces(this.treeConfig);
61
+
62
+ this.addressSpaceBuilder = new OpcUaAddressSpaceBuilder({
63
+ namespace: this.namespace,
64
+ namespaces: this.namespaces,
65
+ server: this.server,
66
+ registry: this.registry,
67
+ node: this.node,
68
+ serverName: this.serverName,
69
+ addressSpace: this.addressSpace,
70
+ allowAnonymous: this.allowAnonymous,
71
+ users: this.users
72
+ });
73
+
74
+
75
+ this.addressSpaceBuilder.rebuild(this.treeConfig);
76
+ await this.server.start();
77
+ this.registry.registerServer(this);
78
+
79
+ //Methods
80
+ const ServerMethods = new OpcUaServerMethods({
81
+ addressSpace: addressSpace,
82
+ registry: this.registry,
83
+ node: this.node
84
+ })
85
+
86
+ ServerMethods.start();
87
+
88
+
89
+ }
90
+
91
+ async stop() {
92
+ if (!this.server) {
93
+ this.node.status({ fill: "grey", shape: "ring", text: "stopped" });
94
+ return;
95
+ }
96
+
97
+ try {
98
+ if (this.addressSpaceBuilder) {
99
+ this.addressSpaceBuilder.clearDynamicNodes();
100
+ this.addressSpaceBuilder.variableStore.clear();
101
+ }
102
+
103
+ await this.server.shutdown(1000);
104
+ } finally {
105
+ this.registry.unregisterServer(this.id);
106
+ this.addressSpaceBuilder = null;
107
+ this.namespace = null;
108
+ this.namespaces = new Map();
109
+ this.namespaceDefinitions = new Map();
110
+ this.server = null;
111
+ this.node.status({ fill: "grey", shape: "ring", text: "stopped" });
112
+ }
113
+ }
114
+
115
+ ensureReady() {
116
+ if (!this.server || !this.namespace || !this.addressSpaceBuilder) {
117
+ throw new Error("OPC UA server is not available");
118
+ }
119
+ }
120
+
121
+
122
+
123
+ async updateTree(treeConfig) {
124
+ this.ensureReady();
125
+ this.syncNamespaces(treeConfig);
126
+ this.treeConfig = treeConfig;
127
+ this.addressSpaceBuilder.sync(treeConfig);
128
+ }
129
+
130
+ readValueByPath(path) {
131
+ this.ensureReady();
132
+ return this.addressSpaceBuilder.readValueByPath(path);
133
+ }
134
+
135
+ readValueByNodeId(nodeId) {
136
+ this.ensureReady();
137
+ return this.addressSpaceBuilder.readValueByNodeId(nodeId);
138
+ }
139
+
140
+ readValue(identifierType, identifier) {
141
+ this.ensureReady();
142
+ return this.addressSpaceBuilder.readValue(identifierType, identifier);
143
+ }
144
+
145
+ writeEventByPath(valuesPayload) {
146
+ this.ensureReady();
147
+ return this.addressSpaceBuilder.eventValueByPath(valuesPayload);
148
+ }
149
+
150
+ writeValueByPath(path, value) {
151
+ this.ensureReady();
152
+ return this.addressSpaceBuilder.writeValueByPath(path, value);
153
+ }
154
+
155
+ writeValueByNodeId(nodeId, value) {
156
+ this.ensureReady();
157
+ return this.addressSpaceBuilder.writeValueByNodeId(nodeId, value);
158
+ }
159
+
160
+ writeValue(identifierType, identifier, value) {
161
+ this.ensureReady();
162
+ return this.addressSpaceBuilder.writeValue(identifierType, identifier, value);
163
+ }
164
+
165
+ getEndpointUrl() {
166
+ if (!this.server || !Array.isArray(this.server.endpoints)) {
167
+ return "";
168
+ }
169
+
170
+ for (let index = 0; index < this.server.endpoints.length; index += 1) {
171
+ const endpoint = this.server.endpoints[index];
172
+ if (!endpoint || typeof endpoint.endpointDescriptions !== "function") {
173
+ continue;
174
+ }
175
+
176
+ const descriptions = endpoint.endpointDescriptions();
177
+ if (Array.isArray(descriptions) && descriptions.length && descriptions[0].endpointUrl) {
178
+ return descriptions[0].endpointUrl;
179
+ }
180
+ }
181
+
182
+ return "opc.tcp://localhost:" + this.port + this.resourcePath;
183
+ }
184
+
185
+ buildServerOptions() {
186
+ const activeUsers = Array.isArray(this.users) ? this.users : [];
187
+ const userTokenPolicies = [];
188
+
189
+ if (this.allowAnonymous) {
190
+ userTokenPolicies.push({
191
+ policyId: "anonymous",
192
+ tokenType: UserTokenType.Anonymous
193
+ });
194
+ }
195
+
196
+ if (activeUsers.length) {
197
+ userTokenPolicies.push({
198
+ policyId: "username",
199
+ tokenType: UserTokenType.UserName
200
+ });
201
+ }
202
+
203
+ return {
204
+ port: this.port,
205
+ resourcePath: this.resourcePath,
206
+ buildInfo: {
207
+ productName: "opc-ua-server",
208
+ buildNumber: "1",
209
+ buildDate: new Date()
210
+ },
211
+ serverCapabilities: {
212
+ maxSessions: this.maxConnections
213
+ },
214
+ serverInfo: {
215
+ applicationName: { text: this.serverName },
216
+ applicationUri: buildApplicationUri(this.serverName),
217
+ productUri: "urn:node-red:opc-ua-server"
218
+ },
219
+ securityPolicies: [this.securityPolicy],
220
+ securityModes: [this.securityMode],
221
+ allowAnonymous: this.allowAnonymous,
222
+ userManager: {
223
+ isValidUser: (username, password) => this.isValidUser(username, password),
224
+ getUserRoles: (username) => this.getUserRoles(username)
225
+ },
226
+ userTokenPolicies
227
+ };
228
+ }
229
+
230
+ getUserRoles(username) {
231
+ const normalizedUserName = typeof username === "string" ? username.trim() : "";
232
+ if (!normalizedUserName || normalizedUserName.toLowerCase() === "anonymous") {
233
+ return makeRoles([WellKnownRoles.Anonymous]);
234
+ }
235
+
236
+ const user = this.users.find((entry) => entry && entry.username === normalizedUserName);
237
+ if (!user) {
238
+ return makeRoles([WellKnownRoles.AuthenticatedUser]);
239
+ }
240
+
241
+ const roles = [resolveNodeId("WellKnownRole_AuthenticatedUser")];
242
+ const groups = typeof user.group === "string"
243
+ ? user.group.split(",").map(g => g.trim()).filter(Boolean)
244
+ : Array.isArray(user.group)
245
+ ? user.group
246
+ : [];
247
+
248
+ groups.forEach((groupName) => {
249
+ const customRole = this.resolveGroupRoleNodeId(groupName);
250
+ if (customRole) {
251
+ roles.push(customRole);
252
+ }
253
+ });
254
+ return roles;
255
+ }
256
+
257
+ resolveGroupRoleNodeId(groupName) {
258
+ const normalized = String(groupName || "").trim().toLowerCase();
259
+ if (!normalized || normalized === "public") {
260
+ return null;
261
+ }
262
+
263
+ const wellKnownRoles = {
264
+ operator: "WellKnownRole_Operator",
265
+ supervisor: "WellKnownRole_Supervisor",
266
+ engineer: "WellKnownRole_Engineer",
267
+ engineering: "WellKnownRole_Engineer",
268
+ observer: "WellKnownRole_Observer",
269
+ admin: "WellKnownRole_ConfigureAdmin",
270
+ configureadmin: "WellKnownRole_ConfigureAdmin",
271
+ securityadmin: "WellKnownRole_SecurityAdmin"
272
+ };
273
+
274
+ if (wellKnownRoles[normalized]) {
275
+ return resolveNodeId(wellKnownRoles[normalized]);
276
+ }
277
+
278
+ return resolveNodeId("ns=1;s=NodeRedRole/" + this.sanitizeRoleSegment(normalized));
279
+ }
280
+
281
+ sanitizeRoleSegment(value) {
282
+ return String(value || "")
283
+ .trim()
284
+ .toLowerCase()
285
+ .replace(/\s+/g, "_")
286
+ .replace(/[^a-z0-9._-]/g, "_");
287
+ }
288
+
289
+ isValidUser(username, password) {
290
+ return this.users.some((user) => {
291
+ if (user.username !== username) {
292
+ return false;
293
+ }
294
+
295
+ if (user.password && user.password === password) {
296
+ return true;
297
+ }
298
+
299
+ if (user.passwordHash) {
300
+ if (!bcrypt) {
301
+ this.node.warn("bcryptjs is not installed, so hashed passwords cannot be validated.");
302
+ return false;
303
+ }
304
+ try {
305
+ return bcrypt.compareSync(password, user.passwordHash);
306
+ } catch (error) {
307
+ this.node.warn("Failed to validate password hash for user " + username + ": " + error.message);
308
+ return false;
309
+ }
310
+ }
311
+
312
+ return false;
313
+ });
314
+ }
315
+
316
+ initializeNamespaces(treeConfig) {
317
+ const addressSpace = this.server.engine.addressSpace;
318
+ const configuredNamespaces = this.buildNamespaceDefinitions(treeConfig);
319
+
320
+ this.namespaces = new Map();
321
+ this.namespaceDefinitions = configuredNamespaces;
322
+
323
+ configuredNamespaces.forEach((uri, namespaceId) => {
324
+ const namespace = addressSpace.getNamespace(uri) || addressSpace.registerNamespace(uri);
325
+ this.namespaces.set(namespaceId, namespace);
326
+ });
327
+
328
+ this.namespace = this.namespaces.get(2);
329
+ }
330
+
331
+ syncNamespaces(treeConfig) {
332
+ const addressSpace = this.server.engine.addressSpace;
333
+ const nextDefinitions = this.buildNamespaceDefinitions(treeConfig);
334
+
335
+ this.namespaceDefinitions.forEach((uri, namespaceId) => {
336
+ const nextUri = nextDefinitions.get(namespaceId);
337
+ if (nextUri && nextUri !== uri) {
338
+ throw new Error("Namespace URI changes require a redeploy: namespace " + namespaceId);
339
+ }
340
+
341
+ if (!nextUri) {
342
+ throw new Error("Removing namespaces requires a redeploy: namespace " + namespaceId);
343
+ }
344
+ });
345
+
346
+ nextDefinitions.forEach((uri, namespaceId) => {
347
+ if (this.namespaces.has(namespaceId)) {
348
+ return;
349
+ }
350
+
351
+ const namespace = addressSpace.getNamespace(uri) || addressSpace.registerNamespace(uri);
352
+ this.namespaces.set(namespaceId, namespace);
353
+ });
354
+
355
+ this.namespaceDefinitions = nextDefinitions;
356
+ this.namespace = this.namespaces.get(2);
357
+ }
358
+
359
+ buildNamespaceDefinitions(treeConfig) {
360
+ const definitions = new Map();
361
+ const configuredNamespaces = Array.isArray(treeConfig && treeConfig.nameSpaces) ? treeConfig.nameSpaces : [];
362
+ let defaultNamespaceUri = this.namespaceUri;
363
+
364
+ configuredNamespaces.forEach((namespaceConfig) => {
365
+ if (namespaceConfig.id === 2) {
366
+ defaultNamespaceUri = namespaceConfig.name;
367
+ }
368
+ });
369
+
370
+ definitions.set(2, defaultNamespaceUri);
371
+
372
+ configuredNamespaces
373
+ .slice()
374
+ .sort((left, right) => left.id - right.id)
375
+ .forEach((namespaceConfig) => {
376
+ definitions.set(namespaceConfig.id, namespaceConfig.name);
377
+ });
378
+
379
+ return definitions;
380
+ }
381
+ }
382
+
383
+ module.exports = {
384
+ OpcUaServerRuntime
385
+ };