use serde::{Deserialize}; use serde_json::Value; use rocket::{Route, State}; use rocket::response::NamedFile; use rocket_contrib::templates::Template; use rocket_contrib::json::Json; use async_std::prelude::*; use async_std::fs; use async_std::io::ReadExt; use crate::util::*; use std::path::Path; #[get("/", rank = 6)] async fn files(file: PathBuf) -> Option { NamedFile::open(Path::new("static/").join(file)).ok() } #[get("/")] async fn index() -> Template { // let context = context(); let context = Context::new("Home"); // context.insert("name".to_string(), "Arthur".to_string()); Template::render("index", &context) } #[derive(Deserialize, Debug)] struct MapReq { pub name: String, pub map: crate::planetwars::Map, } use std::path::PathBuf; #[post("/maps", data="")] async fn map_post(map_req: Json) -> Result { let MapReq { name, map } = map_req.into_inner(); let path: PathBuf = PathBuf::from(format!("maps/{}.json", name)); if path.exists() { return Err("File already exists!".into()); } let mut file = fs::File::create(path).await.map_err(|_| "IO error".to_string())?; file.write_all(&serde_json::to_vec_pretty(&map).unwrap()).await.map_err(|_| "IO error".to_string())?; Ok("ok".into()) } #[get("/lobby")] async fn lobby_get(gm: State<'_, game::Manager>, state: State<'_, Games>) -> Result { let maps = get_maps().await?; let games = get_states(&state.get_games(), &gm).await?; let context = Context::new_with("Lobby", Lobby { games, maps }); Ok(Template::render("lobby", &context)) } #[get("/mapbuilder")] async fn builder_get() -> Result { let context = Context::new("Map Builder"); Ok(Template::render("mapbuilder", &context)) } #[get("/debug")] async fn debug_get() -> Result { let context = Context::new("Debug Station"); Ok(Template::render("debug", &context)) } #[get("/visualizer")] async fn visualizer_get() -> Template { let game_options = get_games().await; let context = Context::new_with("Visualizer", json!({"games": game_options, "colours": COLOURS})); Template::render("visualizer", &context) } #[get("/maps/")] async fn map_get(file: String) -> Result { let mut content = String::new(); let mut file = fs::File::open(Path::new("maps/").join(file)).await.map_err(|_| "IO ERROR".to_string())?; file.read_to_string(&mut content).await.map_err(|_| "IO ERROR".to_string())?; Ok(Template::render("map_partial", &serde_json::from_str::(&content).unwrap())) } #[get("/partial/state")] async fn state_get(gm: State<'_, game::Manager>, state: State<'_, Games>) -> Result { let games = get_states(&state.get_games(), &gm).await?; let context = Context::new_with("Lobby", Lobby { games, maps: Vec::new() }); Ok(Template::render("state_partial", &context)) } #[derive(Deserialize, Debug)] struct GameReq { nop: u64, max_turns: u64, map: String, name: String, } #[derive(Serialize)] struct GameRes { players: Vec, state: Value, } use mozaic::util::request::Connect; #[post("/lobby", data="")] async fn game_post(game_req: Json, tp: State<'_, ThreadPool>, gm: State<'_, game::Manager>, state: State<'_, Games>) -> Result, String> { let game = build_builder(tp.clone(), game_req.nop, game_req.max_turns, &game_req.map, &game_req.name); let game_id = gm.start_game(game).await.unwrap(); state.add_game(game_req.name.clone(), game_id); match gm.get_state(game_id).await { Some(Ok((state, conns))) => { let players: Vec = conns.iter().map(|conn| match conn { Connect::Waiting(_, key) => *key, _ => 0, }).collect(); Ok(Json(GameRes { players, state })) }, Some(Err(v)) => { Err(serde_json::to_string(&v).unwrap()) }, None => { Err(String::from("Fuck the world")) } } } pub fn fuel(routes: &mut Vec) { routes.extend(routes![files, index, map_post, map_get, lobby_get, builder_get, visualizer_get, game_post, state_get, debug_get]); } use crate::planetwars; use mozaic::modules::types::*; use mozaic::modules::{game, StepLock}; use futures::executor::ThreadPool; use rand::prelude::*; fn generate_string_id() -> String { rand::thread_rng() .sample_iter(&rand::distributions::Alphanumeric) .take(15) .collect::() + ".json" } fn build_builder( pool: ThreadPool, number_of_clients: u64, max_turns: u64, map: &str, name: &str, ) -> game::Builder { let config = planetwars::Config { map_file: map.to_string(), max_turns: max_turns, }; let game = planetwars::PlanetWarsGame::new(config.create_game(number_of_clients as usize), &generate_string_id(), name, map); let players: Vec = (0..number_of_clients).collect(); game::Builder::new(players.clone(), game).with_step_lock( StepLock::new(players.clone(), pool.clone()) .with_timeout(std::time::Duration::from_secs(1)), ) }