node-opcua-samples 2.97.0 → 2.98.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/get_endpoints.d.ts +2 -2
- package/dist/get_endpoints.js +141 -141
- package/dist/mini_server.d.ts +1 -1
- package/dist/mini_server.js +88 -88
- package/dist/server_with_changing_password.d.ts +1 -1
- package/dist/server_with_changing_password.js +100 -100
- package/dist/server_with_push_certificate.d.ts +2 -2
- package/dist/server_with_push_certificate.js +111 -111
- package/dist/simple_client_ts.d.ts +2 -2
- package/dist/simple_client_ts.js +661 -661
- package/dist/simple_findservers.d.ts +2 -2
- package/dist/simple_findservers.js +48 -48
- package/dist/simple_secure_server.d.ts +2 -2
- package/dist/simple_secure_server.js +125 -125
- package/dist/simple_server_with_custom_extension_objects.d.ts +2 -2
- package/dist/simple_server_with_custom_extension_objects.js +81 -81
- package/dist/stressing_client.d.ts +1 -1
- package/dist/stressing_client.js +36 -36
- package/dist/tiny_client.d.ts +1 -1
- package/dist/tiny_client.js +32 -32
- package/package.json +15 -12
- package/bin/createOPCUACertificate.cmd +0 -6
- package/bin/create_certificates.js +0 -2
- package/bin/crypto_create_CA.js +0 -2
- package/bin/demo_server_with_alarm.js +0 -51
- package/bin/findServersOnNetwork.js +0 -32
- package/bin/get_endpoints.ts +0 -166
- package/bin/machineryServer.js +0 -83
- package/bin/mini_server.ts +0 -106
- package/bin/more.js +0 -40
- package/bin/node-opcua.js +0 -2
- package/bin/opcua_interceptor.js +0 -122
- package/bin/server_with_changing_password.ts +0 -97
- package/bin/server_with_push_certificate.ts +0 -122
- package/bin/simple_client.js +0 -830
- package/bin/simple_client_ts.ts +0 -847
- package/bin/simple_findservers.ts +0 -45
- package/bin/simple_secure_server.ts +0 -152
- package/bin/simple_server_with_custom_extension_objects.ts +0 -89
- package/bin/stressing_client.ts +0 -28
- package/bin/tiny_client.ts +0 -24
package/bin/simple_client.js
DELETED
|
@@ -1,830 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/* eslint-disable max-statements */
|
|
3
|
-
/* eslint-disable no-prototype-builtins */
|
|
4
|
-
// PLEASE use simple_client_ts.ts , simple_client_ts presents a more modern approach...*
|
|
5
|
-
const fs = require("fs");
|
|
6
|
-
const path = require("path");
|
|
7
|
-
const util = require("util");
|
|
8
|
-
const treeify = require("treeify");
|
|
9
|
-
const chalk = require("chalk");
|
|
10
|
-
const Table = require("easy-table");
|
|
11
|
-
const {
|
|
12
|
-
ApplicationType,
|
|
13
|
-
assert,
|
|
14
|
-
AttributeIds,
|
|
15
|
-
BrowseDirection,
|
|
16
|
-
callConditionRefresh,
|
|
17
|
-
ClientMonitoredItem,
|
|
18
|
-
coerceMessageSecurityMode,
|
|
19
|
-
coerceNodeId,
|
|
20
|
-
coerceSecurityPolicy,
|
|
21
|
-
constructEventFilter,
|
|
22
|
-
dumpEvent,
|
|
23
|
-
hexDump,
|
|
24
|
-
makeExpandedNodeId,
|
|
25
|
-
makeNodeId,
|
|
26
|
-
MessageSecurityMode,
|
|
27
|
-
NodeClassMask,
|
|
28
|
-
NodeCrawler,
|
|
29
|
-
NodeId,
|
|
30
|
-
ObjectTypeIds,
|
|
31
|
-
OPCUAClient,
|
|
32
|
-
resolveNodeId,
|
|
33
|
-
SecurityPolicy,
|
|
34
|
-
VariableIds,
|
|
35
|
-
ObjectIds,
|
|
36
|
-
UserTokenType,
|
|
37
|
-
} = require("node-opcua");
|
|
38
|
-
const { toPem } = require("node-opcua-crypto");
|
|
39
|
-
|
|
40
|
-
//node bin/simple_client.js --endpoint opc.tcp://localhost:53530/OPCUA/SimulationServer --node "ns=5;s=Sinusoid1"
|
|
41
|
-
const yargs = require("yargs/yargs");
|
|
42
|
-
const argv = yargs(process.argv)
|
|
43
|
-
.wrap(132)
|
|
44
|
-
// .usage("Usage: $0 -d --endpoint <endpointUrl> [--securityMode (None|SignAndEncrypt|Sign)] [--securityPolicy (None|Basic256|Basic128Rsa15)] --node <node_id_to_monitor> --crawl")
|
|
45
|
-
|
|
46
|
-
.option("endpoint", {
|
|
47
|
-
alias: "e",
|
|
48
|
-
demandOption: true,
|
|
49
|
-
describe: "the end point to connect to "
|
|
50
|
-
})
|
|
51
|
-
.option("securityMode", {
|
|
52
|
-
alias: "s",
|
|
53
|
-
default: "None",
|
|
54
|
-
describe: "the security mode ( None Sign SignAndEncrypt )"
|
|
55
|
-
})
|
|
56
|
-
.option("securityPolicy", {
|
|
57
|
-
alias: "P",
|
|
58
|
-
default: "None",
|
|
59
|
-
describe: "the policy mode : (" + Object.keys(SecurityPolicy).join(" - ") + ")"
|
|
60
|
-
})
|
|
61
|
-
.option("userName", {
|
|
62
|
-
alias: "u",
|
|
63
|
-
describe: "specify the user name of a UserNameIdentityToken"
|
|
64
|
-
})
|
|
65
|
-
.option("password", {
|
|
66
|
-
alias: "p",
|
|
67
|
-
describe: "specify the password of a UserNameIdentityToken"
|
|
68
|
-
})
|
|
69
|
-
.option("node", {
|
|
70
|
-
alias: "n",
|
|
71
|
-
describe: "the nodeId of the value to monitor"
|
|
72
|
-
})
|
|
73
|
-
.option("timeout", {
|
|
74
|
-
alias: "t",
|
|
75
|
-
describe: " the timeout of the session in second => (-1 for infinity)"
|
|
76
|
-
})
|
|
77
|
-
.option("debug", {
|
|
78
|
-
alias: "d",
|
|
79
|
-
boolean: true,
|
|
80
|
-
describe: " display more verbose information"
|
|
81
|
-
})
|
|
82
|
-
.option("history", {
|
|
83
|
-
alias: "h",
|
|
84
|
-
describe: "make an historical read"
|
|
85
|
-
})
|
|
86
|
-
.option("crawl", {
|
|
87
|
-
alias: "c",
|
|
88
|
-
describe: "crawl"
|
|
89
|
-
})
|
|
90
|
-
.option("discovery", {
|
|
91
|
-
alias: "D",
|
|
92
|
-
describe: "specify the endpoint uri of discovery server (by default same as server endpoint uri)"
|
|
93
|
-
})
|
|
94
|
-
.example("simple_client --endpoint opc.tcp://localhost:49230 -P=Basic256Rsa256 -s=Sign", "")
|
|
95
|
-
.example("simple_client -e opc.tcp://localhost:49230 -P=Basic256Sha256 -s=Sign -u JoeDoe -p P@338@rd ", "")
|
|
96
|
-
.example("simple_client --endpoint opc.tcp://localhost:49230 -n=\"ns=0;i=2258\"", "")
|
|
97
|
-
.argv;
|
|
98
|
-
|
|
99
|
-
const securityMode = coerceMessageSecurityMode(argv.securityMode);
|
|
100
|
-
if (securityMode === MessageSecurityMode.Invalid) {
|
|
101
|
-
throw new Error("Invalid Security mode");
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const securityPolicy = coerceSecurityPolicy(argv.securityPolicy);
|
|
105
|
-
if (securityPolicy === SecurityPolicy.Invalid) {
|
|
106
|
-
throw new Error("Invalid securityPolicy");
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const timeout = argv.timeout * 1000 || 20000;
|
|
110
|
-
|
|
111
|
-
const monitored_node = coerceNodeId(argv.node ||
|
|
112
|
-
makeNodeId(VariableIds.Server_ServerStatus_CurrentTime));
|
|
113
|
-
|
|
114
|
-
console.log(chalk.cyan("securityMode = "), securityMode.toString());
|
|
115
|
-
console.log(chalk.cyan("securityPolicy = "), securityPolicy.toString());
|
|
116
|
-
console.log(chalk.cyan("timeout = "), timeout ? timeout : " Infinity ");
|
|
117
|
-
console.log(" monitoring node id = ", monitored_node);
|
|
118
|
-
|
|
119
|
-
const endpointUrl = argv.endpoint;
|
|
120
|
-
|
|
121
|
-
if (!endpointUrl) {
|
|
122
|
-
yargs.showHelp();
|
|
123
|
-
process.exit(0);
|
|
124
|
-
}
|
|
125
|
-
const discoveryUrl = argv.discovery ? argv.discovery : endpointUrl;
|
|
126
|
-
|
|
127
|
-
const doCrawling = !!argv.crawl;
|
|
128
|
-
const doHistory = !!argv.history;
|
|
129
|
-
|
|
130
|
-
function w(str, l) {
|
|
131
|
-
return str.padEnd(l).substring(0, l);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async function enumerateAllConditionTypes(session) {
|
|
135
|
-
|
|
136
|
-
const tree = {};
|
|
137
|
-
|
|
138
|
-
const conditionEventTypes = {};
|
|
139
|
-
|
|
140
|
-
async function findAllNodeOfType(
|
|
141
|
-
tree1,
|
|
142
|
-
typeNodeId1,
|
|
143
|
-
browseName
|
|
144
|
-
) {
|
|
145
|
-
|
|
146
|
-
const browseDesc1 = {
|
|
147
|
-
nodeId: typeNodeId1,
|
|
148
|
-
referenceTypeId: resolveNodeId("HasSubtype"),
|
|
149
|
-
|
|
150
|
-
browseDirection: BrowseDirection.Forward,
|
|
151
|
-
includeSubtypes: true,
|
|
152
|
-
resultMask: 63
|
|
153
|
-
|
|
154
|
-
};
|
|
155
|
-
const browseDesc2 = {
|
|
156
|
-
nodeId: typeNodeId1,
|
|
157
|
-
referenceTypeId: resolveNodeId("HasTypeDefinition"),
|
|
158
|
-
|
|
159
|
-
browseDirection: BrowseDirection.Inverse,
|
|
160
|
-
includeSubtypes: true,
|
|
161
|
-
resultMask: 63
|
|
162
|
-
|
|
163
|
-
};
|
|
164
|
-
const browseDesc3 = {
|
|
165
|
-
nodeId: typeNodeId1,
|
|
166
|
-
referenceTypeId: resolveNodeId("HasTypeDefinition"),
|
|
167
|
-
|
|
168
|
-
browseDirection: BrowseDirection.Forward,
|
|
169
|
-
includeSubtypes: true,
|
|
170
|
-
resultMask: 63
|
|
171
|
-
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
const nodesToBrowse = [
|
|
175
|
-
browseDesc1,
|
|
176
|
-
browseDesc2,
|
|
177
|
-
browseDesc3
|
|
178
|
-
];
|
|
179
|
-
const browseResults = await session.browse(nodesToBrowse);
|
|
180
|
-
|
|
181
|
-
tree1[browseName] = {};
|
|
182
|
-
browseResults[0].references = browseResults[0].references || [];
|
|
183
|
-
const promises = [];
|
|
184
|
-
for (const reference of browseResults[0].references) {
|
|
185
|
-
conditionEventTypes[reference.nodeId.toString()] = reference.browseName.toString();
|
|
186
|
-
promises.push(findAllNodeOfType(tree1[browseName], reference.nodeId, reference.browseName.toString()));
|
|
187
|
-
}
|
|
188
|
-
await Promise.all(promises);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const typeNodeId = resolveNodeId("ConditionType");
|
|
192
|
-
|
|
193
|
-
await findAllNodeOfType(tree, typeNodeId, "ConditionType");
|
|
194
|
-
|
|
195
|
-
return tree;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
async function enumerateAllAlarmAndConditionInstances(session) {
|
|
199
|
-
|
|
200
|
-
const conditions = {};
|
|
201
|
-
|
|
202
|
-
const found = [];
|
|
203
|
-
|
|
204
|
-
function isConditionEventType(nodeId) {
|
|
205
|
-
return conditions.hasOwnProperty(nodeId.toString());
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
async function exploreForObjectOfType(session1, nodeId) {
|
|
209
|
-
|
|
210
|
-
async function worker(element) {
|
|
211
|
-
|
|
212
|
-
const nodeToBrowse = {
|
|
213
|
-
nodeId: element.nodeId,
|
|
214
|
-
referenceTypeId: resolveNodeId("HierarchicalReferences"),
|
|
215
|
-
|
|
216
|
-
browseDirection: BrowseDirection.Forward,
|
|
217
|
-
includeSubtypes: true,
|
|
218
|
-
nodeClassMask: 0x1, // Objects
|
|
219
|
-
resultMask: 63
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
const browseResult = await session1.browse(nodeToBrowse);
|
|
223
|
-
|
|
224
|
-
for (const ref of browseResult.references) {
|
|
225
|
-
if (isConditionEventType(ref.typeDefinition)) {
|
|
226
|
-
//
|
|
227
|
-
const alarm = {
|
|
228
|
-
parent: element.nodeId,
|
|
229
|
-
|
|
230
|
-
alarmNodeId: ref.nodeId,
|
|
231
|
-
browseName: ref.browseName,
|
|
232
|
-
typeDefinition: ref.typeDefinition,
|
|
233
|
-
typeDefinitionName: conditions[ref.typeDefinition.toString()]
|
|
234
|
-
};
|
|
235
|
-
found.push(alarm);
|
|
236
|
-
|
|
237
|
-
} else {
|
|
238
|
-
await worker(ref.nodeId);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
await worker(nodeId);
|
|
244
|
-
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
await enumerateAllConditionTypes(session);
|
|
248
|
-
|
|
249
|
-
await exploreForObjectOfType(session, resolveNodeId("RootFolder"));
|
|
250
|
-
|
|
251
|
-
return Object.values(conditions);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
async function _getAllEventTypes(session, baseNodeId, tree) {
|
|
255
|
-
|
|
256
|
-
const browseDesc1 = {
|
|
257
|
-
nodeId: baseNodeId,
|
|
258
|
-
referenceTypeId: resolveNodeId("HasSubtype"),
|
|
259
|
-
|
|
260
|
-
browseDirection: BrowseDirection.Forward,
|
|
261
|
-
includeSubtypes: true,
|
|
262
|
-
nodeClassMask: NodeClassMask.ObjectType, // Objects
|
|
263
|
-
resultMask: 63
|
|
264
|
-
};
|
|
265
|
-
const browseResult = await session.browse(browseDesc1);
|
|
266
|
-
|
|
267
|
-
// to do continuation points
|
|
268
|
-
for (const reference of browseResult.references) {
|
|
269
|
-
const subtree = { nodeId: reference.nodeId.toString() };
|
|
270
|
-
tree[reference.browseName.toString()] = subtree;
|
|
271
|
-
await _getAllEventTypes(session, reference.nodeId, subtree);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* getAllEventType recursively
|
|
277
|
-
*/
|
|
278
|
-
async function getAllEventTypes(session) {
|
|
279
|
-
|
|
280
|
-
const baseNodeId = makeNodeId(ObjectTypeIds.BaseEventType);
|
|
281
|
-
const result = {};
|
|
282
|
-
await _getAllEventTypes(session, baseNodeId, result);
|
|
283
|
-
return result;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
async function monitorAlarm(subscription) {
|
|
287
|
-
try {
|
|
288
|
-
await callConditionRefresh(subscription);
|
|
289
|
-
} catch (err) {
|
|
290
|
-
console.log(" monitorAlarm failed , may be your server doesn't support A&E", err.message);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
function getTick() {
|
|
295
|
-
return Date.now();
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
let the_subscription;
|
|
299
|
-
let the_session;
|
|
300
|
-
let client;
|
|
301
|
-
|
|
302
|
-
async function main() {
|
|
303
|
-
|
|
304
|
-
const optionsInitial = {
|
|
305
|
-
|
|
306
|
-
securityMode,
|
|
307
|
-
securityPolicy,
|
|
308
|
-
|
|
309
|
-
endpointMustExist: false,
|
|
310
|
-
keepSessionAlive: true,
|
|
311
|
-
|
|
312
|
-
connectionStrategy: {
|
|
313
|
-
initialDelay: 2000,
|
|
314
|
-
maxDelay: 10 * 1000,
|
|
315
|
-
maxRetry: 10
|
|
316
|
-
},
|
|
317
|
-
|
|
318
|
-
discoveryUrl
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
client = OPCUAClient.create(optionsInitial);
|
|
322
|
-
|
|
323
|
-
client.on("backoff", (retry, delay) => {
|
|
324
|
-
console.log(chalk.bgWhite.yellow("backoff attempt #"), retry, " retrying in ", delay / 1000.0, " seconds");
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
console.log(" connecting to ", chalk.cyan.bold(endpointUrl));
|
|
328
|
-
console.log(" strategy", client.connectionStrategy);
|
|
329
|
-
|
|
330
|
-
try {
|
|
331
|
-
await client.connect(endpointUrl);
|
|
332
|
-
console.log(" Connected ! exact endpoint url is ", client.endpointUrl);
|
|
333
|
-
|
|
334
|
-
} catch (err) {
|
|
335
|
-
console.log(chalk.red(" Cannot connect to ") + endpointUrl);
|
|
336
|
-
console.log(" Error = ", err.message);
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
const endpoints = await client.getEndpoints();
|
|
341
|
-
|
|
342
|
-
if (argv.debug) {
|
|
343
|
-
fs.writeFileSync("tmp/endpoints.log", JSON.stringify(endpoints, null, " "));
|
|
344
|
-
endpoints.forEach((a) => a.serverCertificate = a.serverCertificate.toString("base64"));
|
|
345
|
-
console.log(treeify.asTree(endpoints, true));
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
const table = new Table();
|
|
349
|
-
|
|
350
|
-
let serverCertificate;
|
|
351
|
-
|
|
352
|
-
let i = 0;
|
|
353
|
-
for (const endpoint of endpoints) {
|
|
354
|
-
table.cell("endpoint", endpoint.endpointUrl + "");
|
|
355
|
-
table.cell("Application URI", endpoint.server.applicationUri);
|
|
356
|
-
table.cell("Product URI", endpoint.server.productUri);
|
|
357
|
-
table.cell("Application Name", endpoint.server.applicationName.text);
|
|
358
|
-
table.cell("Security Mode", MessageSecurityMode[endpoint.securityMode].toString());
|
|
359
|
-
table.cell("securityPolicyUri", endpoint.securityPolicyUri);
|
|
360
|
-
table.cell("Type", ApplicationType[endpoint.server.applicationType]);
|
|
361
|
-
table.cell("certificate", "..." /*endpoint.serverCertificate*/);
|
|
362
|
-
endpoint.server.discoveryUrls = endpoint.server.discoveryUrls || [];
|
|
363
|
-
table.cell("discoveryUrls", endpoint.server.discoveryUrls.join(" - "));
|
|
364
|
-
|
|
365
|
-
serverCertificate = endpoint.serverCertificate;
|
|
366
|
-
|
|
367
|
-
const certificate_filename = path.join(__dirname, "../certificates/PKI/server_certificate" + i + ".pem");
|
|
368
|
-
|
|
369
|
-
if (serverCertificate) {
|
|
370
|
-
fs.writeFile(certificate_filename, toPem(serverCertificate, "CERTIFICATE"), () => {/**/
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
table.newRow();
|
|
374
|
-
i++;
|
|
375
|
-
}
|
|
376
|
-
console.log(table.toString());
|
|
377
|
-
|
|
378
|
-
for (const endpoint of endpoints) {
|
|
379
|
-
console.log("Identify Token for : Security Mode=", endpoint.securityMode.toString(), " Policy=", endpoint.securityPolicyUri);
|
|
380
|
-
const table2 = new Table();
|
|
381
|
-
for (const token of endpoint.userIdentityTokens) {
|
|
382
|
-
table2.cell("policyId", token.policyId);
|
|
383
|
-
table2.cell("tokenType", token.tokenType.toString());
|
|
384
|
-
table2.cell("issuedTokenType", token.issuedTokenType);
|
|
385
|
-
table2.cell("issuerEndpointUrl", token.issuerEndpointUrl);
|
|
386
|
-
table2.cell("securityPolicyUri", token.securityPolicyUri);
|
|
387
|
-
table2.newRow();
|
|
388
|
-
}
|
|
389
|
-
console.log(table2.toString());
|
|
390
|
-
}
|
|
391
|
-
await client.disconnect();
|
|
392
|
-
|
|
393
|
-
// reconnect using the correct end point URL now
|
|
394
|
-
console.log(chalk.cyan("Server Certificate :"));
|
|
395
|
-
console.log(chalk.yellow(hexDump(serverCertificate)));
|
|
396
|
-
|
|
397
|
-
const adjustedEndpointUrl = client.endpointUrl;
|
|
398
|
-
|
|
399
|
-
const options = {
|
|
400
|
-
securityMode,
|
|
401
|
-
securityPolicy,
|
|
402
|
-
|
|
403
|
-
// we provide here server certificate , so it is important to connect with proper endpoint Url
|
|
404
|
-
// serverCertificate,
|
|
405
|
-
|
|
406
|
-
defaultSecureTokenLifetime: 40000,
|
|
407
|
-
|
|
408
|
-
endpointMustExist: false,
|
|
409
|
-
|
|
410
|
-
connectionStrategy: {
|
|
411
|
-
initialDelay: 2000,
|
|
412
|
-
maxDelay: 10 * 1000,
|
|
413
|
-
maxRetry: 10
|
|
414
|
-
}
|
|
415
|
-
};
|
|
416
|
-
console.log("Options = ", options.securityMode.toString(), options.securityPolicy.toString());
|
|
417
|
-
|
|
418
|
-
client = OPCUAClient.create(options);
|
|
419
|
-
|
|
420
|
-
console.log(" reconnecting to ", chalk.cyan.bold(adjustedEndpointUrl));
|
|
421
|
-
await client.connect(adjustedEndpointUrl);
|
|
422
|
-
|
|
423
|
-
console.log(" Connected ! exact endpoint url is ", client.endpointUrl);
|
|
424
|
-
|
|
425
|
-
let userIdentity; // anonymous
|
|
426
|
-
if (argv.userName && argv.password) {
|
|
427
|
-
|
|
428
|
-
userIdentity = {
|
|
429
|
-
password: argv.password,
|
|
430
|
-
userName: argv.userName,
|
|
431
|
-
type: UserTokenType.UserName
|
|
432
|
-
};
|
|
433
|
-
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
the_session = await client.createSession(userIdentity);
|
|
437
|
-
client.on("connection_reestablished", () => {
|
|
438
|
-
console.log(chalk.bgWhite.red(" !!!!!!!!!!!!!!!!!!!!!!!! CONNECTION RE-ESTABLISHED !!!!!!!!!!!!!!!!!!!"));
|
|
439
|
-
});
|
|
440
|
-
console.log(chalk.yellow(" session created"));
|
|
441
|
-
console.log(" sessionId : ", the_session.sessionId.toString());
|
|
442
|
-
|
|
443
|
-
client.on("backoff", (retry, delay) => {
|
|
444
|
-
console.log(chalk.bgWhite.yellow("backoff attempt #"), retry, " retrying in ", delay / 1000.0, " seconds");
|
|
445
|
-
});
|
|
446
|
-
client.on("start_reconnection", () => {
|
|
447
|
-
console.log(chalk.bgWhite.red(" !!!!!!!!!!!!!!!!!!!!!!!! Starting Reconnection !!!!!!!!!!!!!!!!!!!"));
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
// -----------------------------------------------------------------------------------------------------------
|
|
451
|
-
// NAMESPACE
|
|
452
|
-
// display namespace array
|
|
453
|
-
// -----------------------------------------------------------------------------------------------------------
|
|
454
|
-
const server_NamespaceArray_Id = makeNodeId(VariableIds.Server_NamespaceArray); // ns=0;i=2006
|
|
455
|
-
|
|
456
|
-
const dataValue = await the_session.readVariableValue(server_NamespaceArray_Id);
|
|
457
|
-
|
|
458
|
-
console.log(" --- NAMESPACE ARRAY ---");
|
|
459
|
-
const namespaceArray = dataValue.value.value /*as string[] */;
|
|
460
|
-
namespaceArray.forEach((namespace, index) => {
|
|
461
|
-
console.log(" Namespace ", index, " : ", namespace);
|
|
462
|
-
});
|
|
463
|
-
console.log(" -----------------------");
|
|
464
|
-
|
|
465
|
-
// -----------------------------------------------------------------------------------------------------------
|
|
466
|
-
// enumerate all EVENT TYPES
|
|
467
|
-
// -----------------------------------------------------------------------------------------------------------
|
|
468
|
-
const result = getAllEventTypes(the_session);
|
|
469
|
-
console.log(chalk.cyan("---------------------------------------------------- All Event Types "));
|
|
470
|
-
console.log(treeify.asTree(result, true));
|
|
471
|
-
console.log(" -----------------------");
|
|
472
|
-
|
|
473
|
-
// -----------------------------------------------------------------------------------------------------------
|
|
474
|
-
// Node Crawling
|
|
475
|
-
// -----------------------------------------------------------------------------------------------------------
|
|
476
|
-
let t1;
|
|
477
|
-
let t2;
|
|
478
|
-
|
|
479
|
-
function print_stat() {
|
|
480
|
-
try {
|
|
481
|
-
|
|
482
|
-
t2 = Date.now();
|
|
483
|
-
const str = util.format("R= %d W= %d T=%d t= %d",
|
|
484
|
-
client.bytesRead, client.bytesWritten, client.transactionsPerformed, (t2 - t1));
|
|
485
|
-
console.log(chalk.yellow.bold(str));
|
|
486
|
-
} catch (err) {
|
|
487
|
-
console.log("err =", err);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
if (doCrawling) {
|
|
492
|
-
assert((the_session !== null && typeof the_session === "object"));
|
|
493
|
-
const crawler = new NodeCrawler(the_session);
|
|
494
|
-
|
|
495
|
-
let t5 = Date.now();
|
|
496
|
-
client.on("send_request", () => {
|
|
497
|
-
t1 = Date.now();
|
|
498
|
-
});
|
|
499
|
-
|
|
500
|
-
client.on("receive_response", print_stat);
|
|
501
|
-
|
|
502
|
-
t5 = Date.now();
|
|
503
|
-
crawler.on("browsed", function(element) {
|
|
504
|
-
try {
|
|
505
|
-
console.log("->", (new Date()).getTime() - t, element.browseName.name, element.nodeId.toString());
|
|
506
|
-
} catch (err) {
|
|
507
|
-
console.log("err =", err);
|
|
508
|
-
}
|
|
509
|
-
});
|
|
510
|
-
|
|
511
|
-
const nodeId = resolveNodeId(ObjectIds.Server);
|
|
512
|
-
console.log("now crawling object folder ...please wait...");
|
|
513
|
-
|
|
514
|
-
const obj = await crawler.read(nodeId);
|
|
515
|
-
|
|
516
|
-
console.log(" Time = ", (new Date()).getTime() - t5);
|
|
517
|
-
console.log(" read = ", crawler.readCounter);
|
|
518
|
-
console.log(" browse = ", crawler.browseCounter);
|
|
519
|
-
console.log(" browseNext = ", crawler.browseNextCounter);
|
|
520
|
-
console.log(" transaction = ", crawler.transactionCounter);
|
|
521
|
-
if (true) {
|
|
522
|
-
// todo : treeify.asTree performance is *very* slow on large object, replace with better implementation
|
|
523
|
-
// xx console.log(treeify.asTree(obj, true));
|
|
524
|
-
treeify.asLines(obj, true, true, (line) => {
|
|
525
|
-
console.log(line);
|
|
526
|
-
});
|
|
527
|
-
}
|
|
528
|
-
crawler.dispose();
|
|
529
|
-
}
|
|
530
|
-
client.removeListener("receive_response", print_stat);
|
|
531
|
-
|
|
532
|
-
// -----------------------------------------------------------------------------------------------------------------
|
|
533
|
-
// enumerate all Condition Types exposed by the server
|
|
534
|
-
// -----------------------------------------------------------------------------------------------------------------
|
|
535
|
-
|
|
536
|
-
console.log("--------------------------------------------------------------- Enumerate all Condition Types exposed by the server");
|
|
537
|
-
const conditionTree = await enumerateAllConditionTypes(the_session);
|
|
538
|
-
console.log(treeify.asTree(conditionTree));
|
|
539
|
-
console.log(" -----------------------------------------------------------------------------------------------------------------");
|
|
540
|
-
|
|
541
|
-
// -----------------------------------------------------------------------------------------------------------------
|
|
542
|
-
// enumerate all objects that have an Alarm & Condition instances
|
|
543
|
-
// -----------------------------------------------------------------------------------------------------------------
|
|
544
|
-
|
|
545
|
-
const alarms = await enumerateAllAlarmAndConditionInstances(the_session);
|
|
546
|
-
|
|
547
|
-
console.log(" -------------------------------------------------------------- Alarms & Conditions ------------------------");
|
|
548
|
-
for (const alarm of alarms) {
|
|
549
|
-
console.log(
|
|
550
|
-
"parent = ",
|
|
551
|
-
chalk.cyan(w(alarm.parent.toString(), 30)),
|
|
552
|
-
chalk.green.bold(w(alarm.typeDefinitionName, 30)),
|
|
553
|
-
"alarmName = ",
|
|
554
|
-
chalk.cyan(w(alarm.browseName.toString(), 30)),
|
|
555
|
-
chalk.yellow(w(alarm.alarmNodeId.toString(), 40))
|
|
556
|
-
);
|
|
557
|
-
}
|
|
558
|
-
console.log(" -----------------------------------------------------------------------------------------------------------------");
|
|
559
|
-
|
|
560
|
-
// -----------------------------------------------------------------------------------------------------------------
|
|
561
|
-
// Testing if server implements QueryFirst
|
|
562
|
-
// -----------------------------------------------------------------------------------------------------------------
|
|
563
|
-
try {
|
|
564
|
-
console.log(" ---------------------------------------------------------- Testing QueryFirst");
|
|
565
|
-
const queryFirstRequest = {
|
|
566
|
-
view: {
|
|
567
|
-
viewId: NodeId.nullNodeId
|
|
568
|
-
},
|
|
569
|
-
|
|
570
|
-
nodeTypes: [
|
|
571
|
-
{
|
|
572
|
-
typeDefinitionNode: makeExpandedNodeId("i=58"),
|
|
573
|
-
|
|
574
|
-
includeSubTypes: true,
|
|
575
|
-
|
|
576
|
-
dataToReturn: [{
|
|
577
|
-
|
|
578
|
-
attributeId: AttributeIds.AccessLevel,
|
|
579
|
-
relativePath: undefined
|
|
580
|
-
}]
|
|
581
|
-
}
|
|
582
|
-
]
|
|
583
|
-
};
|
|
584
|
-
|
|
585
|
-
console.log(" -----------------------------------------------------------------------------------------------------------------");
|
|
586
|
-
} catch (err) {
|
|
587
|
-
console.log(" Server is not supporting queryFirst err=", err.message);
|
|
588
|
-
}
|
|
589
|
-
// create Read
|
|
590
|
-
if (doHistory) {
|
|
591
|
-
|
|
592
|
-
console.log(" ---------------------------------------------------------- History Read------------------------");
|
|
593
|
-
const now = Date.now();
|
|
594
|
-
const start = now - 1000; // read 1 seconds of history
|
|
595
|
-
console.log(" -----------------------------------------------------------------------------------------------------------------");
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
// ----------------------------------------------------------------------------------
|
|
599
|
-
// create subscription
|
|
600
|
-
// ----------------------------------------------------------------------------------
|
|
601
|
-
console.log(" ---------------------------------------------------------- Create Subscription ");
|
|
602
|
-
const parameters = {
|
|
603
|
-
maxNotificationsPerPublish: 10,
|
|
604
|
-
priority: 10,
|
|
605
|
-
publishingEnabled: true,
|
|
606
|
-
requestedLifetimeCount: 1000,
|
|
607
|
-
requestedMaxKeepAliveCount: 12,
|
|
608
|
-
requestedPublishingInterval: 2000
|
|
609
|
-
};
|
|
610
|
-
|
|
611
|
-
the_subscription = await the_session.createSubscription2(parameters);
|
|
612
|
-
|
|
613
|
-
let t = getTick();
|
|
614
|
-
|
|
615
|
-
console.log("started subscription :", the_subscription.subscriptionId);
|
|
616
|
-
console.log(" revised parameters ");
|
|
617
|
-
console.log(" revised maxKeepAliveCount ", the_subscription.maxKeepAliveCount, " ( requested ", parameters.requestedMaxKeepAliveCount + ")");
|
|
618
|
-
console.log(" revised lifetimeCount ", the_subscription.lifetimeCount, " ( requested ", parameters.requestedLifetimeCount + ")");
|
|
619
|
-
console.log(" revised publishingInterval ", the_subscription.publishingInterval, " ( requested ", parameters.requestedPublishingInterval + ")");
|
|
620
|
-
|
|
621
|
-
console.log("subscription duration ",
|
|
622
|
-
((the_subscription.lifetimeCount * the_subscription.publishingInterval) / 1000).toFixed(3), "seconds")
|
|
623
|
-
the_subscription.on("internal_error", (err) => {
|
|
624
|
-
console.log(" received internal error", err.message);
|
|
625
|
-
}).on("keepalive", () => {
|
|
626
|
-
const t4 = getTick();
|
|
627
|
-
const span = t4 - t;
|
|
628
|
-
t = t4;
|
|
629
|
-
console.log("keepalive ", span / 1000, "sec",
|
|
630
|
-
" pending request on server = ", the_subscription.getPublishEngine().nbPendingPublishRequests);
|
|
631
|
-
|
|
632
|
-
}).on("terminated", () => { /* */
|
|
633
|
-
|
|
634
|
-
console.log("Subscription is terminated ....")
|
|
635
|
-
});
|
|
636
|
-
|
|
637
|
-
try {
|
|
638
|
-
const results1 = await the_subscription.getMonitoredItems();
|
|
639
|
-
console.log("MonitoredItems clientHandles", results1.clientHandles);
|
|
640
|
-
console.log("MonitoredItems serverHandles", results1.serverHandles);
|
|
641
|
-
} catch (err) {
|
|
642
|
-
console.log("Server doesn't seems to implement getMonitoredItems method ", err.message);
|
|
643
|
-
}
|
|
644
|
-
// get_monitored_item
|
|
645
|
-
|
|
646
|
-
// monitor_a_variable_node_value
|
|
647
|
-
console.log("Monitoring monitor_a_variable_node_value");
|
|
648
|
-
|
|
649
|
-
// ---------------------------------------------------------------
|
|
650
|
-
// monitor a variable node value
|
|
651
|
-
// ---------------------------------------------------------------
|
|
652
|
-
console.log(" Monitoring node ", monitored_node.toString());
|
|
653
|
-
const monitoredItem = ClientMonitoredItem.create(
|
|
654
|
-
the_subscription,
|
|
655
|
-
{
|
|
656
|
-
attributeId: AttributeIds.Value,
|
|
657
|
-
nodeId: monitored_node
|
|
658
|
-
},
|
|
659
|
-
{
|
|
660
|
-
discardOldest: true,
|
|
661
|
-
queueSize: 10000,
|
|
662
|
-
samplingInterval: 1000
|
|
663
|
-
// xx filter: { parameterTypeId: "ns=0;i=0", encodingMask: 0 },
|
|
664
|
-
}
|
|
665
|
-
);
|
|
666
|
-
monitoredItem.on("initialized", () => {
|
|
667
|
-
console.log("monitoredItem initialized");
|
|
668
|
-
});
|
|
669
|
-
monitoredItem.on("changed", (dataValue1) => {
|
|
670
|
-
console.log(monitoredItem.itemToMonitor.nodeId.toString(), " value has changed to " + dataValue1.value.toString());
|
|
671
|
-
});
|
|
672
|
-
monitoredItem.on("err", (err_message) => {
|
|
673
|
-
console.log(monitoredItem.itemToMonitor.nodeId.toString(), chalk.red(" ERROR"), err_message);
|
|
674
|
-
});
|
|
675
|
-
|
|
676
|
-
const results = await the_subscription.getMonitoredItems();
|
|
677
|
-
console.log("MonitoredItems clientHandles", results.clientHandles);
|
|
678
|
-
console.log("MonitoredItems serverHandles", results.serverHandles);
|
|
679
|
-
|
|
680
|
-
console.log("Monitoring monitor_the_object_events");
|
|
681
|
-
|
|
682
|
-
// ---------------------------------------------------------------
|
|
683
|
-
// monitor the object events
|
|
684
|
-
// ---------------------------------------------------------------
|
|
685
|
-
|
|
686
|
-
const baseEventTypeId = "i=2041"; // BaseEventType;
|
|
687
|
-
const serverObjectId = "i=2253";
|
|
688
|
-
|
|
689
|
-
const fields = [
|
|
690
|
-
"EventId",
|
|
691
|
-
"EventType",
|
|
692
|
-
"SourceNode",
|
|
693
|
-
"SourceName",
|
|
694
|
-
"Time",
|
|
695
|
-
"ReceiveTime",
|
|
696
|
-
"Message",
|
|
697
|
-
"Severity",
|
|
698
|
-
|
|
699
|
-
// ConditionType
|
|
700
|
-
"ConditionClassId",
|
|
701
|
-
"ConditionClassName",
|
|
702
|
-
"ConditionName",
|
|
703
|
-
"BranchId",
|
|
704
|
-
"Retain",
|
|
705
|
-
"EnabledState",
|
|
706
|
-
"Quality",
|
|
707
|
-
"LastSeverity",
|
|
708
|
-
"Comment",
|
|
709
|
-
"ClientUserId",
|
|
710
|
-
|
|
711
|
-
// AcknowledgeConditionType
|
|
712
|
-
"AckedState",
|
|
713
|
-
"ConfirmedState",
|
|
714
|
-
|
|
715
|
-
// AlarmConditionType
|
|
716
|
-
"ActiveState",
|
|
717
|
-
"InputNode",
|
|
718
|
-
"SuppressedState",
|
|
719
|
-
|
|
720
|
-
"HighLimit",
|
|
721
|
-
"LowLimit",
|
|
722
|
-
"HighHighLimit",
|
|
723
|
-
"LowLowLimit",
|
|
724
|
-
|
|
725
|
-
"Value"
|
|
726
|
-
];
|
|
727
|
-
|
|
728
|
-
const eventFilter = constructEventFilter(fields, [
|
|
729
|
-
resolveNodeId("ConditionType")
|
|
730
|
-
]);
|
|
731
|
-
|
|
732
|
-
const event_monitoringItem = ClientMonitoredItem.create(
|
|
733
|
-
the_subscription,
|
|
734
|
-
{
|
|
735
|
-
attributeId: AttributeIds.EventNotifier,
|
|
736
|
-
nodeId: serverObjectId
|
|
737
|
-
},
|
|
738
|
-
{
|
|
739
|
-
discardOldest: true,
|
|
740
|
-
filter: eventFilter,
|
|
741
|
-
queueSize: 100000
|
|
742
|
-
}
|
|
743
|
-
);
|
|
744
|
-
|
|
745
|
-
event_monitoringItem.on("initialized", () => {
|
|
746
|
-
console.log("event_monitoringItem initialized");
|
|
747
|
-
});
|
|
748
|
-
|
|
749
|
-
event_monitoringItem.on("changed", (eventFields) => {
|
|
750
|
-
dumpEvent(the_session, fields, eventFields);
|
|
751
|
-
});
|
|
752
|
-
event_monitoringItem.on("err", (err_message) => {
|
|
753
|
-
console.log(chalk.red("event_monitoringItem ", baseEventTypeId, " ERROR"), err_message);
|
|
754
|
-
});
|
|
755
|
-
|
|
756
|
-
console.log("--------------------------------------------- Monitoring alarms");
|
|
757
|
-
const alarmNodeId = coerceNodeId("ns=2;s=1:Colours/EastTank?Green");
|
|
758
|
-
await monitorAlarm(the_subscription);
|
|
759
|
-
|
|
760
|
-
console.log("Starting timer ", timeout);
|
|
761
|
-
if (timeout > 0) {
|
|
762
|
-
|
|
763
|
-
// simulate a connection break at t =timeout/2
|
|
764
|
-
// new Promise((resolve) => {
|
|
765
|
-
setTimeout(() => {
|
|
766
|
-
|
|
767
|
-
console.log(chalk.red(" -------------------------------------------------------------------- "));
|
|
768
|
-
console.log(chalk.red(" -- SIMULATE CONNECTION BREAK -- "));
|
|
769
|
-
console.log(chalk.red(" -------------------------------------------------------------------- "));
|
|
770
|
-
const socket = client._secureChannel._transport._socket;
|
|
771
|
-
socket.end();
|
|
772
|
-
socket.emit("error", new Error("ECONNRESET"));
|
|
773
|
-
}, timeout / 2.0);
|
|
774
|
-
// });
|
|
775
|
-
|
|
776
|
-
await new Promise((resolve) => {
|
|
777
|
-
setTimeout(async () => {
|
|
778
|
-
console.log(chalk.yellow("------------------------------"), "time out => shutting down ");
|
|
779
|
-
if (!the_subscription) {
|
|
780
|
-
return resolve();
|
|
781
|
-
}
|
|
782
|
-
if (the_subscription) {
|
|
783
|
-
const s = the_subscription;
|
|
784
|
-
the_subscription = null;
|
|
785
|
-
await s.terminate();
|
|
786
|
-
await the_session.close();
|
|
787
|
-
await client.disconnect();
|
|
788
|
-
console.log(" Done ");
|
|
789
|
-
process.exit(0);
|
|
790
|
-
}
|
|
791
|
-
}, timeout);
|
|
792
|
-
});
|
|
793
|
-
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
console.log(" closing session");
|
|
797
|
-
await the_session.close();
|
|
798
|
-
console.log(" session closed");
|
|
799
|
-
|
|
800
|
-
console.log(" Calling disconnect");
|
|
801
|
-
await client.disconnect();
|
|
802
|
-
|
|
803
|
-
console.log(chalk.cyan(" disconnected"));
|
|
804
|
-
|
|
805
|
-
console.log("success !! ");
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
let user_interruption_count = 0;
|
|
809
|
-
process.on("SIGINT", async () => {
|
|
810
|
-
|
|
811
|
-
console.log(" user interruption ...");
|
|
812
|
-
|
|
813
|
-
user_interruption_count += 1;
|
|
814
|
-
if (user_interruption_count >= 3) {
|
|
815
|
-
process.exit(1);
|
|
816
|
-
}
|
|
817
|
-
if (the_subscription) {
|
|
818
|
-
console.log(chalk.red.bold(" Received client interruption from user "));
|
|
819
|
-
console.log(chalk.red.bold(" shutting down ..."));
|
|
820
|
-
const subscription = the_subscription;
|
|
821
|
-
the_subscription = null;
|
|
822
|
-
|
|
823
|
-
await subscription.terminate();
|
|
824
|
-
await the_session.close();
|
|
825
|
-
await client.disconnect();
|
|
826
|
-
process.exit(0);
|
|
827
|
-
}
|
|
828
|
-
});
|
|
829
|
-
|
|
830
|
-
main();
|