use tracing_subscriber::prelude::*; use tracing_subscriber::{fmt, EnvFilter}; pub use tracing::{error, warn, info, debug, trace}; #[cfg(feature="disabled")] mod disabled { //mod select; //use select::WeightedSet; mod api; mod utils; mod id; mod user; use tracing_subscriber::prelude::*; use tracing_subscriber::{fmt, EnvFilter}; pub use tracing::{error, warn, info, debug, trace}; use rand::prelude::*; use std::collections::HashSet; use std::collections::HashMap; #[derive(Debug, thiserror::Error)] pub enum NoError {} #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)] struct UserID(u128); impl std::fmt::Display for UserID { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "UserID({})", self.0) } } #[derive(Default)] struct Participants(Vec<(UserID, usize)>); trait Event { fn registered(&self, uid: UserID) -> bool; fn participated(&self, uid: UserID) -> bool { self.registered(uid) } } #[derive(Clone)] struct MockEvent { id: usize, users: HashMap, } impl MockEvent { fn new(id: usize, registrants: HashSet, participants: HashSet) -> Self { let users = registrants.into_iter() .map(|uid| (uid, participants.contains(&uid))) .collect(); Self { id, users } } } impl std::fmt::Display for MockEvent { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "MockEvent{}({:?})", self.id, self.users) } } impl Event for &MockEvent { fn registered(&self, uid: UserID) -> bool { self.users.get(&uid).is_some() } fn participated(&self, uid: UserID) -> bool { self.users.get(&uid).is_some_and(|participated|*participated) } } impl Participants { pub fn add(mut self, uid: UserID) -> Self { self.0.push((uid, 1)); self } pub fn select(mut self, history: H, rng: &mut impl Rng, count: usize) -> HashSet where H: Iterator, ::Item: Event, { for event in history { let mut modified = false; for item in self.0.iter_mut() { if event.registered(item.0) && !event.participated(item.0) { modified = true; item.1 += 1; } } if !modified { break; } } println!("{:?}", self.0); self.0.sample_weighted(rng, count, |item: &'_ (_, usize)| item.1 as f64) .unwrap() .map(|item| item.0) .collect() } } async fn connect<'a, I: spond::auth::Identifier + From<&'a str>>(id: &'a str) -> Result { let pw = std::env::var("SPOND_PASSWORD").expect("a password is required in SPOND_PASSWORD"); let id: I = id.into(); let auth = spond::auth::Login::new(id, pw); let client = spond::Api::new(auth).await?; Ok(client) } async fn main() -> anyhow::Result<()> { let filter = EnvFilter::try_from_default_env() .unwrap_or_else(|_| EnvFilter::new("info")); tracing_subscriber::registry() .with(fmt::layer().pretty()) .with(filter) .init(); error!("Error Message"); warn!("Warn Message"); info!("Info Message"); debug!("Debug Message"); trace!("Trace Message"); let client = if let Ok(email) = std::env::var("SPOND_EMAIL") { connect::(&email).await? } else if let Ok(phone) = std::env::var("SPOND_PHONE") { connect::(&phone).await? } else { panic!("no credentials provided"); }; let _ = client; let users = (0..25).map(UserID).collect::>(); let mut events = Vec::new(); for id in 0..5 { let mut rng = rand::rng(); let want = users.iter().filter(|_| (&mut rng).random_bool(0.75)).map(|id|id.clone()).collect::>(); let mut participants = Participants::default(); for uid in want.iter() { participants = participants.add(*uid); } let participants = participants.select(events.iter().rev(), &mut rng, 12); let event = MockEvent::new(id, want, participants); println!("{event}"); events.push(event); } for uid in users.into_iter() { let (registered, participated) = events.iter() .fold((0, 0), |(registered, participated), event| { let registered = registered + if event.registered(uid) { 1 } else { 0 }; let participated = participated + if event.participated(uid) { 1 } else { 0 }; (registered, participated) }); println!("{uid}: ({participated}/{registered}) {:.2}%", (participated as f64) / (registered as f64) * 100f64); } Ok(()) } } fn tracing_setup(filter: &str) { let filter = EnvFilter::try_from_default_env() .unwrap_or_else(|_| EnvFilter::new(filter)); tracing_subscriber::registry() .with(fmt::layer().pretty()) .with(filter) .init(); } async fn connect(authenticator: A, credentials: C) -> Result::Error, >::Error>> { let auth = spond::authentication::Login; authenticator.authenticate(&auth, &credentials).await } #[derive(serde::Deserialize)] struct Spond() #[derive(serde::Deserialize)] struct Sponds(Vec); impl spond::traits::endpoint::Private for Sponds { const METHOD: spond::Method = spond::Method::GET; type Schema = Self; fn path(&self, _: &SpodsW } #[derive(serde::Seralize)] struct SpondsQuery; #[tokio::main] async fn main() { tracing_setup("info"); #[cfg(feature="disabled")] disabled::main().await; error!("Error Message"); warn!("Warn Message"); info!("Info Message"); debug!("Debug Message"); trace!("Trace Message"); let pw = std::env::var("SPOND_PASSWORD").expect("a password is required in SPOND_PASSWORD"); let client = spond::reqwest::Public::new().expect("public client"); let client = if let Ok(email) = std::env::var("SPOND_EMAIL") { connect(client, spond::authentication::login::Email::new(&email, &pw)).await } else if let Ok(phone) = std::env::var("SPOND_PHONE") { connect(client, spond::authentication::login::Phone::new(&phone, &pw)).await } else { panic!("no credentials provided"); }; let _ = client.execute(; }