Skip to main content

go_fish_game_server/
lib.rs

1pub mod connection;
2pub mod lobby;
3
4use serde::Deserialize;
5use std::net::SocketAddr;
6use tokio::sync::mpsc;
7use tracing::info;
8
9pub use connection::{
10    ClientEvent, ClientHandle, ConnectionManager, DisconnectReason,
11    LobbyEvent, ManagerCommand, ServerMessage,
12};
13pub use lobby::{
14    ClientPhase, Lobby, LobbyCommand, LobbyManager, PlayerRecord,
15};
16
17#[derive(Debug, Deserialize)]
18pub struct SimpleBotConfig {
19    pub memory_limit: u8,
20    pub error_margin: f32,
21}
22
23#[derive(Debug, Deserialize)]
24pub struct BotConfig {
25    pub thinking_time_min_ms: u64,
26    pub thinking_time_max_ms: u64,
27    pub simple_bot: SimpleBotConfig,
28}
29
30#[derive(Debug, Deserialize)]
31pub struct Config {
32    pub address: SocketAddr,
33    pub lobby_max_players: usize,
34    pub max_client_connections: usize,
35    pub bots: Option<BotConfig>,
36}
37
38impl Default for Config {
39    fn default() -> Self {
40        Config {
41            address: "127.0.0.1:9001".parse().unwrap(),
42            lobby_max_players: 4,
43            max_client_connections: 10,
44            bots: None,
45        }
46    }
47}
48
49pub async fn run(config: Config) -> Result<(), anyhow::Error> {
50    let (lobby_event_tx, lobby_event_rx) = mpsc::channel::<LobbyEvent>(64);
51    let (lobby_cmd_tx, lobby_cmd_rx) = mpsc::channel::<LobbyCommand>(8);
52
53    let manager = ConnectionManager::new(lobby_event_tx.clone(), config.max_client_connections);
54    let event_tx = manager.event_tx();
55    let command_tx = manager.command_tx();
56
57    let bot_config = config.bots.unwrap_or(BotConfig {
58        thinking_time_min_ms: 2000,
59        thinking_time_max_ms: 4500,
60        simple_bot: SimpleBotConfig { memory_limit: 3, error_margin: 0.2 },
61    });
62
63    let lobby_manager = LobbyManager::new(
64        lobby_event_rx,
65        lobby_cmd_rx,
66        config.lobby_max_players,
67        lobby_event_tx.clone(),
68        bot_config,
69    );
70
71    let (listener_cmd_tx, listener_cmd_rx) = mpsc::channel::<ManagerCommand>(1);
72    tokio::spawn(connection::run_tcp_listener(config.address, event_tx, listener_cmd_rx));
73    tokio::spawn(lobby_manager.run());
74
75    let mut sigterm = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())?;
76
77    async fn shutdown(
78        listener_cmd_tx: mpsc::Sender<ManagerCommand>,
79        command_tx: mpsc::Sender<ManagerCommand>,
80        lobby_cmd_tx: mpsc::Sender<LobbyCommand>,
81    ) {
82        let _ = listener_cmd_tx.send(ManagerCommand::Shutdown).await;
83        let _ = command_tx.send(ManagerCommand::Shutdown).await;
84        let _ = lobby_cmd_tx.send(LobbyCommand::Shutdown).await;
85    }
86
87    tokio::select! {
88        _ = manager.run() => {}
89        _ = tokio::signal::ctrl_c() => {
90            info!(event = "shutdown", signal = "SIGINT");
91            shutdown(listener_cmd_tx, command_tx, lobby_cmd_tx).await;
92        }
93        _ = sigterm.recv() => {
94            info!(event = "shutdown", signal = "SIGTERM");
95            shutdown(listener_cmd_tx, command_tx, lobby_cmd_tx).await;
96        }
97    }
98
99    Ok(())
100}