Skip to content

Commit

Permalink
Recursive browser (#56)
Browse files Browse the repository at this point in the history
Utility for recursively browsing the node hierarchy clientside.

This is something a lot of OPC-UA client applications need to do at some point, which isn't necessarily trivial to implement well. It makes sense to include a generic utility for doing this in the client library. If it isn't sufficiently flexible users are always free to use it as a reference and build something using the services directly.
  • Loading branch information
einarmo authored Dec 18, 2024
1 parent f1bc40d commit a8005bd
Show file tree
Hide file tree
Showing 15 changed files with 1,336 additions and 413 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

75 changes: 74 additions & 1 deletion lib/tests/integration/browse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use opcua::{
RelativePathElement, StatusCode, VariableTypeId,
},
};
use opcua_types::{AttributeId, ReadValueId, TimestampsToReturn, Variant};
use opcua_client::browser::BrowseFilter;
use opcua_nodes::DefaultTypeTree;
use opcua_types::{AttributeId, ReadValueId, TimestampsToReturn, VariableId, Variant};

fn hierarchical_desc(node_id: NodeId) -> BrowseDescription {
BrowseDescription {
Expand Down Expand Up @@ -579,3 +581,74 @@ async fn translate_browse_paths_auto_impl() {
)))
);
}

#[tokio::test]
async fn test_recursive_browser() {
let (_tester, _nm, session) = setup().await;

let filter = BrowseFilter::new_hierarchical();
let to_browse = vec![filter.new_description_from_node(ObjectId::TypesFolder.into())];
let res = session
.browser()
.max_concurrent_requests(3)
.handler(filter)
.run_into_result(to_browse)
.await
.unwrap();

assert_eq!(3740, res.nodes.len());

// Try to get some event fields.
let rs: Vec<_> = res
.references
.find_references(
&ObjectTypeId::BaseEventType.into(),
None::<(NodeId, _)>,
&DefaultTypeTree::new(),
BrowseDirection::Forward,
)
.collect();

assert_eq!(rs.len(), 21);

assert!(rs
.iter()
.find(|r| *r.target_node == VariableId::BaseEventType_EventId)
.is_some());
}

#[tokio::test]
// Hit the same node multiple times.
async fn test_recursive_browser_multi_hit() {
let (_tester, _nm, session) = setup().await;

let filter = BrowseFilter::new(BrowseDirection::Forward, ReferenceTypeId::References, true);
let to_browse = vec![filter.new_description_from_node(ObjectId::TypesFolder.into())];
let res = session
.browser()
.max_concurrent_requests(3)
.handler(filter)
.run_into_result(to_browse)
.await
.unwrap();

assert_eq!(4228, res.nodes.len());

// This one will be referenced from many places.
assert!(res
.nodes
.contains_key(&NodeId::from(ObjectId::ModellingRule_Mandatory)));

// Get the nodes that have a mandatory modelling rule
let rs: Vec<_> = res
.references
.find_references(
&ObjectId::ModellingRule_Mandatory.into(),
None::<(NodeId, _)>,
&DefaultTypeTree::new(),
BrowseDirection::Inverse,
)
.collect();

assert_eq!(rs.len(), 2164);
}
8 changes: 5 additions & 3 deletions opcua-client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[package]
name = "opcua-client"
version = "0.13.0" # OPCUARustVersion
version = "0.13.0" # OPCUARustVersion
description = "OPC UA client API"
authors = ["Adam Lock <[email protected]>", "Einar Omang <[email protected]>"]
homepage = "https://github.com/locka99/opcua"
repository = "https://github.com/locka99/opcua"
license = "MPL-2.0"
keywords = ["opcua","opc","ua"]
categories = ["embedded","network-programming"]
keywords = ["opcua", "opc", "ua"]
categories = ["embedded", "network-programming"]
readme = "../README.md"
documentation = "https://docs.rs/opcua/"
edition = "2021"
Expand All @@ -20,6 +20,7 @@ arc-swap = { workspace = true }
async-trait = { workspace = true }
chrono = { workspace = true }
futures = { workspace = true }
hashbrown = { workspace = true }
lazy_static = { workspace = true }
log = { workspace = true }
parking_lot = { workspace = true }
Expand All @@ -32,4 +33,5 @@ serde = { workspace = true }
opcua-types = { path = "../opcua-types" }
opcua-core = { path = "../opcua-core" }
opcua-crypto = { path = "../opcua-crypto" }
opcua-nodes = { path = "../opcua-nodes" }
opcua-xml = { path = "../opcua-xml", optional = true }
Loading

0 comments on commit a8005bd

Please sign in to comment.