node-opcua-client-dynamic-extension-object 2.127.0 → 2.128.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/convert_data_type_definition_to_structuretype_schema.d.ts +14 -3
- package/dist/convert_data_type_definition_to_structuretype_schema.js +285 -204
- package/dist/convert_data_type_definition_to_structuretype_schema.js.map +1 -1
- package/dist/convert_structuretype_schema_to_structure_definition.js +1 -2
- package/dist/convert_structuretype_schema_to_structure_definition.js.map +1 -1
- package/dist/get_extension_object_constructor.js +1 -2
- package/dist/get_extension_object_constructor.js.map +1 -1
- package/dist/get_extra_data_type_manager.d.ts +3 -1
- package/dist/get_extra_data_type_manager.js +18 -7
- package/dist/get_extra_data_type_manager.js.map +1 -1
- package/dist/populate_data_type_manager.d.ts +7 -1
- package/dist/populate_data_type_manager.js +26 -9
- package/dist/populate_data_type_manager.js.map +1 -1
- package/dist/private/find_encodings.js +1 -2
- package/dist/private/find_encodings.js.map +1 -1
- package/dist/private/populate_data_type_manager_103.js +49 -46
- package/dist/private/populate_data_type_manager_103.js.map +1 -1
- package/dist/private/populate_data_type_manager_104.d.ts +2 -4
- package/dist/private/populate_data_type_manager_104.js +29 -102
- package/dist/private/populate_data_type_manager_104.js.map +1 -1
- package/dist/promote_opaque_structure.js +2 -3
- package/dist/promote_opaque_structure.js.map +1 -1
- package/dist/promote_opaque_structure_in_notification_data.js +1 -2
- package/dist/promote_opaque_structure_in_notification_data.js.map +1 -1
- package/dist/resolve_dynamic_extension_object.js +2 -3
- package/dist/resolve_dynamic_extension_object.js.map +1 -1
- package/package.json +16 -16
- package/source/convert_data_type_definition_to_structuretype_schema.ts +361 -236
- package/source/get_extra_data_type_manager.ts +17 -5
- package/source/populate_data_type_manager.ts +26 -6
- package/source/private/populate_data_type_manager_103.ts +68 -60
- package/source/private/populate_data_type_manager_104.ts +46 -119
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "node-opcua-pseudo-session";
|
|
8
8
|
//
|
|
9
9
|
import { ExtraDataTypeManager } from "./extra_data_type_manager";
|
|
10
|
-
import { populateDataTypeManager } from "./populate_data_type_manager";
|
|
10
|
+
import { DataTypeExtractStrategy, populateDataTypeManager } from "./populate_data_type_manager";
|
|
11
11
|
|
|
12
12
|
const doDebug = checkDebugFlag(__filename);
|
|
13
13
|
const debugLog = make_debugLog(__filename);
|
|
@@ -29,7 +29,7 @@ export async function invalidateExtraDataTypeManager(session: IBasicSessionAsync
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
async function
|
|
32
|
+
export async function extractDataTypeManagerPrivate(session: IBasicSessionAsync2, strategy: DataTypeExtractStrategy): Promise<ExtraDataTypeManager> {
|
|
33
33
|
const namespaceArray = await readNamespaceArray(session);
|
|
34
34
|
// istanbul ignore next
|
|
35
35
|
if (namespaceArray.length === 0) {
|
|
@@ -45,7 +45,7 @@ async function extractDataTypeManager(session: IBasicSessionAsync2): Promise<Ext
|
|
|
45
45
|
const dataTypeFactory1 = new DataTypeFactory([getStandardDataTypeFactory()]);
|
|
46
46
|
dataTypeManager.registerDataTypeFactory(namespaceIndex, dataTypeFactory1);
|
|
47
47
|
}
|
|
48
|
-
await populateDataTypeManager(session, dataTypeManager);
|
|
48
|
+
await populateDataTypeManager(session, dataTypeManager, strategy);
|
|
49
49
|
// istanbul ignore next
|
|
50
50
|
if (dataTypeManager.namespaceArray.length === 0) {
|
|
51
51
|
throw new Error("namespaceArray is not populated ! Your server must expose a list of namespace ");
|
|
@@ -53,7 +53,18 @@ async function extractDataTypeManager(session: IBasicSessionAsync2): Promise<Ext
|
|
|
53
53
|
return dataTypeManager;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
|
|
57
|
+
function getStrategy(session: IBasicSessionAsync2, strategy?: DataTypeExtractStrategy): DataTypeExtractStrategy {
|
|
58
|
+
if (strategy !== undefined) {
|
|
59
|
+
return strategy;
|
|
60
|
+
}
|
|
61
|
+
const client = (session as any).client;
|
|
62
|
+
if (client && client.dataTypeExtractStrategy!== undefined) {
|
|
63
|
+
return client.dataTypeExtractStrategy;
|
|
64
|
+
}
|
|
65
|
+
return DataTypeExtractStrategy.Auto;
|
|
66
|
+
}
|
|
67
|
+
export async function getExtraDataTypeManager(session: IBasicSessionAsync2, strategy?: DataTypeExtractStrategy ): Promise<ExtraDataTypeManager> {
|
|
57
68
|
const sessionPriv: IBasicSession_ = session as IBasicSession_;
|
|
58
69
|
if (sessionPriv.$$extraDataTypeManager) {
|
|
59
70
|
return sessionPriv.$$extraDataTypeManager;
|
|
@@ -71,7 +82,8 @@ export async function getExtraDataTypeManager(session: IBasicSessionAsync2): Pro
|
|
|
71
82
|
sessionPriv.$$extraDataTypeManagerToResolve!.push([_resolve, _reject]);
|
|
72
83
|
(async () => {
|
|
73
84
|
try {
|
|
74
|
-
|
|
85
|
+
strategy = getStrategy(session, strategy);
|
|
86
|
+
const dataTypeManager = await extractDataTypeManagerPrivate(session, strategy);
|
|
75
87
|
const tmp = sessionPriv.$$extraDataTypeManagerToResolve!;
|
|
76
88
|
sessionPriv.$$extraDataTypeManagerToResolve = undefined;
|
|
77
89
|
for (const [resolve] of tmp) {
|
|
@@ -111,13 +111,33 @@ export async function serverImplementsDataTypeDefinition(
|
|
|
111
111
|
return false;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
export
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
export enum DataTypeExtractStrategy {
|
|
115
|
+
Auto = 0,
|
|
116
|
+
Force103 = 1,
|
|
117
|
+
Force104 = 2,
|
|
118
|
+
Both = 3
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export async function populateDataTypeManager(
|
|
122
|
+
session: IBasicSessionAsync2,
|
|
123
|
+
dataTypeManager: ExtraDataTypeManager,
|
|
124
|
+
strategy: DataTypeExtractStrategy
|
|
125
|
+
): Promise<void> {
|
|
126
|
+
if (strategy === DataTypeExtractStrategy.Auto) {
|
|
127
|
+
const force104 = await serverImplementsDataTypeDefinition(session);
|
|
128
|
+
if (force104) {
|
|
129
|
+
await populateDataTypeManager104(session, dataTypeManager);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
// old way for 1.03 and early 1.04 prototype
|
|
133
|
+
await populateDataTypeManager103(session, dataTypeManager);
|
|
117
134
|
await populateDataTypeManager104(session, dataTypeManager);
|
|
118
135
|
return;
|
|
119
136
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
137
|
+
if (strategy == DataTypeExtractStrategy.Force103|| strategy == DataTypeExtractStrategy.Both) {
|
|
138
|
+
await populateDataTypeManager103(session, dataTypeManager);
|
|
139
|
+
}
|
|
140
|
+
if (strategy == DataTypeExtractStrategy.Force104 || strategy == DataTypeExtractStrategy.Both) {
|
|
141
|
+
await populateDataTypeManager104(session, dataTypeManager);
|
|
142
|
+
}
|
|
123
143
|
}
|
|
@@ -273,7 +273,7 @@ function sortStructure(dataTypeDefinitions: DataTypeDefinitions) {
|
|
|
273
273
|
const readIsAbstract = async (session: IBasicSessionAsync, nodeId: NodeId): Promise<boolean> => {
|
|
274
274
|
const dataValue = await session.read({ nodeId, attributeId: AttributeIds.IsAbstract });
|
|
275
275
|
return dataValue.value.value;
|
|
276
|
-
}
|
|
276
|
+
};
|
|
277
277
|
|
|
278
278
|
async function _extractDataTypeDictionaryFromDefinition(
|
|
279
279
|
session: IBasicSessionAsync2,
|
|
@@ -300,6 +300,8 @@ async function _extractDataTypeDictionaryFromDefinition(
|
|
|
300
300
|
const dataTypeDefinitions: DataTypeDefinitions = [];
|
|
301
301
|
|
|
302
302
|
let index = 0;
|
|
303
|
+
|
|
304
|
+
const promise: Promise<void>[] = [];
|
|
303
305
|
for (const dataValue of dataValuesWithDataTypeDefinition) {
|
|
304
306
|
const dataTypeNodeId = dataTypeNodeIds[index];
|
|
305
307
|
const dataTypeDescription = dataTypeDescriptions[index];
|
|
@@ -310,10 +312,10 @@ async function _extractDataTypeDictionaryFromDefinition(
|
|
|
310
312
|
|
|
311
313
|
if (dataTypeDefinition && dataTypeDefinition instanceof StructureDefinition) {
|
|
312
314
|
const className = dataTypeDescription.browseName.name!;
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
315
|
+
promise.push((async () => {
|
|
316
|
+
const isAbstract = await readIsAbstract(session, dataTypeNodeId);
|
|
317
|
+
dataTypeDefinitions.push({ className, dataTypeNodeId, dataTypeDefinition, isAbstract });
|
|
318
|
+
})());
|
|
317
319
|
}
|
|
318
320
|
} else {
|
|
319
321
|
debugLog(
|
|
@@ -325,56 +327,65 @@ async function _extractDataTypeDictionaryFromDefinition(
|
|
|
325
327
|
}
|
|
326
328
|
index++;
|
|
327
329
|
}
|
|
330
|
+
await Promise.all(promise);
|
|
331
|
+
|
|
328
332
|
// to do put in logical order
|
|
329
333
|
const dataTypeDefinitionsSorted = sortStructure(dataTypeDefinitions);
|
|
330
334
|
// istanbul ignore next
|
|
331
335
|
if (doDebug) {
|
|
332
336
|
debugLog("order ", dataTypeDefinitionsSorted.map((a) => a.className + " " + a.dataTypeNodeId).join(" -> "));
|
|
333
337
|
}
|
|
338
|
+
|
|
339
|
+
const promises2: Promise<void>[] = [];
|
|
340
|
+
|
|
334
341
|
for (const { className, dataTypeNodeId, dataTypeDefinition, isAbstract } of dataTypeDefinitionsSorted) {
|
|
335
|
-
// istanbul ignore next
|
|
336
|
-
if (doDebug) {
|
|
337
|
-
debugLog(chalk.yellow("--------------------------------------- "), className, dataTypeNodeId.toString());
|
|
338
|
-
}
|
|
339
|
-
if (dataTypeFactory.hasStructureByTypeName(className)) {
|
|
340
|
-
continue; // this structure has already been seen
|
|
341
|
-
}
|
|
342
|
-
// now fill typeDictionary
|
|
343
|
-
try {
|
|
344
|
-
const dataTypeDescription = dataTypeDescriptions.find((a)=>a.nodeId.toString() === dataTypeNodeId.toString());
|
|
345
|
-
if (!dataTypeDefinition) {
|
|
346
|
-
throw new Error("cannot find dataTypeDefinition for "+ dataTypeNodeId.toString());
|
|
347
|
-
}
|
|
348
|
-
const schema = await convertDataTypeDefinitionToStructureTypeSchema(
|
|
349
|
-
session,
|
|
350
|
-
dataTypeNodeId,
|
|
351
|
-
className,
|
|
352
|
-
dataTypeDefinition,
|
|
353
|
-
dataTypeDescription!, // for encodings
|
|
354
|
-
dataTypeFactory,
|
|
355
|
-
isAbstract,
|
|
356
|
-
cache
|
|
357
|
-
);
|
|
358
342
|
|
|
343
|
+
promises2.push((async () => {
|
|
359
344
|
// istanbul ignore next
|
|
360
345
|
if (doDebug) {
|
|
361
|
-
debugLog(chalk.
|
|
346
|
+
debugLog(chalk.yellow("--------------------------------------- "), className, dataTypeNodeId.toString());
|
|
362
347
|
}
|
|
363
|
-
if (
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
348
|
+
if (dataTypeFactory.hasStructureByTypeName(className)) {
|
|
349
|
+
return; // this structure has already been seen
|
|
350
|
+
}
|
|
351
|
+
// now fill typeDictionary
|
|
352
|
+
try {
|
|
353
|
+
const dataTypeDescription = dataTypeDescriptions.find((a) => a.nodeId.toString() === dataTypeNodeId.toString());
|
|
354
|
+
if (!dataTypeDefinition) {
|
|
355
|
+
throw new Error("cannot find dataTypeDefinition for " + dataTypeNodeId.toString());
|
|
356
|
+
}
|
|
357
|
+
const schema = await convertDataTypeDefinitionToStructureTypeSchema(
|
|
358
|
+
session,
|
|
359
|
+
dataTypeNodeId,
|
|
360
|
+
className,
|
|
361
|
+
dataTypeDefinition,
|
|
362
|
+
dataTypeDescription!, // for encodings
|
|
363
|
+
dataTypeFactory,
|
|
364
|
+
isAbstract,
|
|
365
|
+
cache
|
|
366
|
+
);
|
|
367
|
+
|
|
367
368
|
// istanbul ignore next
|
|
368
369
|
if (doDebug) {
|
|
369
|
-
debugLog("
|
|
370
|
+
debugLog(chalk.red("Registering "), chalk.cyan(className.padEnd(30, " ")), schema.dataTypeNodeId.toString());
|
|
371
|
+
}
|
|
372
|
+
if (!isAbstract) {
|
|
373
|
+
const Constructor = createDynamicObjectConstructor(schema, dataTypeFactory) as unknown as ConstructorFuncWithSchema;
|
|
374
|
+
assert(Constructor.schema === schema);
|
|
375
|
+
} else {
|
|
376
|
+
// istanbul ignore next
|
|
377
|
+
if (doDebug) {
|
|
378
|
+
debugLog("Ignoring Abstract ", className);
|
|
379
|
+
}
|
|
370
380
|
}
|
|
381
|
+
} catch (err) {
|
|
382
|
+
errorLog("Constructor verification err: ", (<Error>err).message);
|
|
383
|
+
errorLog("For this reason class " + className + " has not been registered");
|
|
384
|
+
errorLog(err);
|
|
371
385
|
}
|
|
372
|
-
}
|
|
373
|
-
errorLog("Constructor verification err: ", (<Error>err).message);
|
|
374
|
-
errorLog("For this reason class " + className + " has not been registered");
|
|
375
|
-
errorLog(err);
|
|
376
|
-
}
|
|
386
|
+
})());
|
|
377
387
|
}
|
|
388
|
+
await Promise.all(promises2);
|
|
378
389
|
}
|
|
379
390
|
|
|
380
391
|
async function _extractNodeIds(
|
|
@@ -420,18 +431,20 @@ async function _extractDataTypeDictionary(
|
|
|
420
431
|
): Promise<void> {
|
|
421
432
|
const dataTypeDictionaryNodeId = d.reference.nodeId;
|
|
422
433
|
|
|
423
|
-
const name = await session.read({ nodeId: dataTypeDictionaryNodeId, attributeId: AttributeIds.BrowseName });
|
|
424
|
-
const namespace = await _readNamespaceUriProperty(session, dataTypeDictionaryNodeId);
|
|
425
|
-
|
|
426
434
|
if (!_isOldDataTypeDictionary(d)) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
+
if (doDebug) {
|
|
436
|
+
const [name, namespace] = await Promise.all([
|
|
437
|
+
session.read({ nodeId: dataTypeDictionaryNodeId, attributeId: AttributeIds.BrowseName }),
|
|
438
|
+
_readNamespaceUriProperty(session, dataTypeDictionaryNodeId)
|
|
439
|
+
]);
|
|
440
|
+
debugLog(
|
|
441
|
+
"DataTypeDictionary is deprecated or BSD schema stored in dataValue is null !",
|
|
442
|
+
chalk.cyan(name.value.value.toString()),
|
|
443
|
+
"namespace =",
|
|
444
|
+
namespace
|
|
445
|
+
);
|
|
446
|
+
debugLog("let's use the new way (1.04) and let's explore all dataTypes exposed by this name space");
|
|
447
|
+
}
|
|
435
448
|
// dataType definition in store directly in UADataType under the definition attribute
|
|
436
449
|
const dataTypeFactory2 = dataTypeManager.getDataTypeFactory(dataTypeDictionaryNodeId.namespace);
|
|
437
450
|
if (!dataTypeFactory2) {
|
|
@@ -780,18 +793,13 @@ export async function populateDataTypeManager103(
|
|
|
780
793
|
await _exploreDataTypeDefinition(session, dataTypeDictionaryNodeId, dataTypeFactory, dataTypeManager.namespaceArray);
|
|
781
794
|
}
|
|
782
795
|
|
|
796
|
+
const promises: Promise<void>[] = [];
|
|
797
|
+
|
|
783
798
|
// https://medium.com/swlh/dealing-with-multiple-promises-in-javascript-41d6c21f20ff
|
|
784
799
|
for (const d of dataTypeDictionaryInfo) {
|
|
785
|
-
|
|
786
|
-
await processReferenceOnDataTypeDictionaryType(d).catch((e) => {
|
|
787
|
-
debugLog("processReferenceOnDataTypeDictionaryType has failed ");
|
|
788
|
-
debugLog("Error", e.message);
|
|
789
|
-
debugLog(e);
|
|
790
|
-
return e;
|
|
791
|
-
});
|
|
792
|
-
} catch (err) {
|
|
793
|
-
debugLog(chalk.red("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "), err);
|
|
794
|
-
}
|
|
800
|
+
promises.push(processReferenceOnDataTypeDictionaryType(d));
|
|
795
801
|
}
|
|
802
|
+
await Promise.all(promises);
|
|
803
|
+
|
|
796
804
|
debugLog("out ... populateDataTypeManager");
|
|
797
805
|
}
|
|
@@ -1,35 +1,32 @@
|
|
|
1
1
|
import { AttributeIds, BrowseDirection } from "node-opcua-data-model";
|
|
2
|
-
import { make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
2
|
+
import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
3
3
|
import { DataTypeFactory } from "node-opcua-factory";
|
|
4
|
-
import { NodeId, resolveNodeId } from "node-opcua-nodeid";
|
|
4
|
+
import { NodeId, resolveNodeId, NodeIdLike } from "node-opcua-nodeid";
|
|
5
5
|
import { IBasicSessionAsync2, IBasicSessionBrowseAsync, IBasicSessionBrowseNext, IBasicSessionReadAsync, IBasicSessionTranslateBrowsePathAsync, browseAll } from "node-opcua-pseudo-session";
|
|
6
6
|
import { createDynamicObjectConstructor as createDynamicObjectConstructorAndRegister } from "node-opcua-schemas";
|
|
7
|
-
import { StatusCodes } from "node-opcua-status-code";
|
|
8
7
|
import {
|
|
9
8
|
ReferenceDescription,
|
|
10
|
-
BrowseResult,
|
|
11
9
|
BrowseDescriptionOptions,
|
|
12
10
|
StructureDefinition,
|
|
13
|
-
DataTypeDefinition
|
|
14
|
-
BrowseDescription
|
|
15
|
-
} from "node-opcua-types";
|
|
11
|
+
DataTypeDefinition} from "node-opcua-types";
|
|
16
12
|
//
|
|
17
13
|
import { ExtraDataTypeManager } from "../extra_data_type_manager";
|
|
18
14
|
import {
|
|
19
|
-
|
|
15
|
+
ICache,
|
|
20
16
|
convertDataTypeDefinitionToStructureTypeSchema
|
|
21
17
|
} from "../convert_data_type_definition_to_structuretype_schema";
|
|
22
18
|
|
|
23
19
|
const errorLog = make_errorLog(__filename);
|
|
24
20
|
const debugLog = make_debugLog(__filename);
|
|
25
21
|
const warningLog = make_warningLog(__filename);
|
|
22
|
+
const doDebug = checkDebugFlag(__filename);
|
|
26
23
|
|
|
27
24
|
export async function readDataTypeDefinitionAndBuildType(
|
|
28
25
|
session: IBasicSessionAsync2,
|
|
29
26
|
dataTypeNodeId: NodeId,
|
|
30
27
|
name: string,
|
|
31
28
|
dataTypeFactory: DataTypeFactory,
|
|
32
|
-
cache:
|
|
29
|
+
cache: ICache
|
|
33
30
|
): Promise<void> {
|
|
34
31
|
try {
|
|
35
32
|
if (dataTypeFactory.getStructureInfoForDataType(dataTypeNodeId)) {
|
|
@@ -55,8 +52,14 @@ export async function readDataTypeDefinitionAndBuildType(
|
|
|
55
52
|
/* istanbul ignore next */
|
|
56
53
|
if (dataTypeDefinitionDataValue.statusCode.isNotGood()) {
|
|
57
54
|
// may be we are reading a 1.03 server
|
|
55
|
+
// or it could be some of the di:ParameterResultDataType that are not marked as abstract
|
|
56
|
+
// in some cases
|
|
58
57
|
if (!isAbstract) {
|
|
59
|
-
|
|
58
|
+
const [isAbstract2, browseNameDV] = await session.read([
|
|
59
|
+
{ nodeId: dataTypeNodeId, attributeId: AttributeIds.IsAbstract },
|
|
60
|
+
{ nodeId: dataTypeNodeId, attributeId: AttributeIds.BrowseName }
|
|
61
|
+
]);
|
|
62
|
+
warningLog(" Cannot find dataType Definition ! with nodeId =" + dataTypeNodeId.toString(), browseNameDV.value?.value?.toString(), isAbstract2.value?.value);
|
|
60
63
|
return;
|
|
61
64
|
}
|
|
62
65
|
// it is OK to not have dataTypeDefinition for Abstract type!
|
|
@@ -84,118 +87,14 @@ export async function readDataTypeDefinitionAndBuildType(
|
|
|
84
87
|
}
|
|
85
88
|
}
|
|
86
89
|
|
|
87
|
-
class TaskMan {
|
|
88
|
-
private readonly taskList: (() => Promise<void>)[] = [];
|
|
89
|
-
private _runningTask = false;
|
|
90
|
-
private _resolve: (() => void) | undefined = undefined;
|
|
91
|
-
|
|
92
|
-
async flushTaskList() {
|
|
93
|
-
const firstTask = this.taskList.shift()!;
|
|
94
|
-
this._runningTask = true;
|
|
95
|
-
await firstTask();
|
|
96
|
-
this._runningTask = false;
|
|
97
|
-
if (this.taskList.length > 0) {
|
|
98
|
-
setImmediate(async () => {
|
|
99
|
-
await this.flushTaskList();
|
|
100
|
-
});
|
|
101
|
-
} else {
|
|
102
|
-
if (this._resolve) {
|
|
103
|
-
const tmpResolve = this._resolve;
|
|
104
|
-
this._resolve = undefined;
|
|
105
|
-
tmpResolve();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
*
|
|
111
|
-
* a little async task queue that gets executed sequentially
|
|
112
|
-
* outside the main loop
|
|
113
|
-
*/
|
|
114
|
-
public registerTask(taskFunc: () => Promise<void>) {
|
|
115
|
-
this.taskList.push(taskFunc);
|
|
116
|
-
if (this.taskList.length === 1 && !this._runningTask) {
|
|
117
|
-
this.flushTaskList();
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
public async waitForCompletion() {
|
|
121
|
-
if (this._resolve !== undefined) {
|
|
122
|
-
throw new Error("already waiting");
|
|
123
|
-
}
|
|
124
|
-
await new Promise<void>((resolve) => {
|
|
125
|
-
this._resolve = resolve;
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async function applyOnReferenceRecursively(
|
|
131
|
-
session: IBasicSessionTranslateBrowsePathAsync & IBasicSessionReadAsync & IBasicSessionBrowseAsync & IBasicSessionBrowseNext,
|
|
132
|
-
nodeId: NodeId,
|
|
133
|
-
browseDescriptionTemplate: BrowseDescriptionOptions,
|
|
134
|
-
action: (ref: ReferenceDescription) => Promise<void>
|
|
135
|
-
): Promise<void> {
|
|
136
|
-
const taskManager = new TaskMan();
|
|
137
|
-
|
|
138
|
-
let pendingNodesToBrowse: BrowseDescriptionOptions[] = [];
|
|
139
|
-
|
|
140
|
-
function processBrowseResults(nodesToBrowse: BrowseDescriptionOptions[], browseResults: BrowseResult[]) {
|
|
141
|
-
for (let i = 0; i < browseResults.length; i++) {
|
|
142
|
-
const result = browseResults[i];
|
|
143
|
-
const nodeToBrowse = nodesToBrowse[i];
|
|
144
|
-
if (
|
|
145
|
-
result.statusCode.equals(StatusCodes.BadNoContinuationPoints) ||
|
|
146
|
-
result.statusCode.equals(StatusCodes.BadContinuationPointInvalid)
|
|
147
|
-
) {
|
|
148
|
-
// not enough continuation points .. we need to rebrowse
|
|
149
|
-
pendingNodesToBrowse.push(nodeToBrowse);
|
|
150
|
-
// taskManager.registerTask(flushBrowse);
|
|
151
|
-
} else if (result.statusCode.isGood()) {
|
|
152
|
-
for (const r of result.references || []) {
|
|
153
|
-
// also explore sub types
|
|
154
|
-
browseSubDataTypeRecursively(r.nodeId);
|
|
155
|
-
taskManager.registerTask(async () => await action(r));
|
|
156
|
-
}
|
|
157
|
-
} else {
|
|
158
|
-
errorLog(
|
|
159
|
-
"Unexpected status code",
|
|
160
|
-
i,
|
|
161
|
-
new BrowseDescription(nodesToBrowse[i] || {})?.toString(),
|
|
162
|
-
result.statusCode.toString()
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
async function flushBrowse() {
|
|
168
|
-
if (pendingNodesToBrowse.length) {
|
|
169
|
-
const nodesToBrowse = pendingNodesToBrowse;
|
|
170
|
-
pendingNodesToBrowse = [];
|
|
171
|
-
taskManager.registerTask(async () => {
|
|
172
|
-
try {
|
|
173
|
-
const browseResults = await browseAll(session, nodesToBrowse);
|
|
174
|
-
processBrowseResults(nodesToBrowse, browseResults);
|
|
175
|
-
} catch (err) {
|
|
176
|
-
errorLog("err", (err as Error).message);
|
|
177
|
-
errorLog(nodesToBrowse.toString());
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function browseSubDataTypeRecursively(nodeId: NodeId): void {
|
|
184
|
-
const nodeToBrowse: BrowseDescriptionOptions = {
|
|
185
|
-
...browseDescriptionTemplate,
|
|
186
|
-
nodeId
|
|
187
|
-
};
|
|
188
|
-
pendingNodesToBrowse.push(nodeToBrowse);
|
|
189
|
-
taskManager.registerTask(async () => flushBrowse());
|
|
190
|
-
}
|
|
191
|
-
browseSubDataTypeRecursively(nodeId);
|
|
192
|
-
await taskManager.waitForCompletion();
|
|
193
|
-
}
|
|
194
90
|
export async function populateDataTypeManager104(
|
|
195
91
|
session: IBasicSessionAsync2,
|
|
196
92
|
dataTypeManager: ExtraDataTypeManager
|
|
197
93
|
): Promise<void> {
|
|
198
|
-
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
const cache: ICache = {};
|
|
199
98
|
|
|
200
99
|
async function withDataType(r: ReferenceDescription): Promise<void> {
|
|
201
100
|
const dataTypeNodeId = r.nodeId;
|
|
@@ -216,7 +115,7 @@ export async function populateDataTypeManager104(
|
|
|
216
115
|
return;
|
|
217
116
|
}
|
|
218
117
|
// extract it formally
|
|
219
|
-
debugLog(" DataType => ", r.browseName.toString(), dataTypeNodeId.toString());
|
|
118
|
+
doDebug && debugLog(" DataType => ", r.browseName.toString(), dataTypeNodeId.toString());
|
|
220
119
|
await readDataTypeDefinitionAndBuildType(session, dataTypeNodeId, r.browseName.name!, dataTypeFactory, cache);
|
|
221
120
|
} catch (err) {
|
|
222
121
|
errorLog("err=", err);
|
|
@@ -233,3 +132,31 @@ export async function populateDataTypeManager104(
|
|
|
233
132
|
};
|
|
234
133
|
await applyOnReferenceRecursively(session, resolveNodeId("Structure"), nodeToBrowse, withDataType);
|
|
235
134
|
}
|
|
135
|
+
async function applyOnReferenceRecursively(
|
|
136
|
+
session: IBasicSessionTranslateBrowsePathAsync & IBasicSessionReadAsync & IBasicSessionBrowseAsync & IBasicSessionBrowseNext,
|
|
137
|
+
nodeId: NodeId,
|
|
138
|
+
browseDescriptionTemplate: BrowseDescriptionOptions,
|
|
139
|
+
action: (ref: ReferenceDescription) => Promise<void>
|
|
140
|
+
): Promise<void> {
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
const oneLevel = async (nodeId: NodeIdLike) => {
|
|
144
|
+
|
|
145
|
+
const nodeToBrowse: BrowseDescriptionOptions = {
|
|
146
|
+
...browseDescriptionTemplate,
|
|
147
|
+
nodeId
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const browseResult = await browseAll(session, nodeToBrowse);
|
|
151
|
+
|
|
152
|
+
const promises: Promise<void>[] = [];
|
|
153
|
+
for (const ref of browseResult.references || []) {
|
|
154
|
+
promises.push((async () => {
|
|
155
|
+
await action(ref);
|
|
156
|
+
await oneLevel(ref.nodeId);
|
|
157
|
+
})());
|
|
158
|
+
}
|
|
159
|
+
await Promise.all(promises);
|
|
160
|
+
};
|
|
161
|
+
await oneLevel(nodeId);
|
|
162
|
+
}
|