use anyhow::{Context, Result}; use axum::{response::Html, routing::get, Router}; use std::{ // collections::HashSet, fs, net::SocketAddr, sync::{Arc, Mutex}, }; use tokio::sync::broadcast; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; pub mod gamemaster; use crate::gamemaster::*; pub mod api; use crate::api::*; use crate::message_handler::*; /// Parse json for card data fn load_json(path: &str) -> Result> { let data: String = fs::read_to_string(path).with_context(|| format!("Invalid JSON path: \"{}\"", path))?; let jayson: Vec = serde_json::from_str(&data).with_context(|| format!("\"{path}\" is invalid json"))?; Ok(jayson) } // this is still around just for reference #[allow(dead_code)] fn test() -> Result<()> { // choose decks let cards_input_path: &str = "data/cah-cards-full.json"; // TODO: this should be a master card database and pointers // to the cards should be passed to the game instead of actual cards let chosen_packs: Vec = load_json(cards_input_path)?; println!("{}", &chosen_packs.len()); let test_player0 = CAHPlayer { name: "Adam".to_string(), role: PlayerRole::Host, white: vec![], black: vec![], }; let test_player1 = CAHPlayer { name: "Ferris".to_string(), role: PlayerRole::Player, white: vec![], black: vec![], }; // make some games // use hashmap? let mut games: Vec = vec![]; // create game with/for player 0 let test_game0 = NewGameRequest { name: "Test0".to_string(), host: test_player0, // packs: chosen_packs, packs: vec![0], }; games.push(CAHGame::new(test_game0)?); // a new game request struct but this player is a player games[0].create_player(test_player1)?; // start round games[0].game_start()?; println!("----------------------"); for card in &games[0].players[0].white { println!("{}", card.text); } Ok(()) } // Our shared state pub struct AppState { // We require unique usernames. This tracks which usernames have been taken. // user_set: Mutex>, // Channel used to send messages to all connected clients. tx: broadcast::Sender, // Master card decks all_cards: Mutex>, // Games list games: Mutex>, } // Include utf-8 files at **compile** time. async fn index() -> Html<&'static str> { Html(std::include_str!("../public/test_client.html")) } async fn spawnclients() -> Html<&'static str> { Html(std::include_str!("../public/spawnclients.html")) } #[tokio::main] async fn main() -> Result<()> { // stuff for logging tracing_subscriber::registry() .with( tracing_subscriber::EnvFilter::try_from_default_env() .unwrap_or_else(|_| "cards=trace".into()), ) .with(tracing_subscriber::fmt::layer()) .init(); // Set up application state for use with with_state(). // let user_set = Mutex::new(HashSet::new()); let (tx, _rx) = broadcast::channel(100); let cards_input_path: &str = "data/cah-cards-full.json"; let all_cards = Mutex::new(load_json(cards_input_path)?); let games = Mutex::new(vec![]); let app_state = Arc::new(AppState { // user_set, tx, all_cards, games, }); // set routes and apply state let app = Router::new() .route("/", get(index)) .route("/test", get(spawnclients)) .route("/websocket", get(websocket_handler)) .with_state(app_state); // send it let address = "0.0.0.0:3030"; let listener = tokio::net::TcpListener::bind(address) .await .with_context(|| format!("{} is not a valid bind address.", address))?; tracing::debug!("listening on {}", listener.local_addr()?); axum::serve( listener, app.into_make_service_with_connect_info::(), ) .await?; Ok(()) }