Files
secret-santa/src/main.rs
2024-11-23 16:22:28 +01:00

107 lines
3.0 KiB
Rust

use axum::{
response::Html,
routing::{get, post},
Json, Router,
};
use once_cell::sync::Lazy;
use rand::{thread_rng, Rng};
use rand::seq::SliceRandom;
use serde::Deserialize;
use std::net::SocketAddr;
use tokio::sync::Mutex;
use log::debug;
use log::error;
use log::info;
use log::warn;
#[macro_use]
extern crate log;
#[tokio::main]
async fn main() {
env_logger::init();
// tracing_subscriber::fmt::init();
// build our application with some routes
let app = Router::new()
.route("/", get(|| async { Html(INDEX_HTML.as_str()) }))
.route("/api", post(input));
// run it with hyper
let addr = SocketAddr::from(([127, 0, 0, 1], 3067));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
static INDEX_HTML: Lazy<String> = Lazy::new(|| {
let content = include_str!("index.html");
let options: String = everyone()
.into_iter()
.map(|person| format!(r#"<option value="{person}">{person}</option>"#))
.collect();
content.replace("__OPTIONS__", &options)
});
static STATE: Lazy<Mutex<State>> = Lazy::new(Mutex::default);
struct State {
participants: Vec<String>,
remaining: Vec<String>,
}
fn everyone() -> Vec<String> {
vec!["Alice".into(), "Bob".into(), "Carol".into(), "Dave".into()]
}
impl Default for State {
fn default() -> Self {
let mut p = everyone();
p.shuffle(&mut thread_rng());
info!("distribution : {:?}", p.join(" => "));
return Self {
participants: p,
remaining: everyone()
}
}
}
#[derive(Deserialize, Debug)]
struct Input {
person: String,
}
async fn input(Json(input): Json<Input>) -> String {
let mut state = STATE.lock().await;
if state.remaining.is_empty() {
return "ERROR (everybody drew already)".into();
}
info!("joueurs qui restent : {:?}", state.remaining.join(","));
match state.remaining.iter().position(|p| input.person == *p).map(|e| state.remaining.remove(e)) {
Some(rem) => {
match state.participants.iter().position(|p| input.person == *p) {
Some(pos) => {
info!("joueur qui pioche : {:?}", state.participants[pos]);
return match state.participants.iter().nth(pos+1) {
Some(x) => {
info!("joueur qui suit : {:?}", x);
return x.to_string();
}
None => return match state.participants.first() {
Some(x) => {
info!("joueur qui suit : {:?}", x);
return x.to_string();
}
None => "ERROR".to_string()
}
}
}
None => "ERROR".to_string()
}
}
None => "Vous avez déja pioché !".to_string()
}
}