import { NodeId, NodeIdLike } from "node-opcua-nodeid"; import { BrowsePath, makeBrowsePath } from "node-opcua-service-translate-browse-path"; import { BrowseDirection, QualifiedNameLike, coerceQualifiedName } from "node-opcua-data-model"; import { IBasicSessionAsync } from "./basic_session_interface"; export async function findInTypeOrSuperType( session: IBasicSessionAsync, browsePath: BrowsePath ): Promise<{ nodeId: NodeId } | { nodeId: null; err: Error }> { const nodeId = browsePath.startingNode; const result = await session.translateBrowsePath(browsePath); if (result.statusCode.isGood()) { return { nodeId: result.targets![0].targetId as NodeId }; } // cannot be found here, go one step up const br = await session.browse({ nodeId, referenceTypeId: "HasSubtype", browseDirection: BrowseDirection.Inverse, includeSubtypes: true, nodeClassMask: 0, resultMask: 0 }); if (br.statusCode.isNotGood()) { // cannot find typeDefinition return { nodeId: null, err: new Error("cannot find typeDefinition") }; } const typeDefinition = br.references![0].nodeId; browsePath = new BrowsePath({ startingNode: typeDefinition, relativePath: browsePath.relativePath }); return await findInTypeOrSuperType(session, browsePath); } /** * * find a MethodId in a object or in its super type * * note: * - methodName is a browse name and may therefore be prefixed with a namespace index. * - if method is not found on the object specified by nodeId, then the findMethodId will * recursively browse up the hierarchy of object typeDefinition Node * until it reaches the root type. and try to find the first method that matches the * provided name. * * @param session * @param nodeId the nodeId of the object to find * @param methodName the method name to find prefixed with a namespace index (unless ns=0) * ( e.g "Add" or "Add" or "1:BumpCounter" ) */ export async function findMethodId( session: IBasicSessionAsync, nodeId: NodeIdLike, methodName: QualifiedNameLike ): Promise<{ methodId: NodeId } | { methodId: null; err: Error }> { const browsePath = makeBrowsePath(nodeId, "/" + coerceQualifiedName(methodName).toString()); const result = await session.translateBrowsePath(browsePath); if (result.statusCode.isNotGood()) { const br = await session.browse({ nodeId, referenceTypeId: "HasTypeDefinition", browseDirection: BrowseDirection.Forward, includeSubtypes: true, nodeClassMask: 0, resultMask: 0 }); if (br.statusCode.isNotGood()) { // cannot find typeDefinition return { methodId: null, err: new Error("cannot find typeDefinition") }; } const typeDefinition = br.references![0].nodeId; // need to find method on objectType const browsePath = makeBrowsePath(typeDefinition, "/" + methodName); const result = await findInTypeOrSuperType(session, browsePath); if (!result.nodeId) { return { err: result.err, methodId: null }; } return { methodId: result.nodeId }; } result.targets = result.targets || []; if (result.targets.length > 0) { const methodId = result.targets[0].targetId as NodeId; return { methodId }; } /* c8 ignore next */ else { // cannot find objectWithMethodNodeId const err = new Error(" cannot find " + methodName + " Method"); return { methodId: null, err }; } }