cards/server/src/main.rs
2024-08-02 01:20:54 -04:00

109 lines
3.2 KiB
Rust

#![feature(if_let_guard)]
use anyhow::{Context, Result};
use axum::{routing::get, Router};
use lib::models::*;
use std::{
collections::HashMap,
fs::{read_to_string, File},
io::{BufRead, BufReader},
net::SocketAddr,
sync::{Arc, Mutex},
};
use tokio::sync::broadcast;
use tower_http::services::ServeDir;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
pub mod api;
use crate::api::*;
/// Parse json for card data
fn load_cards_from_json(path: &str) -> Result<Vec<CardSet>> {
let data: String =
read_to_string(path).with_context(|| format!("Invalid JSON path: \"{}\"", path))?;
let jayson: Vec<CardSet> =
serde_json::from_str(&data).with_context(|| format!("\"{path}\" is invalid json"))?;
Ok(jayson)
}
/// Parse name list
fn load_names(path: &str) -> Result<Vec<String>> {
let f = File::open(path).with_context(|| format!("Invalid names path: \"{}\"", path))?;
let f = BufReader::new(f);
let mut buf = vec![];
for line in f.lines() {
buf.push(line?)
}
Ok(buf)
}
// Our shared state
pub struct AppState {
// We require unique usernames. This tracks which usernames have been taken.
online_users: Mutex<HashMap<SocketAddr, Arc<Mutex<User>>>>,
offline_users: Mutex<HashMap<String, Arc<Mutex<User>>>>,
// Channel used to send messages to all connected clients.
tx: broadcast::Sender<String>,
// Master card decks
all_cards: Vec<CardSet>,
// Games list
games: Mutex<Vec<Game>>,
// chatrooms: Mutex<HashMap<String, ChatRoom<'user>>>,
first_names: Vec<String>,
last_names: Vec<String>,
}
#[tokio::main]
async fn main() -> Result<()> {
// stuff for logging
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "server=trace,tower_http=trace,lib=trace".into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
// Set up application state for use with with_state().
// Main Broadcast Channel
let (tx, _rx) = broadcast::channel(100);
let online_users = Mutex::new(HashMap::<SocketAddr, Arc<Mutex<User>>>::new());
let offline_users = Mutex::new(HashMap::<String, Arc<Mutex<User>>>::new());
let all_cards = load_cards_from_json("data/cah-cards-full.json")?;
let games = Mutex::new(vec![]);
let first_names = load_names("data/first.txt")?;
let last_names = load_names("data/last.txt")?;
let app_state = Arc::new(AppState {
online_users,
offline_users,
tx,
all_cards,
games,
first_names,
last_names,
});
// set routes and apply state
let app = Router::new()
.route("/websocket", get(websocket_connection_handler))
.nest_service("/", ServeDir::new("dist"))
.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::<SocketAddr>(),
)
.await?;
Ok(())
}