opcua_server/node_manager/
context.rs

1use std::sync::Arc;
2
3use crate::{
4    authenticator::{AuthManager, UserToken},
5    info::ServerInfo,
6    session::instance::Session,
7    SubscriptionCache,
8};
9use opcua_core::{sync::RwLock, trace_read_lock};
10use opcua_nodes::TypeTree;
11use opcua_types::{BrowseDescriptionResultMask, NodeId};
12use parking_lot::lock_api::{RawRwLock, RwLockReadGuard};
13use tracing::debug_span;
14use tracing_futures::Instrument;
15
16use super::{
17    view::{ExternalReferenceRequest, NodeMetadata},
18    DefaultTypeTree, NodeManagers,
19};
20
21/// Trait for providing a static reference to the type tree for a specific user.
22/// This allows subscriptions to hold a reference to the type tree.
23pub trait TypeTreeForUserStatic: Send + Sync {
24    /// Get the type tree read context. This may lock.
25    fn get_type_tree<'a>(&'a self) -> Box<dyn TypeTreeReadContext + 'a>;
26}
27
28impl<T> TypeTreeForUserStatic for RwLock<T>
29where
30    T: TypeTree + Send + Sync + 'static,
31{
32    fn get_type_tree<'a>(&'a self) -> Box<dyn TypeTreeReadContext + 'a> {
33        Box::new(trace_read_lock!(self))
34    }
35}
36
37/// Trait for providing a dynamic type tree for a user.
38/// This is a bit complex, it doesn't return a type tree directly,
39/// instead it returns something that wraps a type tree, for example
40/// a `RwLockReadGuard<'_, RawRwLock, dyn TypeTree>`
41pub trait TypeTreeForUser: Send + Sync {
42    /// Get the type tree for the user associated with the given `ctx`.
43    /// This can be the server global type tree, or a custom type tree for each individual user.
44    ///
45    /// It is sync, so you should do any setup in your [`AuthManager`] implementation.
46    fn get_type_tree_for_user<'a>(
47        &'a self,
48        ctx: &'a RequestContext,
49    ) -> Box<dyn TypeTreeReadContext + 'a>;
50
51    /// Get a static reference to a type tree getter for the current user.
52    /// This is used to allow subscriptions to hold a reference
53    /// to the type tree for events.
54    fn get_type_tree_static(&self, ctx: &RequestContext) -> Arc<dyn TypeTreeForUserStatic>;
55}
56
57pub(crate) struct DefaultTypeTreeGetter;
58
59impl TypeTreeForUser for DefaultTypeTreeGetter {
60    fn get_type_tree_for_user<'a>(
61        &'a self,
62        ctx: &'a RequestContext,
63    ) -> Box<dyn TypeTreeReadContext + 'a> {
64        Box::new(trace_read_lock!(ctx.type_tree))
65    }
66
67    fn get_type_tree_static(&self, ctx: &RequestContext) -> Arc<dyn TypeTreeForUserStatic> {
68        ctx.type_tree.clone()
69    }
70}
71
72/// Type returned from [`TypeTreeForUser`], a trait for something that dereferences
73/// to a `dyn TypeTree`.
74pub trait TypeTreeReadContext {
75    /// Dereference to a dynamic [TypeTree].
76    fn get(&self) -> &dyn TypeTree;
77}
78
79impl<R: RawRwLock, T: TypeTree> TypeTreeReadContext for RwLockReadGuard<'_, R, T> {
80    fn get(&self) -> &dyn TypeTree {
81        &**self
82    }
83}
84
85#[derive(Clone)]
86/// Context object passed during writes, contains useful context the node
87/// managers can use to execute service calls.
88pub struct RequestContext {
89    /// The full session object for the session responsible for this service call.
90    pub session: Arc<RwLock<Session>>,
91    /// The session ID for the session responsible for this service call.
92    pub session_id: u32,
93    /// The global `AuthManager` object.
94    pub authenticator: Arc<dyn AuthManager>,
95    /// The current user token.
96    pub token: UserToken,
97    /// Index of the current node manager.
98    pub current_node_manager_index: usize,
99    /// Global type tree object.
100    pub type_tree: Arc<RwLock<DefaultTypeTree>>,
101    /// Wrapper to get a type tree
102    pub type_tree_getter: Arc<dyn TypeTreeForUser>,
103    /// Subscription cache, containing all subscriptions on the server.
104    pub subscriptions: Arc<SubscriptionCache>,
105    /// Server info object, containing configuration and other shared server
106    /// state.
107    pub info: Arc<ServerInfo>,
108}
109
110impl RequestContext {
111    /// Get the type tree for the current user.
112    pub fn get_type_tree_for_user<'a>(&'a self) -> Box<dyn TypeTreeReadContext + 'a> {
113        self.type_tree_getter.get_type_tree_for_user(self)
114    }
115}
116
117/// Resolve a list of references.
118pub(crate) async fn resolve_external_references(
119    context: &RequestContext,
120    node_managers: &NodeManagers,
121    references: &[(&NodeId, BrowseDescriptionResultMask)],
122) -> Vec<Option<NodeMetadata>> {
123    let mut res: Vec<_> = references
124        .iter()
125        .map(|(n, mask)| ExternalReferenceRequest::new(n, *mask))
126        .collect();
127
128    for nm in node_managers.iter() {
129        let mut items: Vec<_> = res
130            .iter_mut()
131            .filter(|r| nm.owns_node(r.node_id()))
132            .collect();
133
134        nm.resolve_external_references(context, &mut items)
135            .instrument(debug_span!("resolve external references", node_manager = %nm.name()))
136            .await;
137    }
138
139    res.into_iter().map(|r| r.into_inner()).collect()
140}