From 5d6b5049c2a34a3f8abe725d4a871ba84a0dd714 Mon Sep 17 00:00:00 2001 From: salmonik Date: Mon, 24 Aug 2026 14:48:12 +0200 Subject: TLS transport and games framework on client and server --- src/bin/server/handler.rs | 177 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 171 insertions(+), 6 deletions(-) (limited to 'src/bin/server/handler.rs') diff --git a/src/bin/server/handler.rs b/src/bin/server/handler.rs index 01fd9c9..867910e 100644 --- a/src/bin/server/handler.rs +++ b/src/bin/server/handler.rs @@ -1,12 +1,16 @@ +use crate::database; +use crate::games::registry::get_game_registry; +use crate::games::traits::GameError; +use crate::tls::TlsStream; +use once_cell::sync::Lazy; +use rusqlite::Connection; use std::io::{BufRead, BufReader, Write}; use std::net::TcpStream; use std::sync::Mutex; -use once_cell::sync::Lazy; -use rusqlite::Connection; -use crate::database; static DB_CONN: Lazy> = Lazy::new(|| Mutex::new(database::init_db())); +#[allow(dead_code)] pub fn handle_client(stream: TcpStream) { let client_addr = stream.peer_addr().unwrap().to_string(); let mut user = "guest".to_string(); @@ -25,8 +29,49 @@ pub fn handle_client(stream: TcpStream) { } fn process_message(msg: &str, user: &mut String) -> String { - let parts: Vec<&str> = msg.splitn(3, ' ').collect(); + let parts: Vec<&str> = msg.splitn(5, ' ').collect(); match parts[0] { + "GAME_LIST" => { + let registry = get_game_registry(); + let games: Vec = registry.list_games(); + if games.is_empty() { + "ERROR No games available".to_string() + } else { + let game_info: Vec = games + .iter() + .filter_map(|gt| { + registry + .get_game(gt) + .map(|g| format!("{}:{}", gt, g.get_name())) + }) + .collect(); + format!("GAME_LIST {}", game_info.join(",")) + } + } + "GAME_INFO" => { + if parts.len() != 2 { + "ERROR Invalid GAME_INFO format. Usage: GAME_INFO ".to_string() + } else { + let registry = get_game_registry(); + match registry.get_game(parts[1]) { + Some(game) => format!( + "GAME_INFO {} {} {}", + parts[1], + game.get_name(), + game.get_description() + ), + None => format!("ERROR Unknown game type: {}", parts[1]), + } + } + } + "PLAY_START" => { + if parts.len() != 3 { + "ERROR Invalid PLAY_START format. Usage: PLAY_START " + .to_string() + } else { + handle_play_start(user, parts[1], parts[2]) + } + } "REGISTER" => { if parts.len() != 3 { "ERROR Invalid REGISTER format".to_string() @@ -65,13 +110,133 @@ fn process_message(msg: &str, user: &mut String) -> String { "ERROR Not logged in".to_string() } else { let db = DB_CONN.lock().unwrap(); - if let (Some(id), Some(balance)) = (database::get_account_id(&db, user), database::get_balance(&db, user)) { + if let (Some(id), Some(balance)) = ( + database::get_account_id(&db, user), + database::get_balance(&db, user), + ) { format!("INFO {} {} {}", user, id, balance) } else { "ERROR Error retrieving user info".to_string() } } } - _ => msg.to_string(), // Echo back for compatibility + _ => msg.to_string(), + } +} + +fn handle_play_start(user: &str, game_type: &str, bet_amount_str: &str) -> String { + if user == "guest" { + return "ERROR Not logged in".to_string(); + } + + let bet_amount: u64 = match bet_amount_str.parse() { + Ok(amount) => amount, + Err(_) => return "ERROR Invalid bet amount".to_string(), + }; + + let db = DB_CONN.lock().unwrap(); + let current_balance = match database::get_balance(&db, user) { + Some(balance) => balance as u64, + None => return "ERROR Could not retrieve balance".to_string(), + }; + + let registry = get_game_registry(); + let game = match registry.get_game(game_type) { + Some(game) => game, + None => return format!("ERROR Unknown game type: {}", game_type), + }; + + if let Err(e) = game.validate_bet(bet_amount, current_balance) { + return match e { + GameError::InsufficientBalance => "ERROR Insufficient balance".to_string(), + GameError::InvalidBet => "ERROR Invalid bet amount".to_string(), + _ => "ERROR Bet validation failed".to_string(), + }; + } + + let game_state = game.prepare_state(user, bet_amount); + + drop(db); + let db = DB_CONN.lock().unwrap(); + if let Err(_) = db.execute( + "UPDATE users SET balance = balance - ?1 WHERE username = ?2", + (bet_amount as i64, user), + ) { + return "ERROR Failed to deduct bet".to_string(); + } + + let new_state = match game.process_action(&game_state, "spin", &[]) { + Ok(state) => state, + Err(e) => { + let _ = db.execute( + "UPDATE users SET balance = balance + ?1 WHERE username = ?2", + (bet_amount as i64, user), + ); + return format!("ERROR Failed to spin: {:?}", e); + } + }; + + let result = match game.calculate_result(&new_state) { + Ok(result) => result, + Err(e) => { + let _ = db.execute( + "UPDATE users SET balance = balance + ?1 WHERE username = ?2", + (bet_amount as i64, user), + ); + return format!("ERROR Failed to calculate result: {:?}", e); + } + }; + + let total_return = result.bet_amount + result.winnings; + if let Err(_) = db.execute( + "UPDATE users SET balance = balance + ?1 WHERE username = ?2", + (total_return as i64, user), + ) { + return "ERROR Failed to update balance".to_string(); + } + + let new_balance = match database::get_balance(&db, user) { + Some(balance) => balance, + None => return "ERROR Could not retrieve new balance".to_string(), + }; + + let reels = new_state.data.get("reels").cloned().unwrap_or_default(); + let win_type = new_state.data.get("win_type").cloned().unwrap_or_default(); + + format!( + "GAME_RESULT {} {} {} {} {} {}", + result.session_id, result.winnings, result.bet_amount, new_balance, reels, win_type + ) +} + +pub fn handle_client_tls(mut stream: TlsStream) { + let client_addr = stream.peer_addr().unwrap().to_string(); + let mut user = "guest".to_string(); + println!("[{} @ {}] TLS Client connected", user, client_addr); + + loop { + let mut line = String::new(); + match stream.read_line(&mut line) { + Ok(0) => break, + Ok(_) => {} + Err(e) => { + eprintln!("Read error: {}", e); + break; + } + } + + let line = line.trim(); + if line.is_empty() { + continue; + } + + println!("[{} @ {}] Received: {}", user, client_addr, line); + let response = process_message(line, &mut user); + if let Err(e) = stream.write_line(&response) { + eprintln!("Write error: {}", e); + break; + } + println!("[{} @ {}] Sent: {}", user, client_addr, response); } + println!("[{} @ {}] TLS Client disconnected", user, client_addr); } -- cgit v1.2.3