go_fish_game_server/
lib.rs1pub 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}