From a531a00fe55a19f06bc15bc9b99a78f8dcb253a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=A1?= =?UTF-8?q?=D0=B0=D1=84=D1=80=D0=BE=D0=BD=D0=BE=D0=B2?= Date: Sun, 25 May 2025 14:35:35 +0000 Subject: [PATCH] Update src/main.rs --- src/main.rs | 147 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 129 insertions(+), 18 deletions(-) diff --git a/src/main.rs b/src/main.rs index d20bedd..0cade06 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,22 +1,133 @@ -mod config; -mod commands; -mod server; -mod logging; +use std::io::{self, Write}; +use std::net::{TcpStream, ToSocketAddrs}; +use std::time::Duration; +use std::env; +use resp::{Value, Decoder}; +use colored::*; +use regex::Regex; -use std::sync::Arc; -use crate::config::ServerConfig; -use log::error; +mod resp; -#[tokio::main] -async fn main() -> anyhow::Result<()> { - let config = Arc::new(ServerConfig::load()?); - logging::setup_logging(&config.log_path)?; - server::print_startup_info(&config); - - if let Err(e) = server::start_server(config).await { - error!("Server error: {}", e); - return Err(e); +const DEFAULT_PORT: u16 = 9880; +const PROMPT_NAME: &str = "futriix"; +const CONNECTION_TIMEOUT: u64 = 5; // seconds + +fn main() { + // Parse command line arguments + let args: Vec = env::args().collect(); + let mut host = "127.0.0.1".to_string(); + let mut port = DEFAULT_PORT; + + if args.len() > 1 { + let re = Regex::new(r"^(?:([^:]+):)?([^:]+)(?::(\d+))?$").unwrap(); + if let Some(caps) = re.captures(&args[1]) { + if let Some(h) = caps.get(2) { + host = h.as_str().to_string(); + } + if let Some(p) = caps.get(3) { + port = p.as_str().parse().unwrap_or(DEFAULT_PORT); + } + } + } + + // Try to connect to server + let addr = format!("{}:{}", host, port); + let socket_addr = format!("{}:{}", host, port) + .to_socket_addrs() + .expect("Failed to parse address") + .next() + .expect("No address found"); + + let stream = match TcpStream::connect_timeout(&socket_addr, Duration::from_secs(CONNECTION_TIMEOUT)) { + Ok(s) => s, + Err(e) => { + eprintln!("Failed to connect to {}: {}", addr, e); + return; + } + }; + + println!("Connected to {}", addr); + + // Main REPL loop + let mut input = String::new(); + loop { + // Print prompt + print_prompt(&host, port); + + // Read input + input.clear(); + io::stdin().read_line(&mut input).expect("Failed to read input"); + let input = input.trim(); + + if input.is_empty() { + continue; + } + + // Handle special commands + if input.eq_ignore_ascii_case("quit") || input.eq_ignore_ascii_case("exit") { + break; + } + + // Send command to server + match send_command(&stream, input) { + Ok(response) => { + print_response(&response); + } + Err(e) => { + eprintln!("Error: {}", e); + } + } } - - Ok(()) } + +fn print_prompt(host: &str, port: u16) { + let prompt = format!("{}:{}:{}:~>", PROMPT_NAME, host, port); + print!("{} ", prompt.green()); + io::stdout().flush().unwrap(); +} + +fn send_command(stream: &TcpStream, command: &str) -> io::Result { + // Parse command into RESP format + let parts: Vec<&str> = command.split_whitespace().collect(); + let mut resp_command = String::new(); + + // RESP protocol: *\r\n$\r\n\r\n... + resp_command.push_str(&format!("*{}\r\n", parts.len())); + for part in parts { + resp_command.push_str(&format!("${}\r\n{}\r\n", part.len(), part)); + } + + // Send command + let mut stream = stream.try_clone()?; + stream.write_all(resp_command.as_bytes())?; + + // Read response + let mut decoder = Decoder::new(&stream); + decoder.decode() +} + +fn print_response(value: &Value) { + match value { + Value::SimpleString(s) | Value::BulkString(s) => println!("{}", s), + Value::Error(e) => println!("(error) {}", e), + Value::Integer(i) => println!("(integer) {}", i), + Value::Array(arr) => { + for (i, item) in arr.iter().enumerate() { + print!("{}) ", i + 1); + print_response(item); + } + } + Value::Null => println!("(nil)"), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_print_prompt() { + // This would need to be captured and checked in a real test + print_prompt("127.0.0.1", 9880); + } +} \ No newline at end of file