From 6e2787d792de64c003eff03b62a2df798ef851c0 Mon Sep 17 00:00:00 2001 From: salmonik Date: Thu, 29 Oct 2026 20:43:09 +0100 Subject: v2.3.0: add crash with local multiplier and pushed crash event --- src/bin/client/repl.rs | 123 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 100 insertions(+), 23 deletions(-) (limited to 'src/bin/client/repl.rs') diff --git a/src/bin/client/repl.rs b/src/bin/client/repl.rs index f85af47..7fa462a 100644 --- a/src/bin/client/repl.rs +++ b/src/bin/client/repl.rs @@ -102,29 +102,76 @@ impl ClientState { self.apply_prompt(); loop { - let event = read().unwrap(); - match event { - Event::Key(key) => { - if key.kind != KeyEventKind::Press { - continue; - } - let Some(key) = map_key(key) else { - continue; - }; - let effects = self.core.handle_key(key); - if self.apply_effects(effects) { - break; + let mut quit = false; + + if crossterm::event::poll(std::time::Duration::from_millis(25)).unwrap_or(false) { + match read().unwrap() { + Event::Key(key) => { + if key.kind == KeyEventKind::Press { + if let Some(key) = map_key(key) { + let effects = self.core.handle_key(key); + quit = self.apply_effects(effects); + self.apply_prompt(); + } + } } - self.apply_prompt(); + Event::Resize(_, _) => self.apply_prompt(), + _ => {} + } + } + + if !quit && self.core.expects_push() { + quit = self.pump_async(); + } + + if !quit { + let effects = self.core.tick(); + if !effects.is_empty() { + quit = self.apply_effects(effects); } - Event::Resize(_, _) => self.apply_prompt(), - _ => {} + } + + if quit { + break; } } restore_terminal(&self.cleanup_done); } + /// Read any server-initiated lines that are already waiting and apply them. + /// Returns true when an effect asked the program to quit. + fn pump_async(&mut self) -> bool { + loop { + let Some(mut stream) = self.stream.take() else { + return false; + }; + let line = match stream.read_available_line() { + Ok(line) => { + self.stream = Some(stream); + line + } + Err(_) => { + self.core.set_connected(false); + self.stream = None; + return false; + } + }; + + let Some(line) = line else { + return false; + }; + + let effects = match self.core.handle_async_line(&line) { + Some(effects) => effects, + None => self.core.handle_reply(&line), + }; + if self.apply_effects(effects) { + return true; + } + } + } + fn apply_effects(&mut self, effects: Vec) -> bool { for effect in effects { match effect { @@ -250,6 +297,9 @@ impl ClientState { let roulette = lines .first() .is_some_and(|first| first.contains("ROULETTE")); + let crash = lines + .first() + .is_some_and(|first| first.contains("CRASH")); let rendered: Vec = lines .iter() .map(|line| { @@ -263,6 +313,18 @@ impl ClientState { } else { style_roulette_numbers(line) } + } else if crash { + if line.contains("CRASHED") { + line.as_str().bold().red().to_string() + } else if line.starts_with("Cashed out") { + line.as_str().bold().green().to_string() + } else if line.starts_with("Multiplier:") { + line.as_str().yellow().to_string() + } else if line.starts_with("ERROR:") { + line.as_str().red().to_string() + } else { + line.clone() + } } else if line.contains('{') { style_winning_cells(line) } else if line.contains("WIN!") || line.starts_with("Won ") { @@ -361,22 +423,37 @@ impl ClientState { return "ERROR Not connected".to_string(); }; + // A crash event can be pushed while a request is in flight. Route those + // lines as they arrive and keep waiting for the actual reply. + let mut pushed: Vec = Vec::new(); let result = (|| -> std::io::Result { stream.write_line(line)?; - let mut response = String::new(); - let read = stream.read_line(&mut response)?; - if read == 0 { - return Err(std::io::Error::new( - std::io::ErrorKind::UnexpectedEof, - "connection closed", - )); + loop { + let mut response = String::new(); + let read = stream.read_line(&mut response)?; + if read == 0 { + return Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "connection closed", + )); + } + let response = response.trim_end().to_string(); + if self.core.is_async(&response) { + pushed.push(response); + continue; + } + return Ok(response); } - Ok(response) })(); match result { Ok(response) => { self.stream = Some(stream); + for line in pushed { + if let Some(effects) = self.core.handle_async_line(&line) { + self.apply_effects(effects); + } + } response } Err(error) => { -- cgit v1.2.3