231 lines
6.6 KiB
Text
231 lines
6.6 KiB
Text
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<UserID, bool>,
|
|
}
|
|
|
|
impl MockEvent {
|
|
fn new(id: usize, registrants: HashSet<UserID>, participants: HashSet<UserID>) -> 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<H>(mut self, history: H, rng: &mut impl Rng, count: usize)
|
|
-> HashSet<UserID>
|
|
where
|
|
H: Iterator,
|
|
<H as 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<spond::Api, spond::error::Api> {
|
|
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::<spond::auth::Email>(&email).await?
|
|
} else if let Ok(phone) = std::env::var("SPOND_PHONE") {
|
|
connect::<spond::auth::Phone>(&phone).await?
|
|
} else {
|
|
panic!("no credentials provided");
|
|
};
|
|
|
|
let _ = client;
|
|
|
|
|
|
let users = (0..25).map(UserID).collect::<Vec<UserID>>();
|
|
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::<HashSet<UserID>>();
|
|
|
|
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<A: spond::traits::client::Authenticator + Sync, C: spond::traits::authentication::login::Credentials + Sync>(authenticator: A, credentials: C) -> Result<A::Private, spond::error::api::Public<<A as spond::traits::client::Public>::Error, <spond::authentication::Tokens as spond::traits::Schema<C>>::Error>> {
|
|
let auth = spond::authentication::Login;
|
|
|
|
authenticator.authenticate(&auth, &credentials).await
|
|
}
|
|
|
|
#[derive(serde::Deserialize)]
|
|
struct Spond()
|
|
|
|
#[derive(serde::Deserialize)]
|
|
struct Sponds(Vec<Spond>);
|
|
|
|
impl spond::traits::endpoint::Private<SpondsQuery> 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(;
|
|
}
|