use dnd_dice_roller::{dice::Dice, error::DiceError}; use maj::{ gemini::Builder, route, seg, server::{Error, Handler as MajHandler, Request}, split, Response, }; use percent_encoding::percent_decode_str; use std::str::FromStr; mod tarot; pub struct Handler { pub hostname: String, pub files: maj::server::files::Handler, pub cgi: maj::server::cgi::Handler, } async fn dice(req: Request) -> Result { fn dice_roll>(roll: T) -> Result { let mut dice = Dice::from_str(&roll.into())?; if dice.number_of_dice_to_roll > 100 { dice.number_of_dice_to_roll = 100; } if dice.sides > 100 { dice.sides = 100 } if dice.sides == 0 { dice.sides = 6; } let res = dice.roll_dice(); let reply = format!( "{}{} = {}\n", res.dice_results, match dice.modifier { Some(amt) => format!(" + {}", amt), None => "".into(), }, res.final_result[0] ); Ok(reply) } match req.url.query() { None => Ok(Response::input( "What do you want to roll? [n]dn[+n] [adv|dadv]", )), Some(q) => Ok({ let dice = percent_decode_str(q).decode_utf8()?; let b = Builder::new() .heading(1, "Dice Results") .text("") .text(format!("You rolled {} and you got:", dice)) .text("") .preformatted(format!("{}", dice_roll(dice)?)) .text("") .link("/dice", Some("Do another roll".to_string())); Response::render(b.build()) }), } } #[async_trait::async_trait] impl MajHandler for Handler { async fn handle(&self, req: Request) -> Result { if req.url.has_host() && req.url.host_str().unwrap().to_string() != self.hostname { return Ok(Response::no_proxy()); } if req.url.path() == "" { return Ok(Response::perm_redirect(format!( "gemini://{}/", self.hostname ))); } route!(req.url.path(), { (/"dice") => dice(req).await; (/"tools"/"character_gen") => tarot::character().await; (/"cgi-bin"[/rest..]) => self.cgi.handle(req).await; }); self.files.handle(req).await } }