summaryrefslogtreecommitdiffstats
path: root/src/bin/server
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/bin/server/database.rs44
-rw-r--r--src/bin/server/handler.rs35
2 files changed, 62 insertions, 17 deletions
diff --git a/src/bin/server/database.rs b/src/bin/server/database.rs
index 9c51997..0fac387 100644
--- a/src/bin/server/database.rs
+++ b/src/bin/server/database.rs
@@ -1,22 +1,34 @@
1use rusqlite::Connection; 1use rusqlite::Connection;
2 2
3pub fn init_db() -> Connection { 3pub fn init_db() -> Connection {
4 let conn = Connection::open("server.db").unwrap(); 4 let db_path = std::env::var("SERVER_DB").unwrap_or_else(|_| "server.db".to_string());
5 let conn = Connection::open(&db_path).unwrap();
5 conn.execute( 6 conn.execute(
6 "CREATE TABLE IF NOT EXISTS users ( 7 "CREATE TABLE IF NOT EXISTS users (
7 username TEXT PRIMARY KEY, 8 username TEXT PRIMARY KEY,
8 hashed_password TEXT NOT NULL 9 hashed_password TEXT NOT NULL,
10 account_id INTEGER UNIQUE,
11 balance INTEGER DEFAULT 1000
9 )", 12 )",
10 [], 13 [],
11 ).unwrap(); 14 ).unwrap();
15 // Add column if not exists (for migration)
16 let _ = conn.execute("ALTER TABLE users ADD COLUMN account_id INTEGER UNIQUE", []);
17 let _ = conn.execute("ALTER TABLE users ADD COLUMN balance INTEGER DEFAULT 1000", []);
12 conn 18 conn
13} 19}
14 20
15pub fn add_user(conn: &Connection, username: &str, hashed_password: &str) -> Result<(), Box<dyn std::error::Error>> { 21pub fn add_user(conn: &Connection, username: &str, hashed_password: &str) -> Result<(), Box<dyn std::error::Error>> {
16 conn.execute( 22 loop {
17 "INSERT INTO users (username, hashed_password) VALUES (?1, ?2)", 23 let account_id: u32 = rand::random::<u32>();
18 [username, hashed_password], 24 match conn.execute(
19 )?; 25 "INSERT INTO users (username, hashed_password, account_id, balance) VALUES (?1, ?2, ?3, ?4)",
26 [username, hashed_password, &account_id.to_string(), "1000"],
27 ) {
28 Ok(_) => break,
29 Err(_) => continue, // Retry if account_id conflict
30 }
31 }
20 Ok(()) 32 Ok(())
21} 33}
22 34
@@ -29,3 +41,23 @@ pub fn get_hashed_password(conn: &Connection, username: &str) -> Option<String>
29 None 41 None
30 } 42 }
31} 43}
44
45pub fn get_account_id(conn: &Connection, username: &str) -> Option<u32> {
46 let mut stmt = conn.prepare("SELECT account_id FROM users WHERE username = ?1").unwrap();
47 let mut rows = stmt.query([username]).unwrap();
48 if let Ok(Some(row)) = rows.next() {
49 Some(row.get::<_, u32>(0).ok()?)
50 } else {
51 None
52 }
53}
54
55pub fn get_balance(conn: &Connection, username: &str) -> Option<i64> {
56 let mut stmt = conn.prepare("SELECT balance FROM users WHERE username = ?1").unwrap();
57 let mut rows = stmt.query([username]).unwrap();
58 if let Ok(Some(row)) = rows.next() {
59 Some(row.get::<_, i64>(0).ok()?)
60 } else {
61 None
62 }
63}
diff --git a/src/bin/server/handler.rs b/src/bin/server/handler.rs
index 2132d09..01fd9c9 100644
--- a/src/bin/server/handler.rs
+++ b/src/bin/server/handler.rs
@@ -19,6 +19,7 @@ pub fn handle_client(stream: TcpStream) {
19 println!("[{} @ {}] Received: {}", user, client_addr, line); 19 println!("[{} @ {}] Received: {}", user, client_addr, line);
20 let response = process_message(&line, &mut user); 20 let response = process_message(&line, &mut user);
21 writeln!(writer, "{}", response).unwrap(); 21 writeln!(writer, "{}", response).unwrap();
22 println!("[{} @ {}] Sent: {}", user, client_addr, response);
22 } 23 }
23 println!("[{} @ {}] Client disconnected", user, client_addr); 24 println!("[{} @ {}] Client disconnected", user, client_addr);
24} 25}
@@ -28,37 +29,49 @@ fn process_message(msg: &str, user: &mut String) -> String {
28 match parts[0] { 29 match parts[0] {
29 "REGISTER" => { 30 "REGISTER" => {
30 if parts.len() != 3 { 31 if parts.len() != 3 {
31 "FAIL Invalid REGISTER format".to_string() 32 "ERROR Invalid REGISTER format".to_string()
32 } else { 33 } else {
33 let username = parts[1]; 34 let username = parts[1];
34 let hashed_pass = parts[2]; 35 let hashed_password = parts[2];
35 let db = DB_CONN.lock().unwrap(); 36 let db = DB_CONN.lock().unwrap();
36 match database::add_user(&db, username, hashed_pass) { 37 match database::add_user(&db, username, hashed_password) {
37 Ok(_) => format!("OK Registered {}", username), 38 Ok(_) => format!("REGISTERED {}", username),
38 Err(_) => "FAIL User already exists".to_string(), 39 Err(_) => "ERROR User already exists".to_string(),
39 } 40 }
40 } 41 }
41 } 42 }
42 "AUTH" => { 43 "AUTH" => {
43 if parts.len() != 3 { 44 if parts.len() != 3 {
44 "FAIL Invalid AUTH format".to_string() 45 "ERROR Invalid AUTH format".to_string()
45 } else { 46 } else {
46 let username = parts[1]; 47 let username = parts[1];
47 let provided_hash = parts[2]; 48 let sent_hash = parts[2];
48 let db = DB_CONN.lock().unwrap(); 49 let db = DB_CONN.lock().unwrap();
49 if let Some(stored_hash) = database::get_hashed_password(&db, username) { 50 if let Some(stored_hash) = database::get_hashed_password(&db, username) {
50 if provided_hash == stored_hash { 51 if sent_hash == stored_hash {
51 *user = username.to_string(); 52 *user = username.to_string();
52 format!("OK {}", username) 53 format!("OK {}", username)
53 } else { 54 } else {
54 "FAIL Invalid credentials".to_string() 55 "ERROR Invalid credentials".to_string()
55 } 56 }
56 } else { 57 } else {
57 "FAIL User not found".to_string() 58 "ERROR User not found".to_string()
59 }
60 }
61 }
62 "PING" => "PONG".to_string(),
63 "INFO" => {
64 if *user == "guest" {
65 "ERROR Not logged in".to_string()
66 } else {
67 let db = DB_CONN.lock().unwrap();
68 if let (Some(id), Some(balance)) = (database::get_account_id(&db, user), database::get_balance(&db, user)) {
69 format!("INFO {} {} {}", user, id, balance)
70 } else {
71 "ERROR Error retrieving user info".to_string()
58 } 72 }
59 } 73 }
60 } 74 }
61 "PING" => "PING".to_string(),
62 _ => msg.to_string(), // Echo back for compatibility 75 _ => msg.to_string(), // Echo back for compatibility
63 } 76 }
64} 77}