node-opcua-client-dynamic-extension-object
Advanced tools
Comparing version 2.6.4 to 2.6.5
@@ -39,2 +39,3 @@ "use strict"; | ||
if (!a.targets || a.targets.length === 0) { | ||
// the server is probably version < 1.04. | ||
debugLog("Cannot find Deprecated property for dataTypeDictionary " + dataTypeDictionary.toString()); | ||
@@ -91,2 +92,6 @@ return false; | ||
} | ||
/* istanbul ignore next */ | ||
if (nodesToBrowse3.length === 0) { | ||
return []; | ||
} | ||
const results3 = yield session.browse(nodesToBrowse3); | ||
@@ -121,17 +126,19 @@ const binaryEncodings = []; | ||
} | ||
const results4 = yield session.browse(nodesToBrowseDataType); | ||
const dataTypeNodeIds = []; | ||
i = 0; | ||
for (const result4 of results4) { | ||
result4.references = result4.references || []; | ||
/* istanbul ignore next */ | ||
if (result4.references.length !== 1) { | ||
console.log("What's going on ?", result4.toString()); | ||
if (nodesToBrowseDataType.length > 0) { | ||
const results4 = yield session.browse(nodesToBrowseDataType); | ||
i = 0; | ||
for (const result4 of results4) { | ||
result4.references = result4.references || []; | ||
/* istanbul ignore next */ | ||
if (result4.references.length !== 1) { | ||
console.log("What's going on ?", result4.toString()); | ||
} | ||
for (const ref of result4.references) { | ||
const dataTypeNodeId = ref.nodeId; | ||
dataTypeNodeIds.push(dataTypeNodeId); | ||
const dataTypeDescription = dataTypeDescriptions[i++]; | ||
dataTypeDescription.encodings.dataTypeNodeId = dataTypeNodeId; | ||
} | ||
} | ||
for (const ref of result4.references) { | ||
const dataTypeNodeId = ref.nodeId; | ||
dataTypeNodeIds.push(dataTypeNodeId); | ||
const dataTypeDescription = dataTypeDescriptions[i++]; | ||
dataTypeDescription.encodings.dataTypeNodeId = dataTypeNodeId; | ||
} | ||
} | ||
@@ -154,3 +161,3 @@ return dataTypeNodeIds; | ||
if (references.length === 0) { | ||
//xx throw new Error("Cannot find encodings on type " + dataTypeNodeId.toString() + " statusCode " + result.statusCode.toString()); | ||
// xx throw new Error("Cannot find encodings on type " + dataTypeNodeId.toString() + " statusCode " + result.statusCode.toString()); | ||
} | ||
@@ -217,3 +224,3 @@ const encodings = { | ||
const dataTypeNodeIds = yield _enrichWithDescriptionOf(session, dataTypeDescriptions); | ||
// now read DataTypeDefition attributes of all the dataTypeNodeIds, this will only contains concrete structure | ||
// now read DataTypeDefinition attributes of all the dataTypeNodeIds, this will only contains concrete structure | ||
const nodesToRead = dataTypeNodeIds.map((nodeId) => ({ | ||
@@ -243,3 +250,3 @@ attributeId: node_opcua_data_model_1.AttributeIds.DataTypeDefinition, nodeId, | ||
} | ||
// to do put in logicial order | ||
// to do put in logical order | ||
const dataTypeDefinitionsSorted = sortStructure(dataTypeDefinitions); | ||
@@ -252,3 +259,3 @@ if (doDebug) { | ||
if (doDebug) { | ||
console.log(chalk.yellow("--------------------------------------- "), className, dataTypeNodeId.toString()); | ||
debugLog(chalk.yellow("--------------------------------------- "), className, dataTypeNodeId.toString()); | ||
} | ||
@@ -292,15 +299,17 @@ if (dataTypeFactory.hasStructuredType(className)) { | ||
} | ||
function _extractDataTypeDictionary(session, dataTypeDictionaryNodeId, dataTypeManager) { | ||
; | ||
function _extractDataTypeDictionary(session, d, dataTypeManager) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const isDictionaryDeprecated = yield _readDeprecatedFlag(session, dataTypeDictionaryNodeId); | ||
const rawSchemaDataValue = yield session.read({ nodeId: dataTypeDictionaryNodeId, attributeId: node_opcua_data_model_1.AttributeIds.Value }); | ||
const dataTypeDictionaryNodeId = d.reference.nodeId; | ||
const isDictionaryDeprecated = d.isDictionaryDeprecated; // await _readDeprecatedFlag(session, dataTypeDictionaryNodeId); | ||
const rawSchema = d.rawSchema; // DataValue = await session.read({ nodeId: dataTypeDictionaryNodeId, attributeId: AttributeIds.Value }); | ||
const name = yield session.read({ nodeId: dataTypeDictionaryNodeId, attributeId: node_opcua_data_model_1.AttributeIds.BrowseName }); | ||
const namespace = yield _readNamespaceUriProperty(session, dataTypeDictionaryNodeId); | ||
if (isDictionaryDeprecated || !rawSchemaDataValue.value.value) { | ||
if (isDictionaryDeprecated || rawSchema.length === 0) { | ||
debugLog("DataTypeDictionary is deprecated or BSD schema stored in dataValue is null !", chalk.cyan(name.value.value.toString()), "namespace =", namespace); | ||
debugLog("lets use the new way (1.04) and let's crawl all dataTypes exposed by this name space"); | ||
// dataType definition in store directily in UADataType under the $definition property | ||
debugLog("let's use the new way (1.04) and let's crawl all dataTypes exposed by this name space"); | ||
// dataType definition in store directly in UADataType under the $definition property | ||
const dataTypeFactory2 = dataTypeManager.getDataTypeFactory(dataTypeDictionaryNodeId.namespace); | ||
if (!dataTypeFactory2) { | ||
throw new Error("cannot find dataTypeFactort for namespace " + dataTypeDictionaryNodeId.namespace); | ||
throw new Error("cannot find dataTypeFactory for namespace " + dataTypeDictionaryNodeId.namespace); | ||
} | ||
@@ -314,3 +323,2 @@ yield _extractDataTypeDictionaryFromDefinition(session, dataTypeDictionaryNodeId, dataTypeFactory2); | ||
// one need to read the schema file store in the dataTypeDictionary node and parse it ! | ||
const rawSchema = rawSchemaDataValue.value.value.toString(); | ||
/* istanbul ignore next */ | ||
@@ -405,8 +413,16 @@ if (doDebug) { | ||
const namespaceArray = dataValueNamespaceArray.value.value; | ||
if (dataValueNamespaceArray.statusCode === node_opcua_status_code_1.StatusCodes.Good && | ||
(namespaceArray && namespaceArray.length > 0)) { | ||
// istanbul ignore next | ||
if (!namespaceArray) { | ||
// throw new Error("Cannot get Server_NamespaceArray as a array of string"); | ||
return; | ||
} | ||
// istanbul ignore next | ||
if (doDebug) { | ||
debugLog("namespaceArray ", namespaceArray.map((a, index) => " " + index.toString().padEnd(3) + ":" + a).join(" ")); | ||
} | ||
if (dataValueNamespaceArray.statusCode === node_opcua_status_code_1.StatusCodes.Good && (namespaceArray && namespaceArray.length > 0)) { | ||
dataTypeManager.setNamespaceArray(namespaceArray); | ||
for (let namespaceIndex = 1; namespaceIndex < namespaceArray.length; namespaceIndex++) { | ||
if (!dataTypeManager.hasDataTypeFactory(namespaceIndex)) { | ||
const dataTypeFactory1 = new node_opcua_factory_1.DataTypeFactory([node_opcua_factory_1.getStandartDataTypeFactory()]); | ||
const dataTypeFactory1 = new node_opcua_factory_1.DataTypeFactory([node_opcua_factory_1.getStandardDataTypeFactory()]); | ||
dataTypeManager.registerDataTypeFactory(namespaceIndex, dataTypeFactory1); | ||
@@ -424,3 +440,2 @@ } | ||
const opcBinaryNodeId = node_opcua_nodeid_1.resolveNodeId("OPCBinarySchema_TypeSystem"); | ||
debugLog(opcBinaryNodeId.toString()); | ||
// let find all DataType dictionary node corresponding to a given namespace | ||
@@ -446,24 +461,141 @@ // (have DataTypeDictionaryType) | ||
node_opcua_nodeid_1.sameNodeId(e.typeDefinition, dataTypeDictionaryType)); | ||
debugLog(`found ${references.length} dictionnary`); | ||
debugLog(`found ${references.length} dictionary`); | ||
function putInCorrectOrder() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const infos = []; | ||
const innerMap = {}; | ||
for (const reference of references) { | ||
const dataTypeDictionaryNodeId = reference.nodeId; | ||
const isDictionaryDeprecated = yield _readDeprecatedFlag(session, dataTypeDictionaryNodeId); | ||
const rawSchemaDataValue = yield session.read({ nodeId: dataTypeDictionaryNodeId, attributeId: node_opcua_data_model_1.AttributeIds.Value }); | ||
const rawSchema = rawSchemaDataValue.value.value ? rawSchemaDataValue.value.value.toString() : ""; | ||
const info = { | ||
dataTypeDictionaryNodeId, | ||
dependencies: {}, | ||
isDictionaryDeprecated, | ||
rawSchema, | ||
reference, | ||
targetNamespace: "", | ||
}; | ||
infos.push(info); | ||
if (!isDictionaryDeprecated && rawSchema.length > 0) { | ||
const matches = rawSchema.match(/<opc:TypeDictionary(.*)>/); | ||
if (matches) { | ||
// extract xml:NS="namespace" from attribute list | ||
// for instance: | ||
// <opc:TypeDictionary | ||
// xmlns:opc="http://opcfoundation.org/BinarySchema/" | ||
// xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
// xmlns:ua="http://opcfoundation.org/UA/" | ||
// xmlns:tns="urn:SomeName:Ua:Types:GlobalTypes" | ||
// DefaultByteOrder="LittleEndian" | ||
// TargetNamespace="urn:SomeName:Ua:Types:GlobalTypes"> | ||
const typeDictionaryElementAttributes = matches[1]; | ||
const c2 = typeDictionaryElementAttributes.match(/TargetNamespace="([^\"]+)"/); | ||
if (c2) { | ||
info.targetNamespace = c2[1]; | ||
} | ||
const nsKeyNamespace = {}; | ||
for (const attribute of typeDictionaryElementAttributes.split(" ")) { | ||
const c = attribute.match(/xmlns:(.*)=\"([^\"]+)\"/); | ||
if (c) { | ||
const xmlns = c[1]; | ||
const namespace = c[2]; | ||
nsKeyNamespace[xmlns] = namespace; | ||
debugLog("xxxx ns= ", xmlns, "=>", namespace); | ||
} | ||
} | ||
info.dependencies = nsKeyNamespace; | ||
debugLog("xxx targetNamespace = ", info.targetNamespace); | ||
innerMap[info.targetNamespace] = info; | ||
} | ||
} | ||
else { | ||
// may be 1.04 => the rawScheme is no more needed in new version | ||
info.targetNamespace = namespaceArray[dataTypeDictionaryNodeId.namespace]; | ||
debugLog("xxx targetNamespace = ", info.targetNamespace); | ||
innerMap[info.targetNamespace] = info; | ||
} | ||
node_opcua_assert_1.assert(info.targetNamespace.length !== 0); | ||
} | ||
// ---------------------------------- | ||
const orderedList = []; | ||
const visited = {}; | ||
function explore(d) { | ||
if (visited[d.targetNamespace]) { | ||
return; | ||
} | ||
visited[d.targetNamespace] = 1; | ||
for (const [xmlns, namespace] of Object.entries(d.dependencies)) { | ||
if (!innerMap[namespace] || namespace === d.targetNamespace) { | ||
continue; | ||
} | ||
explore(innerMap[namespace]); | ||
} | ||
orderedList.push(d); | ||
} | ||
for (const d of infos) { | ||
explore(d); | ||
} | ||
debugLog(" Ordered List = ", orderedList.map(a => a.targetNamespace).join(" ")); | ||
return orderedList; | ||
}); | ||
} | ||
const dataTypeDictionaryInfo = yield putInCorrectOrder(); | ||
// setup dependencies | ||
const map = {}; | ||
for (const d of dataTypeDictionaryInfo) { | ||
map[d.targetNamespace] = d; | ||
debugLog(" fixing based dataTypeFactory dependencies for ", d.targetNamespace, "index = ", d.dataTypeDictionaryNodeId.namespace); | ||
const baseDataFactories = [node_opcua_factory_1.getStandardDataTypeFactory()]; | ||
for (const namespace of Object.values(d.dependencies)) { | ||
if (namespace === d.targetNamespace) { | ||
continue; | ||
} | ||
const baseDataFactory = map[namespace]; | ||
if (!baseDataFactory) { | ||
// xx console.log("xxxxx baseDataFactory = ", namespace); | ||
continue; | ||
} | ||
const namespaceIndex = baseDataFactory.dataTypeDictionaryNodeId.namespace; | ||
if (dataTypeManager.hasDataTypeFactory(namespaceIndex)) { | ||
const dep = dataTypeManager.getDataTypeFactory(namespaceIndex); | ||
baseDataFactories.push(dep); | ||
debugLog(" considering , ", baseDataFactory.targetNamespace, "index = ", baseDataFactory.dataTypeDictionaryNodeId.namespace); | ||
} | ||
} | ||
const dataTypeFactory = dataTypeManager.getDataTypeFactory(d.dataTypeDictionaryNodeId.namespace); | ||
dataTypeFactory.repairBaseDataFactories(baseDataFactories); | ||
} | ||
// -------------------- | ||
// now investigate DataTypeDescriptionType | ||
yield (() => __awaiter(this, void 0, void 0, function* () { | ||
function processReference2(ref) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const dataTypeDicitionaryNodeId = ref.nodeId; | ||
// xx const dataTypeFactory = dataTypeManager.getDataTypeFactoryForNamespace(dataTypeDicitionaryNodeId.namespace); | ||
yield _extractDataTypeDictionary(session, dataTypeDicitionaryNodeId, dataTypeManager); | ||
/* istanbul ignore next */ | ||
if (doDebug) { | ||
debugLog(chalk.bgWhite(" => "), ref.browseName.toString(), ref.nodeId.toString()); | ||
} | ||
const dataTypeFactory = dataTypeManager.getDataTypeFactoryForNamespace(dataTypeDicitionaryNodeId.namespace); | ||
yield _exploreDataTypeDefinition(session, dataTypeDicitionaryNodeId, dataTypeFactory, dataTypeManager.namespaceArray); | ||
function processReferenceOnDataTypeDictionaryType(d) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
debugLog(chalk.cyan("processReferenceOnDataTypeDictionaryType on "), d.targetNamespace); | ||
const ref = d.reference; | ||
const dataTypeDictionaryNodeId = d.reference.nodeId; | ||
yield _extractDataTypeDictionary(session, d, dataTypeManager); | ||
/* istanbul ignore next */ | ||
if (doDebug) { | ||
debugLog(chalk.bgWhite(" => "), ref.browseName.toString(), ref.nodeId.toString()); | ||
} | ||
const dataTypeFactory = dataTypeManager.getDataTypeFactoryForNamespace(dataTypeDictionaryNodeId.namespace); | ||
yield _exploreDataTypeDefinition(session, dataTypeDictionaryNodeId, dataTypeFactory, dataTypeManager.namespaceArray); | ||
}); | ||
} | ||
// https://medium.com/swlh/dealing-with-multiple-promises-in-javascript-41d6c21f20ff | ||
for (const d of dataTypeDictionaryInfo) { | ||
try { | ||
yield processReferenceOnDataTypeDictionaryType(d).catch(e => { | ||
console.log(e); | ||
debugLog("processReferenceOnDataTypeDictionaryType has failed "); | ||
debugLog("Error", e.message); | ||
debugLog(e); | ||
return e; | ||
}); | ||
} | ||
const promises2 = []; | ||
for (const ref of references) { | ||
promises2.push(processReference2(ref)); | ||
catch (err) { | ||
debugLog(chalk.red("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "), err); | ||
} | ||
yield Promise.all(promises2); | ||
}))(); | ||
} | ||
debugLog("out ... populateDataTypeManager"); | ||
@@ -597,3 +729,4 @@ }); | ||
} | ||
const name = yield (yield session.read({ nodeId: dataTypeNodeId, attributeId: node_opcua_data_model_1.AttributeIds.BrowseName })).value.value.name; | ||
const nameDataValue = yield session.read({ nodeId: dataTypeNodeId, attributeId: node_opcua_data_model_1.AttributeIds.BrowseName }); | ||
const name = nameDataValue.value.value.name; | ||
const schema = dataTypeFactory.getStructuredTypeSchema(name); | ||
@@ -638,3 +771,3 @@ return schema; | ||
if (subTypeNodeId.namespace === 0 && subTypeNodeId.value <= 29) { | ||
// well knwow node ID ! | ||
// well known node ID ! | ||
switch (subTypeNodeId.value) { | ||
@@ -685,3 +818,3 @@ case 22: /* Structure */ | ||
if (dataValue.statusCode !== node_opcua_status_code_1.StatusCodes.Good) { | ||
const message = "cannot extract BrowseName of nodeId = " + nodeId.toString(); | ||
const message = "cannot extract BrowseName of nodeId = " + nodeId.toString() + " statusCode = " + dataValue.statusCode.toString(); | ||
debugLog(message); | ||
@@ -695,10 +828,3 @@ throw new Error(message); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if ((dataTypeNodeId.namespace === 0 && dataTypeNodeId.value === 22)) { | ||
// this is the default Structure ! | ||
// throw new Error("invalid nodeId " + dataTypeNodeId.toString()); | ||
/* istanbul ignore next */ | ||
if (doDebug) { | ||
console.log("resolveFieldType: Invalid NodeId ", dataTypeNodeId.toString()); | ||
console.log(pe.render(new Error())); | ||
} | ||
if (dataTypeNodeId.namespace === 0 && dataTypeNodeId.value === 22) { | ||
return null; | ||
@@ -813,6 +939,6 @@ } | ||
case node_opcua_types_1.StructureType.Union: | ||
//xx console.log("Union Found : ", name); | ||
// xx console.log("Union Found : ", name); | ||
fields.push({ | ||
fieldType: "UInt32", | ||
name: "SwitchField", | ||
fieldType: "UInt32" | ||
}); | ||
@@ -855,2 +981,3 @@ break; | ||
field.category = category; | ||
field.schema = schema; | ||
fields.push(field); | ||
@@ -857,0 +984,0 @@ } |
@@ -36,3 +36,3 @@ "use strict"; | ||
if (namespaceIndex === 0) { | ||
return node_opcua_factory_1.getStandartDataTypeFactory(); | ||
return node_opcua_factory_1.getStandardDataTypeFactory(); | ||
} | ||
@@ -63,3 +63,3 @@ return this.dataTypeFactoryMapByNamespace[namespaceIndex]; | ||
} | ||
write("ExtraDataTypeMananager"); | ||
write("ExtraDataTypeManager"); | ||
for (let n = 0; n < this.namespaceArray.length; n++) { | ||
@@ -66,0 +66,0 @@ write("-----------", this.namespaceArray[n]); |
@@ -1,4 +0,7 @@ | ||
import { DataValue } from "node-opcua-data-value"; | ||
import { IBasicSession } from "node-opcua-pseudo-session"; | ||
import { Variant } from "node-opcua-variant"; | ||
export declare function getExtraDataTypeManager(session: IBasicSession): Promise<any>; | ||
export declare function promoteOpaqueStructure(session: IBasicSession, dataValues: DataValue[]): Promise<void>; | ||
export interface PseudoDataValue { | ||
value: Variant; | ||
} | ||
export declare function promoteOpaqueStructure(session: IBasicSession, dataValues: PseudoDataValue[]): Promise<void>; |
@@ -30,2 +30,3 @@ "use strict"; | ||
exports.getExtraDataTypeManager = getExtraDataTypeManager; | ||
; | ||
function promoteOpaqueStructure(session, dataValues) { | ||
@@ -49,3 +50,4 @@ return __awaiter(this, void 0, void 0, function* () { | ||
})); | ||
yield Promise.all(promises); | ||
// https://medium.com/swlh/dealing-with-multiple-promises-in-javascript-41d6c21f20ff | ||
yield Promise.all(promises.map(p => p.catch(e => e))); | ||
}); | ||
@@ -52,0 +54,0 @@ } |
{ | ||
"name": "node-opcua-client-dynamic-extension-object", | ||
"version": "2.6.4", | ||
"version": "2.6.5", | ||
"description": "pure nodejs OPCUA SDK - module client-dynamic-extension-object", | ||
@@ -16,15 +16,15 @@ "main": "./dist/index.js", | ||
"node-opcua-binary-stream": "^2.6.1", | ||
"node-opcua-data-model": "^2.6.1", | ||
"node-opcua-data-value": "^2.6.4", | ||
"node-opcua-data-model": "^2.6.5", | ||
"node-opcua-data-value": "^2.6.5", | ||
"node-opcua-debug": "^2.6.1", | ||
"node-opcua-extension-object": "^2.6.1", | ||
"node-opcua-factory": "^2.6.1", | ||
"node-opcua-extension-object": "^2.6.5", | ||
"node-opcua-factory": "^2.6.5", | ||
"node-opcua-nodeid": "^2.6.1", | ||
"node-opcua-pseudo-session": "^2.6.4", | ||
"node-opcua-schemas": "^2.6.4", | ||
"node-opcua-service-browse": "^2.6.4", | ||
"node-opcua-service-translate-browse-path": "^2.6.4", | ||
"node-opcua-pseudo-session": "^2.6.5", | ||
"node-opcua-schemas": "^2.6.5", | ||
"node-opcua-service-browse": "^2.6.5", | ||
"node-opcua-service-translate-browse-path": "^2.6.5", | ||
"node-opcua-status-code": "^2.6.1", | ||
"node-opcua-types": "^2.6.4", | ||
"node-opcua-variant": "^2.6.1" | ||
"node-opcua-types": "^2.6.5", | ||
"node-opcua-variant": "^2.6.5" | ||
}, | ||
@@ -46,3 +46,3 @@ "author": "Etienne Rossignon", | ||
"homepage": "http://node-opcua.github.io/", | ||
"gitHead": "0d168bdc8351bbaf7ff9e60e21d459e8c4bdfeca" | ||
"gitHead": "e5e38142a719ebe22afb9617dce34b985d407d9b" | ||
} |
@@ -10,3 +10,2 @@ // tslint:disable: no-console | ||
import { assert } from "node-opcua-assert"; | ||
@@ -35,3 +34,3 @@ import { | ||
TypeSchemaBase, | ||
getStandartDataTypeFactory, | ||
getStandardDataTypeFactory, | ||
EnumerationDefinitionSchema, | ||
@@ -88,2 +87,3 @@ } from "node-opcua-factory"; | ||
if (!a.targets || a.targets.length === 0) { | ||
// the server is probably version < 1.04. | ||
debugLog("Cannot find Deprecated property for dataTypeDictionary " + dataTypeDictionary.toString()); | ||
@@ -111,5 +111,5 @@ return false; | ||
dataTypeDictionaryNodeId: NodeId | ||
): Promise<IDataTypeDescriptuon[]> { | ||
): Promise<IDataTypeDescription[]> { | ||
const nodeToBrowse2 = { | ||
const nodeToBrowse2: BrowseDescriptionLike = { | ||
browseDirection: BrowseDirection.Forward, | ||
@@ -130,3 +130,3 @@ includeSubtypes: false, | ||
session: IBasicSession, | ||
dataTypeDescriptions: IDataTypeDescriptuon[] | ||
dataTypeDescriptions: IDataTypeDescription[] | ||
): Promise<NodeId[]> { | ||
@@ -146,2 +146,6 @@ const nodesToBrowse3: BrowseDescriptionOptions[] = []; | ||
} | ||
/* istanbul ignore next */ | ||
if (nodesToBrowse3.length === 0) { | ||
return []; | ||
} | ||
const results3 = await session.browse(nodesToBrowse3); | ||
@@ -181,20 +185,22 @@ | ||
} | ||
const results4 = await session.browse(nodesToBrowseDataType); | ||
const dataTypeNodeIds: NodeId[] = []; | ||
i = 0; | ||
for (const result4 of results4) { | ||
result4.references = result4.references || []; | ||
if (nodesToBrowseDataType.length > 0) { | ||
const results4 = await session.browse(nodesToBrowseDataType); | ||
i = 0; | ||
for (const result4 of results4) { | ||
result4.references = result4.references || []; | ||
/* istanbul ignore next */ | ||
if (result4.references.length !== 1) { | ||
console.log("What's going on ?", result4.toString()); | ||
} | ||
/* istanbul ignore next */ | ||
if (result4.references.length !== 1) { | ||
console.log("What's going on ?", result4.toString()); | ||
} | ||
for (const ref of result4.references) { | ||
const dataTypeNodeId = ref.nodeId; | ||
for (const ref of result4.references) { | ||
const dataTypeNodeId = ref.nodeId; | ||
dataTypeNodeIds.push(dataTypeNodeId); | ||
dataTypeNodeIds.push(dataTypeNodeId); | ||
const dataTypeDescription = dataTypeDescriptions[i++]; | ||
dataTypeDescription.encodings!.dataTypeNodeId = dataTypeNodeId; | ||
const dataTypeDescription = dataTypeDescriptions[i++]; | ||
dataTypeDescription.encodings!.dataTypeNodeId = dataTypeNodeId; | ||
} | ||
} | ||
@@ -205,3 +211,3 @@ } | ||
interface IDataTypeDescriptuon { | ||
interface IDataTypeDescription { | ||
browseName: QualifiedName; | ||
@@ -213,3 +219,3 @@ nodeId: NodeId; | ||
async function _findEncodings(session: IBasicSession, dataTypeNodeId: NodeId): Promise<DataTypeAndEncodingId> { | ||
const nodeToBrowse = { | ||
const nodeToBrowse: BrowseDescriptionLike = { | ||
browseDirection: BrowseDirection.Forward, | ||
@@ -225,3 +231,3 @@ includeSubtypes: true, | ||
if (references.length === 0) { | ||
//xx throw new Error("Cannot find encodings on type " + dataTypeNodeId.toString() + " statusCode " + result.statusCode.toString()); | ||
// xx throw new Error("Cannot find encodings on type " + dataTypeNodeId.toString() + " statusCode " + result.statusCode.toString()); | ||
} | ||
@@ -307,3 +313,3 @@ const encodings: DataTypeAndEncodingId = { | ||
// now read DataTypeDefition attributes of all the dataTypeNodeIds, this will only contains concrete structure | ||
// now read DataTypeDefinition attributes of all the dataTypeNodeIds, this will only contains concrete structure | ||
const nodesToRead: ReadValueIdLike[] = dataTypeNodeIds.map((nodeId: NodeId) => ({ | ||
@@ -339,3 +345,3 @@ attributeId: AttributeIds.DataTypeDefinition, nodeId, | ||
} | ||
// to do put in logicial order | ||
// to do put in logical order | ||
const dataTypeDefinitionsSorted = sortStructure(dataTypeDefinitions); | ||
@@ -349,3 +355,3 @@ if (doDebug) { | ||
if (doDebug) { | ||
console.log(chalk.yellow("--------------------------------------- "), className, dataTypeNodeId.toString()); | ||
debugLog(chalk.yellow("--------------------------------------- "), className, dataTypeNodeId.toString()); | ||
} | ||
@@ -399,23 +405,34 @@ if (dataTypeFactory.hasStructuredType(className)) { | ||
interface TypeDictionaryInfo { | ||
reference: ReferenceDescription, | ||
dataTypeDictionaryNodeId: NodeId, | ||
isDictionaryDeprecated: boolean, | ||
rawSchema: string, | ||
dependencies: { [key: string]: string }, | ||
targetNamespace: string, | ||
}; | ||
async function _extractDataTypeDictionary( | ||
session: IBasicSession, | ||
dataTypeDictionaryNodeId: NodeId, | ||
d: TypeDictionaryInfo, | ||
dataTypeManager: ExtraDataTypeManager | ||
): Promise<void> { | ||
const isDictionaryDeprecated = await _readDeprecatedFlag(session, dataTypeDictionaryNodeId); | ||
const rawSchemaDataValue = await session.read({ nodeId: dataTypeDictionaryNodeId, attributeId: AttributeIds.Value }); | ||
const dataTypeDictionaryNodeId = d.reference.nodeId; | ||
const isDictionaryDeprecated = d.isDictionaryDeprecated; // await _readDeprecatedFlag(session, dataTypeDictionaryNodeId); | ||
const rawSchema = d.rawSchema; // DataValue = await session.read({ nodeId: dataTypeDictionaryNodeId, attributeId: AttributeIds.Value }); | ||
const name = await session.read({ nodeId: dataTypeDictionaryNodeId, attributeId: AttributeIds.BrowseName }); | ||
const namespace = await _readNamespaceUriProperty(session, dataTypeDictionaryNodeId); | ||
if (isDictionaryDeprecated || !rawSchemaDataValue.value.value) { | ||
if (isDictionaryDeprecated || rawSchema.length === 0) { | ||
debugLog("DataTypeDictionary is deprecated or BSD schema stored in dataValue is null !", chalk.cyan(name.value.value.toString()), "namespace =", namespace); | ||
debugLog("lets use the new way (1.04) and let's crawl all dataTypes exposed by this name space"); | ||
debugLog("let's use the new way (1.04) and let's crawl all dataTypes exposed by this name space"); | ||
// dataType definition in store directily in UADataType under the $definition property | ||
// dataType definition in store directly in UADataType under the $definition property | ||
const dataTypeFactory2 = dataTypeManager.getDataTypeFactory(dataTypeDictionaryNodeId.namespace); | ||
if (!dataTypeFactory2) { | ||
throw new Error("cannot find dataTypeFactort for namespace " + dataTypeDictionaryNodeId.namespace); | ||
throw new Error("cannot find dataTypeFactory for namespace " + dataTypeDictionaryNodeId.namespace); | ||
} | ||
@@ -429,4 +446,2 @@ await _extractDataTypeDictionaryFromDefinition(session, dataTypeDictionaryNodeId, dataTypeFactory2); | ||
// one need to read the schema file store in the dataTypeDictionary node and parse it ! | ||
const rawSchema = rawSchemaDataValue.value.value.toString(); | ||
/* istanbul ignore next */ | ||
@@ -451,3 +466,3 @@ if (doDebug) { | ||
const nodeToBrowse = { | ||
const nodeToBrowse: BrowseDescriptionLike = { | ||
browseDirection: BrowseDirection.Forward, | ||
@@ -537,15 +552,25 @@ includeSubtypes: false, | ||
const namespaceArray = dataValueNamespaceArray.value.value; | ||
const namespaceArray: string[] = dataValueNamespaceArray.value.value; | ||
if (dataValueNamespaceArray.statusCode === StatusCodes.Good && | ||
(namespaceArray && namespaceArray.length > 0)) { | ||
dataTypeManager.setNamespaceArray(namespaceArray as string[]); | ||
// istanbul ignore next | ||
if (!namespaceArray) { | ||
// throw new Error("Cannot get Server_NamespaceArray as a array of string"); | ||
return; | ||
} | ||
// istanbul ignore next | ||
if (doDebug) { | ||
debugLog("namespaceArray ", namespaceArray.map((a, index) => " " + index.toString().padEnd(3) + ":" + a).join(" ")); | ||
} | ||
if (dataValueNamespaceArray.statusCode === StatusCodes.Good && (namespaceArray && namespaceArray.length > 0)) { | ||
dataTypeManager.setNamespaceArray(namespaceArray); | ||
for (let namespaceIndex = 1; namespaceIndex < namespaceArray.length; namespaceIndex++) { | ||
if (!dataTypeManager.hasDataTypeFactory(namespaceIndex)) { | ||
const dataTypeFactory1 = new DataTypeFactory([getStandartDataTypeFactory()]); | ||
const dataTypeFactory1 = new DataTypeFactory([getStandardDataTypeFactory()]); | ||
dataTypeManager.registerDataTypeFactory(namespaceIndex, dataTypeFactory1); | ||
} | ||
} | ||
} | ||
@@ -564,4 +589,2 @@ | ||
debugLog(opcBinaryNodeId.toString()); | ||
// let find all DataType dictionary node corresponding to a given namespace | ||
@@ -591,28 +614,155 @@ // (have DataTypeDictionaryType) | ||
debugLog(`found ${references.length} dictionnary`); | ||
debugLog(`found ${references.length} dictionary`); | ||
// now investigate DataTypeDescriptionType | ||
await (async () => { | ||
async function processReference2(ref: ReferenceDescription): Promise<void> { | ||
async function putInCorrectOrder(): Promise<TypeDictionaryInfo[]> { | ||
const dataTypeDicitionaryNodeId = ref.nodeId; | ||
// xx const dataTypeFactory = dataTypeManager.getDataTypeFactoryForNamespace(dataTypeDicitionaryNodeId.namespace); | ||
const infos: TypeDictionaryInfo[] = []; | ||
const innerMap: { [key: string]: TypeDictionaryInfo } = {}; | ||
await _extractDataTypeDictionary(session, dataTypeDicitionaryNodeId, dataTypeManager); | ||
/* istanbul ignore next */ | ||
if (doDebug) { | ||
debugLog(chalk.bgWhite(" => "), ref.browseName.toString(), ref.nodeId.toString()); | ||
for (const reference of references) { | ||
const dataTypeDictionaryNodeId = reference.nodeId; | ||
const isDictionaryDeprecated = await _readDeprecatedFlag(session, dataTypeDictionaryNodeId); | ||
const rawSchemaDataValue = await session.read({ nodeId: dataTypeDictionaryNodeId, attributeId: AttributeIds.Value }); | ||
const rawSchema = rawSchemaDataValue.value.value ? rawSchemaDataValue.value.value.toString() : ""; | ||
const info: TypeDictionaryInfo = { | ||
dataTypeDictionaryNodeId, | ||
dependencies: {}, | ||
isDictionaryDeprecated, | ||
rawSchema, | ||
reference, | ||
targetNamespace: "", | ||
}; | ||
infos.push(info); | ||
if (!isDictionaryDeprecated && rawSchema.length > 0) { | ||
const matches = rawSchema.match(/<opc:TypeDictionary(.*)>/); | ||
if (matches) { | ||
// extract xml:NS="namespace" from attribute list | ||
// for instance: | ||
// <opc:TypeDictionary | ||
// xmlns:opc="http://opcfoundation.org/BinarySchema/" | ||
// xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
// xmlns:ua="http://opcfoundation.org/UA/" | ||
// xmlns:tns="urn:SomeName:Ua:Types:GlobalTypes" | ||
// DefaultByteOrder="LittleEndian" | ||
// TargetNamespace="urn:SomeName:Ua:Types:GlobalTypes"> | ||
const typeDictionaryElementAttributes = matches[1]; | ||
const c2 = typeDictionaryElementAttributes.match(/TargetNamespace="([^\"]+)"/); | ||
if (c2) { | ||
info.targetNamespace = c2[1]; | ||
} | ||
const nsKeyNamespace: { [key: string]: string } = {}; | ||
for (const attribute of typeDictionaryElementAttributes.split(" ")) { | ||
const c = attribute.match(/xmlns:(.*)=\"([^\"]+)\"/); | ||
if (c) { | ||
const xmlns = c[1]; | ||
const namespace = c[2]; | ||
nsKeyNamespace[xmlns] = namespace; | ||
debugLog("xxxx ns= ", xmlns, "=>", namespace); | ||
} | ||
} | ||
info.dependencies = nsKeyNamespace; | ||
debugLog("xxx targetNamespace = ", info.targetNamespace); | ||
innerMap[info.targetNamespace] = info; | ||
} | ||
} else { | ||
// may be 1.04 => the rawScheme is no more needed in new version | ||
info.targetNamespace = namespaceArray[dataTypeDictionaryNodeId.namespace]; | ||
debugLog("xxx targetNamespace = ", info.targetNamespace); | ||
innerMap[info.targetNamespace] = info; | ||
} | ||
const dataTypeFactory = dataTypeManager.getDataTypeFactoryForNamespace(dataTypeDicitionaryNodeId.namespace); | ||
await _exploreDataTypeDefinition(session, dataTypeDicitionaryNodeId, dataTypeFactory, dataTypeManager.namespaceArray); | ||
assert(info.targetNamespace.length !== 0); | ||
} | ||
// ---------------------------------- | ||
const orderedList: TypeDictionaryInfo[] = []; | ||
const visited: any = {}; | ||
function explore(d: TypeDictionaryInfo): void { | ||
if (visited[d.targetNamespace]) { | ||
return; | ||
} | ||
visited[d.targetNamespace] = 1; | ||
for (const [xmlns, namespace] of Object.entries(d.dependencies)) { | ||
if (!innerMap[namespace] || namespace === d.targetNamespace) { | ||
continue; | ||
} | ||
explore(innerMap[namespace]); | ||
} | ||
orderedList.push(d); | ||
} | ||
for (const d of infos) { | ||
explore(d); | ||
} | ||
debugLog(" Ordered List = ", orderedList.map(a => a.targetNamespace).join(" ")); | ||
return orderedList; | ||
} | ||
const dataTypeDictionaryInfo = await putInCorrectOrder(); | ||
// setup dependencies | ||
const map: { [key: string]: TypeDictionaryInfo } = {}; | ||
for (const d of dataTypeDictionaryInfo) { | ||
map[d.targetNamespace] = d; | ||
debugLog(" fixing based dataTypeFactory dependencies for ", d.targetNamespace, "index = ", d.dataTypeDictionaryNodeId.namespace); | ||
const baseDataFactories: DataTypeFactory[] = [getStandardDataTypeFactory()]; | ||
for (const namespace of Object.values(d.dependencies)) { | ||
if (namespace === d.targetNamespace) { | ||
continue; | ||
} | ||
const baseDataFactory = map[namespace]; | ||
if (!baseDataFactory) { | ||
// xx console.log("xxxxx baseDataFactory = ", namespace); | ||
continue; | ||
} | ||
const namespaceIndex = baseDataFactory.dataTypeDictionaryNodeId.namespace; | ||
if (dataTypeManager.hasDataTypeFactory(namespaceIndex)) { | ||
const dep = dataTypeManager.getDataTypeFactory(namespaceIndex); | ||
baseDataFactories.push(dep); | ||
debugLog(" considering , ", baseDataFactory.targetNamespace, "index = ", baseDataFactory.dataTypeDictionaryNodeId.namespace); | ||
} | ||
} | ||
const promises2: Promise<void>[] = []; | ||
for (const ref of references) { | ||
promises2.push(processReference2(ref)); | ||
const dataTypeFactory = dataTypeManager.getDataTypeFactory(d.dataTypeDictionaryNodeId.namespace); | ||
dataTypeFactory.repairBaseDataFactories(baseDataFactories); | ||
} | ||
// -------------------- | ||
// now investigate DataTypeDescriptionType | ||
async function processReferenceOnDataTypeDictionaryType(d: TypeDictionaryInfo): Promise<void> { | ||
debugLog(chalk.cyan("processReferenceOnDataTypeDictionaryType on "), d.targetNamespace); | ||
const ref = d.reference; | ||
const dataTypeDictionaryNodeId = d.reference.nodeId; | ||
await _extractDataTypeDictionary(session, d, dataTypeManager); | ||
/* istanbul ignore next */ | ||
if (doDebug) { | ||
debugLog(chalk.bgWhite(" => "), ref.browseName.toString(), ref.nodeId.toString()); | ||
} | ||
await Promise.all(promises2); | ||
const dataTypeFactory = dataTypeManager.getDataTypeFactoryForNamespace(dataTypeDictionaryNodeId.namespace); | ||
await _exploreDataTypeDefinition(session, dataTypeDictionaryNodeId, dataTypeFactory, dataTypeManager.namespaceArray); | ||
} | ||
})(); | ||
// https://medium.com/swlh/dealing-with-multiple-promises-in-javascript-41d6c21f20ff | ||
for (const d of dataTypeDictionaryInfo) { | ||
try { | ||
await processReferenceOnDataTypeDictionaryType(d).catch(e => { | ||
console.log(e); | ||
debugLog("processReferenceOnDataTypeDictionaryType has failed ") | ||
debugLog("Error", e.message); | ||
debugLog(e); | ||
return e; | ||
}); | ||
} catch (err) { | ||
debugLog(chalk.red("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "), err); | ||
} | ||
} | ||
debugLog("out ... populateDataTypeManager"); | ||
@@ -626,3 +776,3 @@ } | ||
const nodeToBrowse1 = { | ||
const nodeToBrowse1: BrowseDescriptionLike = { | ||
browseDirection: BrowseDirection.Forward, | ||
@@ -682,3 +832,3 @@ includeSubtypes: false, | ||
async function getDefinition(session: IBasicSession, defaultBinaryEncodingNodeId: NodeId): Promise<NodeId> { | ||
const nodeToBrowse2 = { | ||
const nodeToBrowse2: BrowseDescriptionLike = { | ||
browseDirection: BrowseDirection.Forward, | ||
@@ -714,3 +864,3 @@ includeSubtypes: false, | ||
// find parent node to access the xsd File | ||
const nodeToBrowse3 = { | ||
const nodeToBrowse3: BrowseDescriptionLike = { | ||
browseDirection: BrowseDirection.Inverse, | ||
@@ -767,4 +917,6 @@ includeSubtypes: false, | ||
} | ||
const name = await (await session.read({ nodeId: dataTypeNodeId, attributeId: AttributeIds.BrowseName })).value.value.name; | ||
const nameDataValue: DataValue = | ||
await session.read({ nodeId: dataTypeNodeId, attributeId: AttributeIds.BrowseName }); | ||
const name = nameDataValue.value.value.name!; | ||
const schema = dataTypeFactory.getStructuredTypeSchema(name); | ||
@@ -779,3 +931,3 @@ return schema; | ||
const nodeToBrowse3 = { | ||
const nodeToBrowse3: BrowseDescriptionLike = { | ||
browseDirection: BrowseDirection.Inverse, | ||
@@ -817,3 +969,3 @@ includeSubtypes: false, | ||
if (subTypeNodeId.namespace === 0 && subTypeNodeId.value <= 29) { | ||
// well knwow node ID ! | ||
// well known node ID ! | ||
switch (subTypeNodeId.value) { | ||
@@ -874,3 +1026,3 @@ case 22: /* Structure */ | ||
if (dataValue.statusCode !== StatusCodes.Good) { | ||
const message = "cannot extract BrowseName of nodeId = " + nodeId.toString(); | ||
const message = "cannot extract BrowseName of nodeId = " + nodeId.toString() + " statusCode = " + dataValue.statusCode.toString(); | ||
debugLog(message); | ||
@@ -889,10 +1041,3 @@ throw new Error(message); | ||
if ((dataTypeNodeId.namespace === 0 && dataTypeNodeId.value === 22)) { | ||
// this is the default Structure ! | ||
// throw new Error("invalid nodeId " + dataTypeNodeId.toString()); | ||
/* istanbul ignore next */ | ||
if (doDebug) { | ||
console.log("resolveFieldType: Invalid NodeId ", dataTypeNodeId.toString()); | ||
console.log(pe.render(new Error())); | ||
} | ||
if (dataTypeNodeId.namespace === 0 && dataTypeNodeId.value === 22) { | ||
return null; | ||
@@ -1032,6 +1177,6 @@ } | ||
case StructureType.Union: | ||
//xx console.log("Union Found : ", name); | ||
// xx console.log("Union Found : ", name); | ||
fields.push({ | ||
fieldType: "UInt32", | ||
name: "SwitchField", | ||
fieldType: "UInt32" | ||
}); | ||
@@ -1080,2 +1225,3 @@ break; | ||
field.category = category; | ||
field.schema = schema; | ||
fields.push(field); | ||
@@ -1082,0 +1228,0 @@ } |
@@ -10,3 +10,3 @@ /** | ||
DataTypeFactory, | ||
getStandartDataTypeFactory, | ||
getStandardDataTypeFactory, | ||
StructuredTypeSchema, | ||
@@ -57,3 +57,3 @@ } from "node-opcua-factory"; | ||
if (namespaceIndex === 0) { | ||
return getStandartDataTypeFactory(); | ||
return getStandardDataTypeFactory(); | ||
} | ||
@@ -90,3 +90,3 @@ return this.dataTypeFactoryMapByNamespace[namespaceIndex]; | ||
} | ||
write("ExtraDataTypeMananager"); | ||
write("ExtraDataTypeManager"); | ||
for (let n = 0; n < this.namespaceArray.length; n++) { | ||
@@ -93,0 +93,0 @@ write("-----------", this.namespaceArray[n]); |
import { DataValue } from "node-opcua-data-value"; | ||
import { OpaqueStructure } from "node-opcua-extension-object"; | ||
import { IBasicSession } from "node-opcua-pseudo-session"; | ||
import { DataType, VariantArrayType } from "node-opcua-variant"; | ||
import { DataType, VariantArrayType, Variant } from "node-opcua-variant"; | ||
@@ -22,9 +22,10 @@ import { populateDataTypeManager } from "./client_dynamic_extension_object"; | ||
export interface PseudoDataValue { value: Variant }; | ||
export async function promoteOpaqueStructure( | ||
session: IBasicSession, | ||
dataValues: DataValue[] | ||
dataValues: PseudoDataValue[] | ||
) { | ||
// count number of Opaque Structures | ||
const dataValuesToFix = dataValues.filter((dataValue: DataValue) => | ||
const dataValuesToFix = dataValues.filter((dataValue: PseudoDataValue) => | ||
dataValue.value && dataValue.value.dataType === DataType.ExtensionObject && | ||
@@ -49,6 +50,7 @@ ( | ||
const promises = dataValuesToFix.map( | ||
async (dataValue: DataValue) => { | ||
async (dataValue: PseudoDataValue) => { | ||
return await resolveDynamicExtensionObject(dataValue.value, extraDataTypeManager) | ||
}); | ||
await Promise.all(promises); | ||
// https://medium.com/swlh/dealing-with-multiple-promises-in-javascript-41d6c21f20ff | ||
await Promise.all(promises.map(p => p.catch(e => e))); | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
162847
2490
Updatednode-opcua-data-model@^2.6.5
Updatednode-opcua-data-value@^2.6.5
Updatednode-opcua-factory@^2.6.5
Updatednode-opcua-schemas@^2.6.5
Updatednode-opcua-types@^2.6.5
Updatednode-opcua-variant@^2.6.5