use crate::session::EndpointSession;
use bacnet_transport::port::TransportPort;
use bacnet_types::error::Error;
use std::sync::Arc;
use tokio::sync::RwLock;
impl<T: TransportPort + 'static> EndpointSession<T> {
pub(super) async fn prepare_identity(&mut self) -> Result<(), Error> {
let Some(identity) = self.identity.as_ref() else {
return Ok(());
};
let identity = identity.resolve(self.local_receive_capacity)?;
if let Some(database) = &self.database {
let database = database.read().await;
if let Some(oid) = database.selected_device() {
identity.validate_device(database.get(&oid).expect("selected under guard"))?;
}
}
if self.database.is_none() {
self.database = Some(Arc::new(RwLock::new(identity.build_database()?)));
}
self.client_config.max_apdu_length = identity.max_apdu_length();
self.config.max_apdu_length = identity.max_apdu_length();
self.identity = Some(identity);
Ok(())
}
}
struct IdentityPreparation<'a, T: TransportPort + 'static> {
session: &'a mut EndpointSession<T>,
original: Option<bacnet_objects::DeviceIdentity>,
had_database: bool,
client_capacity: u16,
session_capacity: u16,
committed: bool,
}
impl<T: TransportPort + 'static> Drop for IdentityPreparation<'_, T> {
fn drop(&mut self) {
if !self.committed {
self.session.identity = self.original.take();
self.session.client_config.max_apdu_length = self.client_capacity;
self.session.config.max_apdu_length = self.session_capacity;
if !self.had_database {
self.session.database = None;
}
}
}
}
impl<T: TransportPort + 'static> EndpointSession<T> {
pub(super) async fn prepare_start(
&mut self,
) -> Result<
(
Option<bacnet_types::primitives::ObjectIdentifier>,
Option<crate::source_audit::recipient::SourceRoutes>,
),
Error,
> {
let mut preparation = IdentityPreparation {
original: self.identity.clone(),
had_database: self.database.is_some(),
client_capacity: self.client_config.max_apdu_length,
session_capacity: self.config.max_apdu_length,
session: self,
committed: false,
};
preparation.session.validate_segmentation().await?;
preparation.session.prepare_identity().await?;
let device = preparation.session.validate_device_execution()?;
let routes = preparation.session.prepare_source_audit_reporter()?;
preparation.session.prepare_registered_port().await?;
preparation.session.commit_device_profile(device);
preparation.committed = true;
Ok((device, routes))
}
}