team04_server/server/
mod.rs1pub mod connection;
4pub mod state;
5
6pub use connection::Connection;
7
8use std::{collections::BTreeMap, sync::Arc, time::Duration};
9
10use state::ServerState;
11
12#[cfg(test)]
13use crate::mock::TcpListener;
14#[cfg(not(test))]
15use tokio::net::TcpListener;
16
17use crate::{config::ConfigSet, log};
18
19pub async fn run(
20 listener: TcpListener,
21 addr_str: &str,
22 configs: BTreeMap<u64, ConfigSet>,
23) -> tokio::io::Result<()> {
24 log::info!("running websocket server on address {addr_str}"; &log::pfx());
25
26 let server_state = ServerState::new(configs);
27
28 let _cleanup_job = {
29 let server_state = Arc::clone(&server_state);
30 tokio::task::spawn(async move {
31 loop {
32 tokio::time::sleep(Duration::from_secs(5 * 60)).await;
33 let mut server_state = server_state.lock().await;
34 server_state.cleanup().await;
35 }
36 })
37 };
38
39 loop {
41 let (con, _) = listener.accept().await?;
42 let server_state = Arc::clone(&server_state);
43 let (abort_tx, abort_rx) = tokio::sync::oneshot::channel();
44 let conn_task = tokio::task::spawn(async move {
45 let mut in_lobby = None;
46 match connection::handle(con, &server_state, &mut in_lobby, abort_rx.await.unwrap())
47 .await
48 {
49 Ok(()) => (),
50 Err(e) => {
51 let mut pfx = log::pfx();
52 if let Some((lobby, _, player_id)) = &in_lobby {
53 pfx.lobby(lobby.id());
54 if let Some(player) = player_id {
55 pfx.player(*player);
56 }
57 }
58 log::info!("closing websocket connection, reason: {e:?}"; &pfx);
59 }
60 }
61 if let Some((lobby, name, player_id)) = in_lobby {
62 lobby.lock().await.client_leave(&name, player_id).await;
63 }
64 });
65 abort_tx.send(conn_task.abort_handle()).unwrap();
66 }
67}