diff --git a/battlesnake/src/main.rs b/battlesnake/src/main.rs index 2c3289e..4636a65 100644 --- a/battlesnake/src/main.rs +++ b/battlesnake/src/main.rs @@ -34,7 +34,22 @@ static THREADS: AtomicUsize = AtomicUsize::new(1); async fn main() { env_logger::init(); - let (sender, mut receiver) = unbounded_channel(); + let record = env::var("RECORD") + .ok() + .and_then(|record| { + record + .parse() + .inspect_err(|err| error!("Unable to parse record options: {err}")) + .ok() + }) + .unwrap_or(false); + + let (sender, receiver) = if record { + let (sender, receiver) = unbounded_channel(); + (Some(sender), Some(receiver)) + } else { + (None, None) + }; debug!("Creating routes"); let app = Router::new() @@ -59,51 +74,53 @@ async fn main() { let port = env::var("PORT").unwrap_or_else(|_| "8000".into()); let listener = TcpListener::bind(format!("0.0.0.0:{port}")).await.unwrap(); - debug!("Starting observer"); - tokio::spawn(async move { - let mut games = HashMap::new(); - while let Some((request_type, request)) = receiver.recv().await { - match request_type { - RequestType::Start => { - let game_id = request.game.id.clone(); - info!("Got start request {game_id}"); - if let Some(old_requests) = games.insert(game_id, vec![request]) { - warn!("evicted duplicate game: {old_requests:?}"); - } - } - RequestType::GetMove => { - let game_id = request.game.id.clone(); - info!("Got move request {game_id}"); - games.entry(game_id).or_default().push(request); - } - RequestType::End => { - let game_id = request.game.id.clone(); - info!("Got end request {game_id}"); - if let Some(mut requests) = games.remove(&game_id) { - requests.push(request); - let json = match serde_json::to_vec_pretty(&requests) { - Ok(json) => json, - Err(e) => { - error!("Unable to serealize json: {e}"); - continue; - } - }; - match File::create_new(format!("games/{game_id}.json")).await { - Ok(mut file) => { - if let Err(e) = file.write_all(&json).await { - error!("Unable to write jsone: {e}"); - } - } - Err(e) => error!("Unable to open file: {e}"), + if let Some(mut receiver) = receiver { + debug!("Starting observer"); + tokio::spawn(async move { + let mut games = HashMap::new(); + while let Some((request_type, request)) = receiver.recv().await { + match request_type { + RequestType::Start => { + let game_id = request.game.id.clone(); + info!("Got start request {game_id}"); + if let Some(old_requests) = games.insert(game_id, vec![request]) { + warn!("evicted duplicate game: {old_requests:?}"); + } + } + RequestType::GetMove => { + let game_id = request.game.id.clone(); + info!("Got move request {game_id}"); + games.entry(game_id).or_default().push(request); + } + RequestType::End => { + let game_id = request.game.id.clone(); + info!("Got end request {game_id}"); + if let Some(mut requests) = games.remove(&game_id) { + requests.push(request); + let json = match serde_json::to_vec_pretty(&requests) { + Ok(json) => json, + Err(e) => { + error!("Unable to serealize json: {e}"); + continue; + } + }; + match File::create_new(format!("games/{game_id}.json")).await { + Ok(mut file) => { + if let Err(e) = file.write_all(&json).await { + error!("Unable to write jsone: {e}"); + } + } + Err(e) => error!("Unable to open file: {e}"), + } + } else { + warn!("end of game without game: {request:?}"); } - } else { - warn!("end of game without game: {request:?}"); } } } - } - warn!("Observer stopped"); - }); + warn!("Observer stopped"); + }); + } debug!("Starting server"); axum::serve(listener, app).await.unwrap(); @@ -139,10 +156,12 @@ enum RequestType { } async fn start( - State(sender): State>, + State(sender): State>>, Json(request): Json, ) { - if let Err(e) = sender.send((RequestType::Start, request.clone())) { + if let Some(sender) = sender + && let Err(e) = sender.send((RequestType::Start, request.clone())) + { warn!("Unable to observe request: {e}"); } let board = Board::from(&request); @@ -151,11 +170,13 @@ async fn start( #[allow(clippy::too_many_lines)] async fn get_move( - State(sender): State>, + State(sender): State>>, Json(request): Json, ) -> response::Json { let start = Instant::now(); - if let Err(e) = sender.send((RequestType::GetMove, request.clone())) { + if let Some(sender) = sender + && let Err(e) = sender.send((RequestType::GetMove, request.clone())) + { warn!("Unable to observe request: {e}"); } let board = Game::from(&request); @@ -285,10 +306,12 @@ fn score_standard(board: &Board, id: u8) -> u32 { } async fn end( - State(sender): State>, + State(sender): State>>, Json(request): Json, ) { - if let Err(e) = sender.send((RequestType::End, request.clone())) { + if let Some(sender) = sender + && let Err(e) = sender.send((RequestType::End, request.clone())) + { warn!("Unable to observe request: {e}"); } let board = Board::from(&request);