//! Building `Message`s use super::*; use std::time::SystemTime; /// Builder for the `Message` type #[derive(Debug, Clone, PartialEq, Eq)] pub struct MessageBuilder { sign: bool, encrypt: bool, respond: Option, _phantom: PhantomData, } impl Default for MessageBuilder { #[inline] fn default() -> Self { Self::new() } } impl MessageBuilder { /// Create a new builder for a message with default settings pub const fn new() -> Self { Self { sign: false, encrypt: false, respond: None, _phantom: PhantomData, } } /// Specify if the message should be signed when serialized. pub const fn sign(mut self, sign: bool) -> Self { self.sign = sign; self } /// Specify if the message should be encrypted when serialized. /// /// A key will be generated randomly for the message on creation. pub const fn encrypt(mut self, encrypt: bool) -> Self { self.encrypt = encrypt; self } /// Specify a message ID that this message should respond to. pub const fn respond(mut self, to: Uuid) -> Self { self.respond = Some(to); self } /// Create a new builder with the capabilities of a sender #[cfg(nightly)] pub const fn for_sender() -> Self { Self::new() .sign(S::CAP_SIGN) .encrypt(S::CAP_ENCRYPT) } /// Create a new builder with the capabilities of a sender #[cfg(not(nightly))] pub fn for_sender() -> Self { Self::new() .sign(S::CAP_SIGN) .encrypt(S::CAP_ENCRYPT) } } impl MessageBuilder { /// Create a message from this builder with this value. pub fn create(self, value: V) -> eyre::Result> { let key = if self.encrypt { Some(aes::AesKey::generate().wrap_err(eyre!("Failed to generate session key"))?) } else { None }; let header = SerHeader::new(self.respond); Ok(Message { header, key, sign: self.sign, value, }) } } /// Get the current unix timestamp. pub(super) fn timestamp_now() -> u64 { match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { Ok(n) => n.as_secs(), Err(_) => panic!("Timestamp for now returned before unix epoch."), } } impl SerHeader { /// Create a new header with optional response ID. #[inline] pub fn new(responds: Option) -> Self { Self { id: Uuid::new_v4(), idemp: Uuid::new_v4(), timestamp: timestamp_now(), responds_to: responds, } } }