summaryrefslogtreecommitdiffstats
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/server/core.rs34
-rw-r--r--src/server/database.rs27
2 files changed, 61 insertions, 0 deletions
diff --git a/src/server/core.rs b/src/server/core.rs
index 4b68ccb..89264f3 100644
--- a/src/server/core.rs
+++ b/src/server/core.rs
@@ -172,6 +172,21 @@ impl ServerCore {
172 self.handle_auth(state, parts[1], parts[2]) 172 self.handle_auth(state, parts[1], parts[2])
173 } 173 }
174 } 174 }
175 "HISTORY" => {
176 if parts.len() > 2 {
177 "ERROR Invalid HISTORY format. Usage: HISTORY [count]".to_string()
178 } else {
179 match parts.get(1) {
180 Some(raw) => match raw.parse::<u32>() {
181 Ok(count) if count > 0 => {
182 self.handle_history(state, count.min(crate::history::MAX_HISTORY))
183 }
184 _ => "ERROR Invalid HISTORY count".to_string(),
185 },
186 None => self.handle_history(state, crate::history::DEFAULT_HISTORY),
187 }
188 }
189 }
175 "PING" => "PONG".to_string(), 190 "PING" => "PONG".to_string(),
176 "INFO" => self.handle_info(state), 191 "INFO" => self.handle_info(state),
177 _ => msg.to_string(), 192 _ => msg.to_string(),
@@ -234,6 +249,25 @@ impl ServerCore {
234 } 249 }
235 } 250 }
236 251
252 fn handle_history(&mut self, state: &ConnectionState, limit: u32) -> String {
253 let Some(user) = state.user.as_deref() else {
254 return "ERROR Not logged in".to_string();
255 };
256 match database::recent_plays(&self.conn, user, limit) {
257 Ok(records) => match serde_json::to_string(&records) {
258 Ok(json) => format!("HISTORY {json}"),
259 Err(error) => {
260 eprintln!("History serialization failed for {user}: {error}");
261 "ERROR Could not read history".to_string()
262 }
263 },
264 Err(error) => {
265 eprintln!("History query failed for {user}: {error}");
266 "ERROR Could not read history".to_string()
267 }
268 }
269 }
270
237 fn handle_info(&self, state: &ConnectionState) -> String { 271 fn handle_info(&self, state: &ConnectionState) -> String {
238 let Some(user) = state.user.as_deref() else { 272 let Some(user) = state.user.as_deref() else {
239 return "ERROR Not logged in".to_string(); 273 return "ERROR Not logged in".to_string();
diff --git a/src/server/database.rs b/src/server/database.rs
index 6dd71a3..cfc48c1 100644
--- a/src/server/database.rs
+++ b/src/server/database.rs
@@ -399,3 +399,30 @@ fn abandoned_details(raw: &str) -> String {
399 } 399 }
400 value.to_string() 400 value.to_string()
401} 401}
402
403/// Most recent settled plays for a user, newest first.
404pub fn recent_plays(
405 conn: &Connection,
406 username: &str,
407 limit: u32,
408) -> rusqlite::Result<Vec<crate::history::PlayRecord>> {
409 let mut statement = conn.prepare(
410 "SELECT game_type, bet_amount, winnings, balance_after, details, created_at
411 FROM plays
412 WHERE username = ?1
413 ORDER BY created_at DESC, rowid DESC
414 LIMIT ?2",
415 )?;
416 let rows = statement.query_map(params![username, limit], |row| {
417 let details: String = row.get(4)?;
418 Ok(crate::history::PlayRecord {
419 game: row.get(0)?,
420 bet: row.get(1)?,
421 winnings: row.get(2)?,
422 balance_after: row.get(3)?,
423 at: row.get(5)?,
424 details: serde_json::from_str(&details).unwrap_or(serde_json::Value::Null),
425 })
426 })?;
427 rows.collect()
428}