diff --git a/futriix-cli/src/main.rs b/futriix-cli/src/main.rs index 804517e..e53fce1 100644 --- a/futriix-cli/src/main.rs +++ b/futriix-cli/src/main.rs @@ -1,33 +1,43 @@ -use serde::{Deserialize, Serialize}; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use std::error::Error; -use tokio::net::TcpStream; use colored::Colorize; -use rustyline::{Editor, error::ReadlineError}; +use rustyline::Editor; +use rustyline::error::ReadlineError; +use serde::{Deserialize, Serialize}; +use serde_json; +use std::error::Error; use std::fs; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::net::TcpStream; use toml::Value; -#[derive(Debug, Serialize, Deserialize)] -enum Command { - Insert { key: String, value: serde_json::Value }, - Get { key: String }, - Update { key: String, value: serde_json::Value }, - Delete { key: String }, - BeginTransaction, - CommitTransaction, - RollbackTransaction, - CreateIndex { field: String }, - DropIndex { field: String }, +mod server { + use serde::{Deserialize, Serialize}; + use serde_json; + + #[derive(Debug, Serialize, Deserialize)] + pub enum Command { + Insert { key: String, value: serde_json::Value }, + Get { key: String }, + Update { key: String, value: serde_json::Value }, + Delete { key: String }, + BeginTransaction, + CommitTransaction, + RollbackTransaction, + CreateIndex { field: String }, + DropIndex { field: String }, + SysExec { script_name: String }, + } + + #[derive(Debug, Serialize, Deserialize)] + pub enum Response { + Success(Option), + Error(String), + } } -#[derive(Debug, Serialize, Deserialize)] -enum Response { - Success(Option), - Error(String), -} +use server::{Command, Response}; -async fn send_command(cmd: Command) -> Result> { - let config_content = fs::read_to_string("../futriix.config.toml")?; +async fn send_command(cmd: Command) -> Result> { + let config_content = fs::read_to_string("futriix.config.toml")?; let config: Value = toml::from_str(&config_content)?; let ip = config["client"]["ip"].as_str().unwrap_or("127.0.0.1"); @@ -58,8 +68,9 @@ async fn main() -> Result<(), Box> { println!("Type 'help' for available commands"); let mut rl = Editor::<()>::new()?; - if rl.load_history("futriix-cli-history.txt").is_err() { + if rl.load_history("futriix-history.txt").is_err() { println!("No previous history."); + println!(); } loop { @@ -73,7 +84,7 @@ async fn main() -> Result<(), Box> { } let parts: Vec<&str> = line.split_whitespace().collect(); - match parts[0] { + match parts[0].to_lowercase().as_str() { "insert" | "i" => { if parts.len() < 3 { println!("{}", "Usage: insert ".red()); @@ -94,13 +105,20 @@ async fn main() -> Result<(), Box> { } }, "get" | "g" => { - if parts.len() != 2 { + if parts.len() < 2 { println!("{}", "Usage: get ".red()); continue; } - match send_command(Command::Get { key: parts[1].to_string() }).await { - Ok(Response::Success(Some(value))) => println!("{}", serde_json::to_string_pretty(&value)?), - Ok(Response::Success(None)) => println!("{}", "Error: Key not found".bold().red()), + let key = parts[1].to_string(); + match send_command(Command::Get { key }).await { + Ok(Response::Success(Some(value))) => { + println!("{}", serde_json::to_string_pretty(&value)?); + println!(); + }, + Ok(Response::Success(None)) => { + println!("{}", "Key found but no value returned".yellow()); + println!(); + }, Ok(Response::Error(e)) => println!("{}", e.bold().red()), Err(e) => println!("{}: {}", "Connection error".red(), e), } @@ -114,7 +132,10 @@ async fn main() -> Result<(), Box> { let value_str = parts[2..].join(" "); match serde_json::from_str(&value_str) { Ok(value) => match send_command(Command::Update { key, value }).await { - Ok(Response::Success(_)) => println!("{}", "Update successful".bright_green()), + Ok(Response::Success(_)) => { + println!("{}", "Update successful".bright_green()); + println!(); + }, Ok(Response::Error(e)) => println!("{}", e.bold().red()), Err(e) => println!("{}: {}", "Connection error".red(), e), }, @@ -122,68 +143,117 @@ async fn main() -> Result<(), Box> { } }, "delete" | "d" => { - if parts.len() != 2 { + if parts.len() < 2 { println!("{}", "Usage: delete ".red()); continue; } - match send_command(Command::Delete { key: parts[1].to_string() }).await { - Ok(Response::Success(_)) => println!("{}", "Delete successful".bright_green()), + let key = parts[1].to_string(); + match send_command(Command::Delete { key }).await { + Ok(Response::Success(_)) => { + println!("{}", "Delete successful".bright_green()); + println!(); + }, Ok(Response::Error(e)) => println!("{}", e.bold().red()), Err(e) => println!("{}: {}", "Connection error".red(), e), } }, - "begin" => match send_command(Command::BeginTransaction).await { - Ok(Response::Success(_)) => println!("{}", "Transaction started".bright_green()), - Ok(Response::Error(e)) => println!("{}", e.bold().red()), - Err(e) => println!("{}: {}", "Connection error".red(), e), + "begin" | "transaction" | "tx" => { + match send_command(Command::BeginTransaction).await { + Ok(Response::Success(_)) => { + println!("{}", "Transaction started".bright_green()); + println!(); + }, + Ok(Response::Error(e)) => println!("{}", e.bold().red()), + Err(e) => println!("{}: {}", "Connection error".red(), e), + } }, - "commit" => match send_command(Command::CommitTransaction).await { - Ok(Response::Success(_)) => println!("{}", "Transaction committed".bright_green()), - Ok(Response::Error(e)) => println!("{}", e.bold().red()), - Err(e) => println!("{}: {}", "Connection error".red(), e), + "commit" => { + match send_command(Command::CommitTransaction).await { + Ok(Response::Success(_)) => { + println!("{}", "Transaction committed".bright_green()); + println!(); + }, + Ok(Response::Error(e)) => println!("{}", e.bold().red()), + Err(e) => println!("{}: {}", "Connection error".red(), e), + } }, - "rollback" => match send_command(Command::RollbackTransaction).await { - Ok(Response::Success(_)) => println!("{}", "Transaction rolled back".bright_green()), - Ok(Response::Error(e)) => println!("{}", e.bold().red()), - Err(e) => println!("{}: {}", "Connection error".red(), e), + "rollback" => { + match send_command(Command::RollbackTransaction).await { + Ok(Response::Success(_)) => { + println!("{}", "Transaction rolled back".bright_green()); + println!(); + }, + Ok(Response::Error(e)) => println!("{}", e.bold().red()), + Err(e) => println!("{}: {}", "Connection error".red(), e), + } }, - "create_index" => { - if parts.len() != 2 { - println!("{}", "Usage: create_index ".red()); + "createindex" => { + if parts.len() < 2 { + println!("{}", "Usage: createindex ".red()); continue; } - match send_command(Command::CreateIndex { field: parts[1].to_string() }).await { - Ok(Response::Success(_)) => println!("{}", format!("Index created on field '{}'", parts[1]).bright_green()), + let field = parts[1].to_string(); + match send_command(Command::CreateIndex { field }).await { + Ok(Response::Success(_)) => { + println!("{}", "Index created".bright_green()); + println!(); + }, Ok(Response::Error(e)) => println!("{}", e.bold().red()), Err(e) => println!("{}: {}", "Connection error".red(), e), } }, - "drop_index" => { - if parts.len() != 2 { - println!("{}", "Usage: drop_index ".red()); + "dropindex" => { + if parts.len() < 2 { + println!("{}", "Usage: dropindex ".red()); continue; } - match send_command(Command::DropIndex { field: parts[1].to_string() }).await { - Ok(Response::Success(_)) => println!("{}", format!("Index dropped on field '{}'", parts[1]).bright_green()), + let field = parts[1].to_string(); + match send_command(Command::DropIndex { field }).await { + Ok(Response::Success(_)) => { + println!("{}", "Index dropped".bright_green()); + println!(); + }, Ok(Response::Error(e)) => println!("{}", e.bold().red()), Err(e) => println!("{}: {}", "Connection error".red(), e), } }, - "help" | "h" => { + "sysexec" => { + if parts.len() < 2 { + println!("{}", "Usage: sysexec ".red()); + continue; + } + let script_name = parts[1].to_string(); + match send_command(Command::SysExec { script_name }).await { + Ok(Response::Success(Some(output))) => { + println!("{}", "Script output:".bright_green()); + println!("{}", output); + println!(); + }, + Ok(Response::Success(None)) => { + println!("{}", "Script executed but no output".yellow()); + println!(); + }, + Ok(Response::Error(e)) => println!("{}", e.bold().red()), + Err(e) => println!("{}: {}", "Connection error".red(), e), + } + }, + "help" => { println!("Available commands:"); - println!(" insert|i - Insert document"); - println!(" get|g - Get document"); - println!(" update|u - Update document"); - println!(" delete|d - Delete document"); - println!(" begin - Start transaction"); + println!(" insert (or i) - Insert data"); + println!(" get (or g) - Get data"); + println!(" update (or u) - Update data"); + println!(" delete (or d) - Delete data"); + println!(" begin (or transaction, tx) - Start transaction"); println!(" commit - Commit transaction"); println!(" rollback - Rollback transaction"); - println!(" create_index - Create index"); - println!(" drop_index - Drop index"); - println!(" help|h - Show this help"); - println!(" exit|quit|q - Exit the client"); + println!(" createindex - Create index"); + println!(" dropindex - Drop index"); + println!(" sysexec - Execute system script"); + println!(" exit (or quit) - Exit client"); + println!(" help - Show this help"); + println!(); }, - "exit" | "quit" | "q" => break, + "exit" | "quit" => break, _ => println!("{}: Unknown command. Type 'help' for available commands.", "Error".red()), } }, @@ -196,6 +266,6 @@ async fn main() -> Result<(), Box> { } } - rl.save_history("futriix-cli-history.txt")?; + rl.save_history("futriix-history.txt")?; Ok(()) } \ No newline at end of file