//! A module for managing and sharing secrets in the Wooly Vault application. //! //! This module provides a [`Vault`] struct that holds a secret and allows it to be shared safely //! across the application using an [`Arc`] (Atomic Reference Counted) pointer. use std::collections::HashSet; use std::fmt::{Debug, Display}; use std::net::{IpAddr, SocketAddr}; use std::sync::Arc; use libpt::log::info; use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; /// A type alias for an [`Arc`] pointer to a [`Vault`] instance. /// /// This type is used to share a [`Vault`] instance across multiple parts of the application. pub type VaultRef = Arc; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Contestant { ip: IpAddr, } /// A struct that holds a secret and provides methods for accessing it. /// /// The [`Vault`] struct is designed to be shared safely across the application using an [`Arc`] pointer. #[derive(Debug, Clone)] pub struct Vault { /// The secret stored in the vault secret: String, contestants: Arc>>, winners: Arc>>, } impl From for Contestant { fn from(value: IpAddr) -> Self { Self { ip: value } } } impl From for Contestant { fn from(value: SocketAddr) -> Self { Self { ip: value.ip() } } } impl From<&SocketAddr> for Contestant { fn from(value: &SocketAddr) -> Self { Self { ip: value.ip() } } } impl Display for Contestant { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.ip) } } impl Vault { /// Creates a new [`Vault`] instance with the given secret. /// /// Returns an [`Arc`] pointer to the new [`Vault`] instance. /// /// # Returns /// /// A new [`Vault`] instance with the given secret. pub fn new(secret: &str) -> VaultRef { let v = Self { secret: secret.to_string(), contestants: Default::default(), winners: Default::default(), }; Arc::new(v) } /// Returns a reference to the secret stored in the vault. /// /// # Returns /// /// A reference to the secret stored in the vault. pub fn secret(&self) -> &str { &self.secret } pub async fn add_contestant(&self, contestant: Contestant) -> bool { info!("new contestant: {contestant}"); self.contestants.lock().await.insert(contestant) } pub async fn add_winner(&self, contestant: Contestant) -> bool { info!("new winner: {contestant}"); self.winners.lock().await.insert(contestant) } pub async fn contestants(&self) -> HashSet { self.contestants.lock().await.clone() } pub async fn winners(&self) -> HashSet { self.winners.lock().await.clone() } }