use std::{ops::Deref, sync::Arc};
use crate::{
authenticator::{AuthManager, UserToken},
info::ServerInfo,
session::instance::Session,
SubscriptionCache,
};
use opcua_core::{sync::RwLock, trace_read_lock};
use opcua_nodes::TypeTree;
use opcua_types::{BrowseDescriptionResultMask, NodeId};
use parking_lot::lock_api::{RawRwLock, RwLockReadGuard};
use tracing::debug_span;
use tracing_futures::Instrument;
use super::{
view::{ExternalReferenceRequest, NodeMetadata},
DefaultTypeTree, NodeManagers,
};
pub trait TypeTreeForUserStatic: Send + Sync {
fn get_type_tree<'a>(&'a self) -> Box<dyn TypeTreeReadContext + 'a>;
}
impl<T> TypeTreeForUserStatic for RwLock<T>
where
T: TypeTree + Send + Sync + 'static,
{
fn get_type_tree<'a>(&'a self) -> Box<dyn TypeTreeReadContext + 'a> {
Box::new(trace_read_lock!(self))
}
}
pub trait TypeTreeForUser: Send + Sync {
fn get_type_tree_for_user<'a>(
&'a self,
ctx: &'a RequestContext,
) -> Box<dyn TypeTreeReadContext + 'a>;
fn get_type_tree_static(&self, ctx: &RequestContext) -> Arc<dyn TypeTreeForUserStatic>;
}
pub(crate) struct DefaultTypeTreeGetter;
impl TypeTreeForUser for DefaultTypeTreeGetter {
fn get_type_tree_for_user<'a>(
&'a self,
ctx: &'a RequestContext,
) -> Box<dyn TypeTreeReadContext + 'a> {
Box::new(trace_read_lock!(ctx.type_tree))
}
fn get_type_tree_static(&self, ctx: &RequestContext) -> Arc<dyn TypeTreeForUserStatic> {
ctx.type_tree.clone()
}
}
pub trait TypeTreeReadContext {
fn get(&self) -> &dyn TypeTree;
}
impl<R: RawRwLock, T: TypeTree> TypeTreeReadContext for RwLockReadGuard<'_, R, T> {
fn get(&self) -> &dyn TypeTree {
&**self
}
}
#[derive(Clone)]
pub struct RequestContext {
pub current_node_manager_index: usize,
pub(crate) inner: Arc<RequestContextInner>,
}
impl Deref for RequestContext {
type Target = RequestContextInner;
fn deref(&self) -> &RequestContextInner {
&self.inner
}
}
pub struct RequestContextInner {
pub session: Arc<RwLock<Session>>,
pub session_id: u32,
pub authenticator: Arc<dyn AuthManager>,
pub token: UserToken,
pub type_tree: Arc<RwLock<DefaultTypeTree>>,
pub type_tree_getter: Arc<dyn TypeTreeForUser>,
pub subscriptions: Arc<SubscriptionCache>,
pub info: Arc<ServerInfo>,
}
impl RequestContext {
pub fn get_type_tree_for_user<'a>(&'a self) -> Box<dyn TypeTreeReadContext + 'a> {
self.type_tree_getter.get_type_tree_for_user(self)
}
pub fn session(&self) -> &RwLock<Session> {
&self.session
}
pub fn session_id(&self) -> u32 {
self.session_id
}
pub fn authenticator(&self) -> &dyn AuthManager {
self.authenticator.as_ref()
}
pub fn user_token(&self) -> &UserToken {
&self.token
}
pub fn type_tree(&self) -> &RwLock<DefaultTypeTree> {
&self.type_tree
}
pub fn subscriptions(&self) -> &SubscriptionCache {
&self.subscriptions
}
pub fn info(&self) -> &ServerInfo {
&self.info
}
}
pub(crate) async fn resolve_external_references(
context: &RequestContext,
node_managers: &NodeManagers,
references: &[(&NodeId, BrowseDescriptionResultMask)],
) -> Vec<Option<NodeMetadata>> {
let mut res: Vec<_> = references
.iter()
.map(|(n, mask)| ExternalReferenceRequest::new(n, *mask))
.collect();
for nm in node_managers.iter() {
let mut items: Vec<_> = res
.iter_mut()
.filter(|r| nm.owns_node(r.node_id()))
.collect();
nm.resolve_external_references(context, &mut items)
.instrument(debug_span!("resolve external references", node_manager = %nm.name()))
.await;
}
res.into_iter().map(|r| r.into_inner()).collect()
}