Skip to content

Commit

Permalink
add get_namespace_index(uri) to Session
Browse files Browse the repository at this point in the history
  • Loading branch information
Olivier authored and oroulet committed Jan 5, 2025
1 parent ed81732 commit 65198b5
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 3 deletions.
59 changes: 57 additions & 2 deletions opcua-client/src/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,9 @@ pub(crate) use session_trace;

use opcua_core::ResponseMessage;
use opcua_types::{
ApplicationDescription, ContextOwned, DecodingOptions, EndpointDescription, IntegerId,
NamespaceMap, NodeId, RequestHeader, ResponseHeader, StatusCode, TypeLoader, UAString,
ApplicationDescription, ContextOwned, DecodingOptions, EndpointDescription, Error, IntegerId,
NamespaceMap, NodeId, ReadValueId, RequestHeader, ResponseHeader, StatusCode,
TimestampsToReturn, TypeLoader, UAString, VariableId, Variant,
};

use crate::browser::Browser;
Expand Down Expand Up @@ -430,4 +431,58 @@ impl Session {
)),
)
}

/// Return namespace array from server and store in namespace cache
pub async fn read_namespace_array(&mut self) -> Result<NamespaceMap, Error> {
let nodeid: NodeId = VariableId::Server_NamespaceArray.into();
let result = self
.read(
&[ReadValueId::from(nodeid)],
TimestampsToReturn::Neither,
0.0,
)
.await
.map_err(|status_code| {
Error::new(status_code, "Reading Server namespace array failed")
})?;
if let Some(Variant::Array(array)) = &result[0].value {
let map = NamespaceMap::new_from_variant_array(&array.values)
.map_err(|e| Error::new(StatusCode::Bad, e))?;
let map_clone = map.clone();
self.set_namespaces(map);
Ok(map_clone)
} else {
Err(Error::new(
StatusCode::BadNoValue,
format!(
"Server namespace array is None. The server has an issue {:?}",
result
),
))
}
}

/// Return index of supplied namespace url from cache
pub fn get_namespace_index_from_cache(&mut self, url: &str) -> Option<u16> {
self.encoding_context.read().namespaces().get_index(url)
}

/// Return index of supplied namespace url
/// by first looking at namespace cache and querying server if necessary
pub async fn get_namespace_index(&mut self, url: &str) -> Result<u16, Error> {
if let Some(idx) = self.get_namespace_index_from_cache(url) {
return Ok(idx);
};
let map = self.read_namespace_array().await?;
let idx = map.get_index(url).ok_or_else(|| {
Error::new(
StatusCode::BadNoMatch,
format!(
"Url {} not found in namespace array. Namspace array is {:?}",
url, &map
),
)
})?;
Ok(idx)
}
}
22 changes: 21 additions & 1 deletion opcua-types/src/namespaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use hashbrown::HashMap;

use crate::{ExpandedNodeId, NodeId};
use crate::{errors::OpcUAError, ExpandedNodeId, NodeId, Variant};

/// Utility for handling assignment of namespaces on server startup.
#[derive(Debug, Default, Clone)]
Expand All @@ -26,6 +26,26 @@ impl NamespaceMap {
}
}

/// Create a new namespace map from a vec of variant as we get when reading
/// the namespace array from the server
pub fn new_from_variant_array(array: &[Variant]) -> Result<Self, OpcUAError> {
let known_namespaces: HashMap<String, u16> = array
.iter()
.enumerate()
.map(|(idx, v)| {
if let Variant::String(s) = v {
Ok((s.value().clone().unwrap_or(String::new()), idx as u16))
} else {
Err(OpcUAError::UnexpectedVariantType {
variant_id: v.scalar_type_id(),
message: "Namespace array on server contains invalid data".to_string(),
})
}
})
.collect::<Result<HashMap<_, _>, _>>()?;
Ok(Self { known_namespaces })
}

/// Add a new namespace, returning its index in the namespace map.
/// If the namespace is already added, its old index is returned.
pub fn add_namespace(&mut self, namespace: &str) -> u16 {
Expand Down

0 comments on commit 65198b5

Please sign in to comment.