use super::*;
use crate::device::AuditWriteSource;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AuditSendDelay(u16);
impl AuditSendDelay {
pub fn new(seconds: u32) -> Result<Self, Error> {
if seconds > 3600 {
return Err(crate::common::value_out_of_range_error());
}
Ok(Self(seconds as u16))
}
pub fn seconds(self) -> u16 {
self.0
}
}
impl AuditReporterObject {
pub fn set_maximum_send_delay(&mut self, delay: Option<AuditSendDelay>) -> Result<(), Error> {
let mut next = self.configuration_internal();
next.maximum_send_delay = delay;
self.change_configuration(next, None)
}
pub fn set_send_now(&mut self, value: bool) -> Result<(), Error> {
self.command_send_now(value, None)
}
fn command_send_now(
&mut self,
value: bool,
source: Option<&AuditWriteSource>,
) -> Result<(), Error> {
if self.configuration_internal().maximum_send_delay.is_none() {
return Err(crate::common::unknown_property_error());
}
if let Some(sink) = self.change_sink.as_ref().and_then(std::sync::Weak::upgrade) {
if !sink.is_active() {
return Err(crate::common::write_access_denied_error());
}
return sink.send_now(
self.oid,
&self.status,
value,
source,
self.clock.as_ref().and_then(|clock| clock.read_clock()),
);
}
if self.change_owner.upgrade().is_some() {
return Err(crate::common::write_access_denied_error());
}
self.status.commit_send_now(value, 0, false)?;
Ok(())
}
}
impl AuditReporterAuthority<'_> {
pub fn write_property(
&mut self,
property: PropertyIdentifier,
value: PropertyValue,
index: Option<u32>,
source: Option<&AuditWriteSource>,
) -> Result<(), Error> {
if property == PropertyIdentifier::DESCRIPTION {
return self.write_description(value, index, source);
}
if !matches!(
property,
PropertyIdentifier::MAXIMUM_SEND_DELAY | PropertyIdentifier::SEND_NOW
) {
return Err(crate::common::write_access_denied_error());
}
let mut next = self.0.configuration_internal();
if next.maximum_send_delay.is_none() {
return Err(crate::common::unknown_property_error());
}
if index.is_some() {
return Err(crate::common::property_is_not_an_array_error());
}
if matches!(value, PropertyValue::Null) {
return self.0.change_configuration(next, source);
}
match (property, value) {
(PropertyIdentifier::MAXIMUM_SEND_DELAY, PropertyValue::Unsigned(seconds)) => {
let seconds = u32::try_from(seconds)
.map_err(|_| crate::common::value_out_of_range_error())?;
next.maximum_send_delay = Some(AuditSendDelay::new(seconds)?);
self.0.change_configuration(next, source)
}
(PropertyIdentifier::SEND_NOW, PropertyValue::Boolean(value)) => {
self.0.command_send_now(value, source)
}
_ => Err(crate::common::invalid_data_type_error()),
}
}
}
impl AuditReporterStatus {
#[doc(hidden)]
pub fn capture_revision(&self) -> u64 {
self.0.lock().unwrap().capture_revision
}
#[doc(hidden)]
pub fn configuration_epoch(&self) -> u64 {
self.0.lock().unwrap().configuration_epoch
}
#[doc(hidden)]
pub fn send_now(&self) -> bool {
self.0.lock().unwrap().send_now
}
#[doc(hidden)]
pub fn validate_send_now(&self, captured: bool) -> Result<(), Error> {
let state = self.0.lock().unwrap();
if state.command_revision == u64::MAX || (captured && state.capture_revision == u64::MAX) {
return Err(Error::Encoding("audit command revision exhausted".into()));
}
Ok(())
}
#[doc(hidden)]
pub fn commit_send_now(&self, value: bool, fence: u64, captured: bool) -> Result<(), Error> {
let mut state = self.0.lock().unwrap();
let revision = state
.command_revision
.checked_add(1)
.ok_or_else(|| Error::Encoding("audit command revision exhausted".into()))?;
let capture = if captured {
state
.capture_revision
.checked_add(1)
.ok_or_else(|| Error::Encoding("audit capture revision exhausted".into()))?
} else {
state.capture_revision
};
state.command_revision = revision;
state.capture_revision = capture;
state.send_now = value && fence != 0;
if value {
state.command_fence = fence;
}
Ok(())
}
#[doc(hidden)]
pub fn settle_send_now(&self, first_unsent: Option<u64>) {
let mut state = self.0.lock().unwrap();
if first_unsent.is_none_or(|first| first > state.command_fence) {
state.send_now = false;
}
}
}