initial git dump

This commit is contained in:
Jonas Rabenstein 2026-02-16 02:51:10 +01:00
commit 781e25470b
47 changed files with 2361 additions and 0 deletions

231
turnerbund/:w Normal file
View file

@ -0,0 +1,231 @@
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(;
}