node-opcua-client-dynamic-extension-object 2.127.1 → 2.129.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 +284 -202
- package/dist/convert_data_type_definition_to_structuretype_schema.js.map +1 -1
- package/dist/get_extra_data_type_manager.d.ts +3 -1
- package/dist/get_extra_data_type_manager.js +17 -5
- 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 +24 -7
- package/dist/populate_data_type_manager.js.map +1 -1
- package/dist/private/populate_data_type_manager_103.js +48 -44
- 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 +27 -99
- package/dist/private/populate_data_type_manager_104.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
|
@@ -3,6 +3,7 @@ import { NodeId } from "node-opcua-nodeid";
|
|
|
3
3
|
import { IBasicSessionAsync2 } from "node-opcua-pseudo-session";
|
|
4
4
|
import { DataTypeDefinition } from "node-opcua-types";
|
|
5
5
|
import { DataTypeAndEncodingId } from "node-opcua-schemas";
|
|
6
|
+
import { DataType } from "node-opcua-variant";
|
|
6
7
|
export interface CacheForFieldResolution {
|
|
7
8
|
fieldTypeName: string;
|
|
8
9
|
schema: TypeDefinition;
|
|
@@ -10,10 +11,20 @@ export interface CacheForFieldResolution {
|
|
|
10
11
|
allowSubType?: boolean;
|
|
11
12
|
dataType?: NodeId;
|
|
12
13
|
}
|
|
14
|
+
export type ResolveReject = [
|
|
15
|
+
resolve: (value: any) => void,
|
|
16
|
+
reject: (err: Error) => void
|
|
17
|
+
];
|
|
18
|
+
export interface ICache {
|
|
19
|
+
superType?: Map<string, NodeId>;
|
|
20
|
+
fieldResolution?: Map<string, CacheForFieldResolution>;
|
|
21
|
+
dataTypes?: Map<string, DataType>;
|
|
22
|
+
browseNameCache?: Map<string, string>;
|
|
23
|
+
hitCount?: number;
|
|
24
|
+
$$resolveStuff?: Map<string, ResolveReject[]>;
|
|
25
|
+
}
|
|
13
26
|
export interface IDataTypeDescriptionMini {
|
|
14
27
|
encodings?: DataTypeAndEncodingId;
|
|
15
28
|
isAbstract?: boolean;
|
|
16
29
|
}
|
|
17
|
-
export declare function convertDataTypeDefinitionToStructureTypeSchema(session: IBasicSessionAsync2, dataTypeNodeId: NodeId, name: string, definition: DataTypeDefinition, dataTypeDescription: IDataTypeDescriptionMini | null, dataTypeFactory: DataTypeFactory, isAbstract: boolean, cache:
|
|
18
|
-
[key: string]: CacheForFieldResolution;
|
|
19
|
-
}): Promise<IStructuredTypeSchema>;
|
|
30
|
+
export declare function convertDataTypeDefinitionToStructureTypeSchema(session: IBasicSessionAsync2, dataTypeNodeId: NodeId, name: string, definition: DataTypeDefinition, dataTypeDescription: IDataTypeDescriptionMini | null, dataTypeFactory: DataTypeFactory, isAbstract: boolean, cache: ICache): Promise<IStructuredTypeSchema>;
|
|
@@ -16,38 +16,62 @@ const find_encodings_1 = require("./private/find_encodings");
|
|
|
16
16
|
const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
|
|
17
17
|
const errorLog = (0, node_opcua_debug_1.make_errorLog)(__filename);
|
|
18
18
|
const warningLog = (0, node_opcua_debug_1.make_warningLog)(__filename);
|
|
19
|
-
|
|
19
|
+
const doDebug = false;
|
|
20
|
+
async function memoize(cache, cacheName, nodeId, func) {
|
|
21
|
+
const key = nodeId.toString();
|
|
22
|
+
if (cache[cacheName]?.has(key)) {
|
|
23
|
+
cache.hitCount = cache.hitCount === undefined ? 0 : cache.hitCount + 1;
|
|
24
|
+
return cache[cacheName]?.get(key);
|
|
25
|
+
}
|
|
26
|
+
const value = await func();
|
|
27
|
+
if (!cache[cacheName]) {
|
|
28
|
+
cache[cacheName] = new Map();
|
|
29
|
+
}
|
|
30
|
+
cache[cacheName].set(key, value);
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
function fromCache(cache, cacheName, nodeId) {
|
|
34
|
+
const key = nodeId.toString();
|
|
35
|
+
if (cache[cacheName]?.has(key)) {
|
|
36
|
+
cache.hitCount = cache.hitCount === undefined ? 0 : cache.hitCount + 1;
|
|
37
|
+
return cache[cacheName]?.get(key);
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
async function findSuperType(session, dataTypeNodeId, cache) {
|
|
20
42
|
if (dataTypeNodeId.namespace === 0 && dataTypeNodeId.value === 24) {
|
|
21
43
|
// BaseDataType !
|
|
22
44
|
return (0, node_opcua_nodeid_2.coerceNodeId)(0);
|
|
23
45
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
return await memoize(cache, "superType", dataTypeNodeId, async () => {
|
|
47
|
+
const nodeToBrowse3 = {
|
|
48
|
+
browseDirection: node_opcua_data_model_1.BrowseDirection.Inverse,
|
|
49
|
+
includeSubtypes: false,
|
|
50
|
+
nodeClassMask: node_opcua_data_model_1.NodeClassMask.DataType,
|
|
51
|
+
nodeId: dataTypeNodeId,
|
|
52
|
+
referenceTypeId: (0, node_opcua_nodeid_2.resolveNodeId)("HasSubtype"),
|
|
53
|
+
resultMask: (0, node_opcua_data_model_1.makeResultMask)("NodeId | ReferenceType | BrowseName | NodeClass")
|
|
54
|
+
};
|
|
55
|
+
const result3 = await (0, node_opcua_pseudo_session_1.browseAll)(session, nodeToBrowse3);
|
|
56
|
+
/* istanbul ignore next */
|
|
57
|
+
if (result3.statusCode.isNotGood()) {
|
|
58
|
+
throw new Error("Cannot find superType for " + dataTypeNodeId.toString());
|
|
59
|
+
}
|
|
60
|
+
result3.references = result3.references || [];
|
|
61
|
+
/* istanbul ignore next */
|
|
62
|
+
if (result3.references.length !== 1) {
|
|
63
|
+
errorLog("Invalid dataType with more than one (or 0) superType", result3.toString());
|
|
64
|
+
throw new Error("Invalid dataType with more than one (or 0) superType " + dataTypeNodeId.toString() + " l=" + result3.references.length);
|
|
65
|
+
}
|
|
66
|
+
return result3.references[0].nodeId;
|
|
67
|
+
});
|
|
44
68
|
}
|
|
45
|
-
async function findDataTypeCategory(session, cache, dataTypeNodeId) {
|
|
46
|
-
const subTypeNodeId = await findSuperType(session, dataTypeNodeId);
|
|
47
|
-
debugLog("subTypeNodeId of ", dataTypeNodeId.toString(), " is ", subTypeNodeId.toString());
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
50
|
-
return
|
|
69
|
+
async function findDataTypeCategory(session, dataTypeFactory, cache, dataTypeNodeId) {
|
|
70
|
+
const subTypeNodeId = await findSuperType(session, dataTypeNodeId, cache);
|
|
71
|
+
doDebug && debugLog("subTypeNodeId of ", dataTypeNodeId.toString(), " is ", subTypeNodeId.toString());
|
|
72
|
+
const fieldResolution = fromCache(cache, "fieldResolution", subTypeNodeId);
|
|
73
|
+
if (fieldResolution) {
|
|
74
|
+
return fieldResolution.category;
|
|
51
75
|
}
|
|
52
76
|
let category;
|
|
53
77
|
const n = subTypeNodeId;
|
|
@@ -67,14 +91,14 @@ async function findDataTypeCategory(session, cache, dataTypeNodeId) {
|
|
|
67
91
|
return category;
|
|
68
92
|
}
|
|
69
93
|
// must drill down ...
|
|
70
|
-
return await findDataTypeCategory(session, cache, subTypeNodeId);
|
|
94
|
+
return await findDataTypeCategory(session, dataTypeFactory, cache, subTypeNodeId);
|
|
71
95
|
}
|
|
72
96
|
async function findDataTypeBasicType(session, cache, dataTypeNodeId) {
|
|
73
|
-
const subTypeNodeId = await findSuperType(session, dataTypeNodeId);
|
|
97
|
+
const subTypeNodeId = await findSuperType(session, dataTypeNodeId, cache);
|
|
74
98
|
debugLog("subTypeNodeId of ", dataTypeNodeId.toString(), " is ", subTypeNodeId.toString());
|
|
75
|
-
const
|
|
76
|
-
if (
|
|
77
|
-
return
|
|
99
|
+
const fieldResolution = fromCache(cache, "fieldResolution", subTypeNodeId);
|
|
100
|
+
if (fieldResolution) {
|
|
101
|
+
return fieldResolution.schema;
|
|
78
102
|
}
|
|
79
103
|
const n = subTypeNodeId;
|
|
80
104
|
if (n.identifierType === node_opcua_nodeid_1.NodeIdType.NUMERIC && n.namespace === 0 && n.value < 29) {
|
|
@@ -93,19 +117,22 @@ async function findDataTypeBasicType(session, cache, dataTypeNodeId) {
|
|
|
93
117
|
return (0, node_opcua_factory_1.getBuiltInType)(name);
|
|
94
118
|
}
|
|
95
119
|
// must drill down ...
|
|
96
|
-
|
|
120
|
+
const td = await findDataTypeBasicType(session, cache, subTypeNodeId);
|
|
121
|
+
return td;
|
|
97
122
|
}
|
|
98
|
-
async function
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
123
|
+
async function readBrowseNameWithCache(session, nodeId, cache) {
|
|
124
|
+
return await memoize(cache, "browseNameCache", nodeId, async () => {
|
|
125
|
+
const dataValue = await session.read({ nodeId, attributeId: node_opcua_data_model_1.AttributeIds.BrowseName });
|
|
126
|
+
if (dataValue.statusCode.isNotGood()) {
|
|
127
|
+
const message = "cannot extract BrowseName of nodeId = " + nodeId.toString() + " statusCode = " + dataValue.statusCode.toString();
|
|
128
|
+
debugLog(message);
|
|
129
|
+
throw new Error(message);
|
|
130
|
+
}
|
|
131
|
+
return dataValue.value.value.name;
|
|
132
|
+
});
|
|
106
133
|
}
|
|
107
134
|
async function resolve2(session, dataTypeNodeId, dataTypeFactory, fieldTypeName, cache) {
|
|
108
|
-
const category = await findDataTypeCategory(session, cache, dataTypeNodeId);
|
|
135
|
+
const category = await findDataTypeCategory(session, dataTypeFactory, cache, dataTypeNodeId);
|
|
109
136
|
debugLog(" type " + fieldTypeName + " has not been seen yet, let resolve it => (category = ", category, " )");
|
|
110
137
|
let schema = undefined;
|
|
111
138
|
switch (category) {
|
|
@@ -154,11 +181,11 @@ async function resolve2(session, dataTypeNodeId, dataTypeFactory, fieldTypeName,
|
|
|
154
181
|
}
|
|
155
182
|
return { schema, category };
|
|
156
183
|
}
|
|
157
|
-
const isExtensionObject = async (session, dataTypeNodeId) => {
|
|
184
|
+
const isExtensionObject = async (session, dataTypeNodeId, cache) => {
|
|
158
185
|
if (dataTypeNodeId.namespace === 0 && dataTypeNodeId.value === node_opcua_variant_1.DataType.ExtensionObject) {
|
|
159
186
|
return true;
|
|
160
187
|
}
|
|
161
|
-
const baseDataType = await findSuperType(session, dataTypeNodeId);
|
|
188
|
+
const baseDataType = await findSuperType(session, dataTypeNodeId, cache);
|
|
162
189
|
const bn = baseDataType;
|
|
163
190
|
if (bn.identifierType === node_opcua_nodeid_1.NodeIdType.NUMERIC) {
|
|
164
191
|
if (bn.namespace === 0 && bn.value === node_opcua_variant_1.DataType.ExtensionObject) {
|
|
@@ -168,98 +195,96 @@ const isExtensionObject = async (session, dataTypeNodeId) => {
|
|
|
168
195
|
return false;
|
|
169
196
|
}
|
|
170
197
|
}
|
|
171
|
-
return await isExtensionObject(session, baseDataType);
|
|
198
|
+
return await isExtensionObject(session, baseDataType, cache);
|
|
172
199
|
};
|
|
173
200
|
// eslint-disable-next-line max-statements
|
|
174
201
|
async function resolveFieldType(session, dataTypeNodeId, dataTypeFactory, cache) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
dataType: (0, node_opcua_nodeid_2.coerceNodeId)(node_opcua_variant_1.DataType.ExtensionObject)
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
const key = dataTypeNodeId.toString();
|
|
189
|
-
const v = cache[key];
|
|
190
|
-
if (v) {
|
|
191
|
-
return v;
|
|
192
|
-
}
|
|
193
|
-
if (dataTypeNodeId.value === 0) {
|
|
194
|
-
const v3 = {
|
|
195
|
-
category: node_opcua_factory_1.FieldCategory.basic,
|
|
196
|
-
fieldTypeName: "Variant",
|
|
197
|
-
schema: dataTypeFactory.getBuiltInType("Variant")
|
|
198
|
-
};
|
|
199
|
-
cache[key] = v3;
|
|
200
|
-
return v3;
|
|
201
|
-
}
|
|
202
|
-
const isAbstract = (await session.read({ nodeId: dataTypeNodeId, attributeId: node_opcua_data_model_1.AttributeIds.IsAbstract })).value.value;
|
|
203
|
-
const fieldTypeName = await readBrowseName(session, dataTypeNodeId);
|
|
204
|
-
if (isAbstract) {
|
|
205
|
-
const _isExtensionObject = await isExtensionObject(session, dataTypeNodeId);
|
|
206
|
-
debugLog(" dataType " + dataTypeNodeId.toString() + " " + fieldTypeName + " is abstract => extObj ?= " + _isExtensionObject);
|
|
207
|
-
if (_isExtensionObject) {
|
|
208
|
-
// we could have complex => Structure
|
|
209
|
-
const v3 = {
|
|
210
|
-
category: node_opcua_factory_1.FieldCategory.complex,
|
|
211
|
-
fieldTypeName: fieldTypeName,
|
|
212
|
-
schema: node_opcua_extension_object_1.ExtensionObject.schema,
|
|
202
|
+
return await memoize(cache, "fieldResolution", dataTypeNodeId, async () => {
|
|
203
|
+
if (dataTypeNodeId.namespace === 0 && dataTypeNodeId.value === 22) {
|
|
204
|
+
// ERN return null;
|
|
205
|
+
const category = node_opcua_factory_1.FieldCategory.complex;
|
|
206
|
+
const fieldTypeName = "Structure";
|
|
207
|
+
const schema = node_opcua_extension_object_1.ExtensionObject.schema;
|
|
208
|
+
return {
|
|
209
|
+
category,
|
|
210
|
+
fieldTypeName,
|
|
211
|
+
schema,
|
|
213
212
|
allowSubType: true,
|
|
214
|
-
dataType:
|
|
213
|
+
dataType: (0, node_opcua_nodeid_2.coerceNodeId)(node_opcua_variant_1.DataType.ExtensionObject)
|
|
215
214
|
};
|
|
216
|
-
cache[key] = v3;
|
|
217
|
-
return v3;
|
|
218
215
|
}
|
|
219
|
-
|
|
220
|
-
// we could have basic => Variant
|
|
216
|
+
if (dataTypeNodeId.value === 0) {
|
|
221
217
|
const v3 = {
|
|
222
218
|
category: node_opcua_factory_1.FieldCategory.basic,
|
|
223
|
-
fieldTypeName:
|
|
224
|
-
schema: dataTypeFactory.getBuiltInType("Variant")
|
|
225
|
-
allowSubType: true,
|
|
226
|
-
dataType: dataTypeNodeId
|
|
219
|
+
fieldTypeName: "Variant",
|
|
220
|
+
schema: dataTypeFactory.getBuiltInType("Variant")
|
|
227
221
|
};
|
|
228
|
-
cache[key] = v3;
|
|
229
222
|
return v3;
|
|
230
223
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
224
|
+
const readIsAbstract = async (dataTypeNodeId) => {
|
|
225
|
+
return (await session.read({ nodeId: dataTypeNodeId, attributeId: node_opcua_data_model_1.AttributeIds.IsAbstract })).value.value;
|
|
226
|
+
};
|
|
227
|
+
const [isAbstract, fieldTypeName] = await Promise.all([
|
|
228
|
+
readIsAbstract(dataTypeNodeId),
|
|
229
|
+
readBrowseNameWithCache(session, dataTypeNodeId, cache)
|
|
230
|
+
]);
|
|
231
|
+
if (isAbstract) {
|
|
232
|
+
const _isExtensionObject = await isExtensionObject(session, dataTypeNodeId, cache);
|
|
233
|
+
debugLog(" dataType " + dataTypeNodeId.toString() + " " + fieldTypeName + " is abstract => extObj ?= " + _isExtensionObject);
|
|
234
|
+
if (_isExtensionObject) {
|
|
235
|
+
// we could have complex => Structure
|
|
236
|
+
const v3 = {
|
|
237
|
+
category: node_opcua_factory_1.FieldCategory.complex,
|
|
238
|
+
fieldTypeName: fieldTypeName,
|
|
239
|
+
schema: node_opcua_extension_object_1.ExtensionObject.schema,
|
|
240
|
+
allowSubType: true,
|
|
241
|
+
dataType: dataTypeNodeId
|
|
242
|
+
};
|
|
243
|
+
return v3;
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
// we could have basic => Variant
|
|
247
|
+
const v3 = {
|
|
248
|
+
category: node_opcua_factory_1.FieldCategory.basic,
|
|
249
|
+
fieldTypeName: fieldTypeName,
|
|
250
|
+
schema: dataTypeFactory.getBuiltInType("Variant"),
|
|
251
|
+
allowSubType: true,
|
|
252
|
+
dataType: dataTypeNodeId
|
|
253
|
+
};
|
|
254
|
+
return v3;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
let schema;
|
|
258
|
+
let category = node_opcua_factory_1.FieldCategory.enumeration;
|
|
259
|
+
if (dataTypeFactory.hasStructureByTypeName(fieldTypeName)) {
|
|
260
|
+
schema = dataTypeFactory.getStructuredTypeSchema(fieldTypeName);
|
|
261
|
+
category = node_opcua_factory_1.FieldCategory.complex;
|
|
262
|
+
}
|
|
263
|
+
else if (dataTypeFactory.hasBuiltInType(fieldTypeName)) {
|
|
264
|
+
category = node_opcua_factory_1.FieldCategory.basic;
|
|
265
|
+
schema = dataTypeFactory.getBuiltInType(fieldTypeName);
|
|
266
|
+
}
|
|
267
|
+
else if (dataTypeFactory.hasEnumeration(fieldTypeName)) {
|
|
268
|
+
category = node_opcua_factory_1.FieldCategory.enumeration;
|
|
269
|
+
schema = dataTypeFactory.getEnumeration(fieldTypeName);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
debugLog(" type " + fieldTypeName + " has not been seen yet, let resolve it");
|
|
273
|
+
const res = await resolve2(session, dataTypeNodeId, dataTypeFactory, fieldTypeName, cache);
|
|
274
|
+
schema = res.schema;
|
|
275
|
+
category = res.category;
|
|
276
|
+
}
|
|
277
|
+
/* istanbul ignore next */
|
|
278
|
+
if (!schema) {
|
|
279
|
+
throw new Error("expecting a schema here fieldTypeName=" + fieldTypeName + " " + dataTypeNodeId.toString() + " category = " + category);
|
|
280
|
+
}
|
|
281
|
+
const v2 = {
|
|
282
|
+
category,
|
|
283
|
+
fieldTypeName,
|
|
284
|
+
schema
|
|
285
|
+
};
|
|
286
|
+
return v2;
|
|
287
|
+
});
|
|
263
288
|
}
|
|
264
289
|
async function _setupEncodings(session, dataTypeNodeId, dataTypeDescription, schema) {
|
|
265
290
|
// read abstract flag
|
|
@@ -276,89 +301,146 @@ async function _setupEncodings(session, dataTypeNodeId, dataTypeDescription, sch
|
|
|
276
301
|
}
|
|
277
302
|
return schema;
|
|
278
303
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
const baseSchema = structureInfo?.schema;
|
|
285
|
-
if (baseSchema) {
|
|
286
|
-
const possibleFields = (0, node_opcua_factory_1.extractAllPossibleFields)(baseSchema);
|
|
287
|
-
fieldCountToIgnore += possibleFields.length;
|
|
304
|
+
async function findBasicDataTypeEx(session, dataTypeNodeId, cache) {
|
|
305
|
+
return await memoize(cache, "dataTypes", dataTypeNodeId, async () => {
|
|
306
|
+
const sessionEx = session;
|
|
307
|
+
if (!sessionEx._$$cache2) {
|
|
308
|
+
sessionEx._$$cache2 = new Map();
|
|
288
309
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
const isUnion = definition.structureType === node_opcua_types_1.StructureType.Union;
|
|
295
|
-
switch (definition.structureType) {
|
|
296
|
-
case node_opcua_types_1.StructureType.Union:
|
|
297
|
-
fields.push({
|
|
298
|
-
fieldType: "UInt32",
|
|
299
|
-
name: "SwitchField"
|
|
300
|
-
});
|
|
301
|
-
break;
|
|
302
|
-
case node_opcua_types_1.StructureType.Structure:
|
|
303
|
-
case node_opcua_types_1.StructureType.StructureWithOptionalFields:
|
|
304
|
-
break;
|
|
310
|
+
const key = dataTypeNodeId.toString();
|
|
311
|
+
if (sessionEx._$$cache2.has(key)) {
|
|
312
|
+
sessionEx._$$cacheHits = sessionEx._$$cacheHits == undefined ? 0 : sessionEx._$$cacheHits + 1;
|
|
313
|
+
// console.log("cache hit 2", key);
|
|
314
|
+
return sessionEx._$$cache2.get(key);
|
|
305
315
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
316
|
+
const d = await (0, node_opcua_pseudo_session_1.findBasicDataType)(session, dataTypeNodeId);
|
|
317
|
+
sessionEx._$$cache2.set(key, d);
|
|
318
|
+
return d;
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
async function nonReentrant(cache, prefix, dataTypeNodeId, func) {
|
|
322
|
+
const key = prefix + dataTypeNodeId.toString();
|
|
323
|
+
if (cache.$$resolveStuff?.has(key)) {
|
|
324
|
+
doDebug && console.log(" re-entering !" + key);
|
|
325
|
+
return await new Promise((resolve, reject) => {
|
|
326
|
+
cache.$$resolveStuff?.get(key).push([resolve, reject]);
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
cache.$$resolveStuff = cache.$$resolveStuff || new Map();
|
|
330
|
+
cache.$$resolveStuff.set(key, []);
|
|
331
|
+
return await new Promise((_resolve, _reject) => {
|
|
332
|
+
cache.$$resolveStuff.get(key).push([_resolve, _reject]);
|
|
333
|
+
(async () => {
|
|
334
|
+
try {
|
|
335
|
+
const result = await func();
|
|
336
|
+
const tmp = cache.$$resolveStuff.get(key);
|
|
337
|
+
cache.$$resolveStuff.delete(key);
|
|
338
|
+
for (const [resolve] of tmp) {
|
|
339
|
+
resolve(result);
|
|
327
340
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
341
|
+
}
|
|
342
|
+
catch (err) {
|
|
343
|
+
const tmp = cache.$$resolveStuff.get(key);
|
|
344
|
+
cache.$$resolveStuff.delete(key);
|
|
345
|
+
for (const [_resolve, reject] of tmp) {
|
|
346
|
+
reject(err);
|
|
332
347
|
}
|
|
333
|
-
const { schema, category, fieldTypeName, dataType, allowSubType } = rt;
|
|
334
|
-
field.fieldType = fieldTypeName;
|
|
335
|
-
field.category = category;
|
|
336
|
-
field.schema = schema;
|
|
337
|
-
field.dataType = dataType || fieldD.dataType;
|
|
338
|
-
field.allowSubType = allowSubType || false;
|
|
339
|
-
field.basicDataType = await (0, node_opcua_pseudo_session_1.findBasicDataType)(session, field.dataType);
|
|
340
|
-
fields.push(field);
|
|
341
348
|
}
|
|
349
|
+
})();
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
// eslint-disable-next-line max-statements, max-params
|
|
353
|
+
async function convertDataTypeDefinitionToStructureTypeSchema(session, dataTypeNodeId, name, definition, dataTypeDescription, dataTypeFactory, isAbstract, cache) {
|
|
354
|
+
return await nonReentrant(cache, "convertDataTypeDefinitionToStructureTypeSchema", dataTypeNodeId, async () => {
|
|
355
|
+
// warningLog(">> convertDataTypeDefinitionToStructureTypeSchema = ", dataTypeNodeId.toString());
|
|
356
|
+
if (definition instanceof node_opcua_types_1.StructureDefinition) {
|
|
357
|
+
let fieldCountToIgnore = 0;
|
|
358
|
+
const structureInfo = dataTypeFactory.getStructureInfoForDataType(definition.baseDataType);
|
|
359
|
+
const baseSchema = structureInfo?.schema;
|
|
360
|
+
if (baseSchema) {
|
|
361
|
+
const possibleFields = (0, node_opcua_factory_1.extractAllPossibleFields)(baseSchema);
|
|
362
|
+
fieldCountToIgnore += possibleFields.length;
|
|
363
|
+
}
|
|
364
|
+
// while (base && !(base.dataTypeNodeId.value === DataType.ExtensionObject && base.dataTypeNodeId.namespace === 0)) {
|
|
365
|
+
// fieldCountToIgnore += base..length;
|
|
366
|
+
// base = base.getBaseSchema();
|
|
367
|
+
// }
|
|
368
|
+
const fields = [];
|
|
369
|
+
const isUnion = definition.structureType === node_opcua_types_1.StructureType.Union;
|
|
370
|
+
switch (definition.structureType) {
|
|
371
|
+
case node_opcua_types_1.StructureType.Union:
|
|
372
|
+
fields.push({
|
|
373
|
+
fieldType: "UInt32",
|
|
374
|
+
name: "SwitchField"
|
|
375
|
+
});
|
|
376
|
+
break;
|
|
377
|
+
case node_opcua_types_1.StructureType.Structure:
|
|
378
|
+
case node_opcua_types_1.StructureType.StructureWithOptionalFields:
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
381
|
+
let switchValue = 1;
|
|
382
|
+
let switchBit = 0;
|
|
383
|
+
const bitFields = isUnion ? undefined : [];
|
|
384
|
+
const postActions = [];
|
|
385
|
+
if (definition.fields) {
|
|
386
|
+
for (let i = fieldCountToIgnore; i < definition.fields.length; i++) {
|
|
387
|
+
const fieldD = definition.fields[i];
|
|
388
|
+
// we need to skip fields that have already been handled in base class
|
|
389
|
+
// promises.push((
|
|
390
|
+
await (async () => {
|
|
391
|
+
let field;
|
|
392
|
+
({ field, switchBit, switchValue } = createField(fieldD, switchBit, bitFields, isUnion, switchValue));
|
|
393
|
+
if (fieldD.dataType.value === dataTypeNodeId.value && fieldD.dataType.namespace === dataTypeNodeId.namespace) {
|
|
394
|
+
// this is a structure with a field of the same type
|
|
395
|
+
// push an empty placeholder that we will fill later
|
|
396
|
+
const fieldTypeName = await readBrowseNameWithCache(session, dataTypeNodeId, cache);
|
|
397
|
+
(field.fieldType = fieldTypeName), (field.category = node_opcua_factory_1.FieldCategory.complex);
|
|
398
|
+
fields.push(field);
|
|
399
|
+
const capturedField = field;
|
|
400
|
+
postActions.push((schema) => {
|
|
401
|
+
capturedField.schema = schema;
|
|
402
|
+
});
|
|
403
|
+
return;
|
|
404
|
+
;
|
|
405
|
+
}
|
|
406
|
+
const rt = (await resolveFieldType(session, fieldD.dataType, dataTypeFactory, cache));
|
|
407
|
+
if (!rt) {
|
|
408
|
+
errorLog("convertDataTypeDefinitionToStructureTypeSchema cannot handle field", fieldD.name, "in", name, "because " + fieldD.dataType.toString() + " cannot be resolved");
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
const { schema, category, fieldTypeName, dataType, allowSubType } = rt;
|
|
412
|
+
field.fieldType = fieldTypeName;
|
|
413
|
+
field.category = category;
|
|
414
|
+
field.schema = schema;
|
|
415
|
+
field.dataType = dataType || fieldD.dataType;
|
|
416
|
+
field.allowSubType = allowSubType || false;
|
|
417
|
+
field.basicDataType = await findBasicDataTypeEx(session, field.dataType, cache);
|
|
418
|
+
fields.push(field);
|
|
419
|
+
})();
|
|
420
|
+
// ));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
/// some server may provide definition.baseDataType to be i=22 (ExtensionObject)
|
|
424
|
+
/// instead of 12756 Union;
|
|
425
|
+
if (isUnion && (0, node_opcua_nodeid_1.sameNodeId)(definition.baseDataType, (0, node_opcua_nodeid_2.coerceNodeId)("i=22"))) {
|
|
426
|
+
definition.baseDataType = (0, node_opcua_nodeid_2.resolveNodeId)("i=1276"); // aka DataTypeIds.Union
|
|
427
|
+
}
|
|
428
|
+
const a = await resolveFieldType(session, definition.baseDataType, dataTypeFactory, cache);
|
|
429
|
+
const baseType = a ? a.fieldTypeName : isUnion ? "Union" : "ExtensionObject";
|
|
430
|
+
const os = new node_opcua_factory_1.StructuredTypeSchema({
|
|
431
|
+
baseType,
|
|
432
|
+
bitFields,
|
|
433
|
+
fields,
|
|
434
|
+
name,
|
|
435
|
+
dataTypeFactory
|
|
436
|
+
});
|
|
437
|
+
const structuredTypeSchema = await _setupEncodings(session, dataTypeNodeId, dataTypeDescription, os);
|
|
438
|
+
postActions.forEach((action) => action(structuredTypeSchema));
|
|
439
|
+
doDebug && console.log("DONE ! convertDataTypeDefinitionToStructureTypeSchema = ", dataTypeNodeId.toString());
|
|
440
|
+
return structuredTypeSchema;
|
|
342
441
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
if (isUnion && (0, node_opcua_nodeid_1.sameNodeId)(definition.baseDataType, (0, node_opcua_nodeid_2.coerceNodeId)("i=22"))) {
|
|
346
|
-
definition.baseDataType = (0, node_opcua_nodeid_2.resolveNodeId)("i=1276"); // aka DataTypeIds.Union
|
|
347
|
-
}
|
|
348
|
-
const a = await resolveFieldType(session, definition.baseDataType, dataTypeFactory, cache);
|
|
349
|
-
const baseType = a ? a.fieldTypeName : isUnion ? "Union" : "ExtensionObject";
|
|
350
|
-
const os = new node_opcua_factory_1.StructuredTypeSchema({
|
|
351
|
-
baseType,
|
|
352
|
-
bitFields,
|
|
353
|
-
fields,
|
|
354
|
-
name,
|
|
355
|
-
dataTypeFactory
|
|
356
|
-
});
|
|
357
|
-
const structuredTypeSchema = await _setupEncodings(session, dataTypeNodeId, dataTypeDescription, os);
|
|
358
|
-
postActions.forEach((action) => action(structuredTypeSchema));
|
|
359
|
-
return structuredTypeSchema;
|
|
360
|
-
}
|
|
361
|
-
throw new Error("Not Implemented");
|
|
442
|
+
throw new Error("Not Implemented");
|
|
443
|
+
});
|
|
362
444
|
function createField(fieldD, switchBit, bitFields, isUnion, switchValue) {
|
|
363
445
|
const field = {
|
|
364
446
|
fieldType: "",
|