diff options
author | evuez <julien@mulga.net> | 2022-11-26 15:38:06 -0500 |
---|---|---|
committer | evuez <julien@mulga.net> | 2024-04-03 22:44:12 +0200 |
commit | 86098797034cbc7eb6db0cee54e17f8dcaedbc5d (patch) | |
tree | 29b6225ead843eb9022296a54657bbadfa1c4da0 /src/repl.rs | |
download | blom-main.tar.gz |
Diffstat (limited to 'src/repl.rs')
-rw-r--r-- | src/repl.rs | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/src/repl.rs b/src/repl.rs new file mode 100644 index 0000000..339405e --- /dev/null +++ b/src/repl.rs @@ -0,0 +1,134 @@ +use crate::common::expr::Error as ProtoError; +use crate::common::expr::Expr; +use crate::common::term::Term; +use std::io::BufReader; +use std::io::Write; +use std::net::TcpStream; +use std::process::ExitCode; + +pub const USAGE: &str = " +Usage: blom start + + Starts the blom repl. + + -b, --bind Bind to the given ADDRESS:PORT. Default is + 0.0.0.0:4902 + +"; + +enum Error { + Connect, +} + +pub fn cmd(args: &[String]) -> ExitCode { + let mut addr = "0.0.0.0:4902"; + + let mut arg_index: usize = 0; + while arg_index < args.len() { + match args[arg_index].as_str() { + "--addr" | "-a" => { + addr = args + .get(arg_index + 1) + .expect("Missing address after --addr.") + .as_str(); + arg_index += 1; + } + _ => { + println!("Too many arguments."); + return ExitCode::FAILURE; + } + } + + arg_index += 1; + } + + match start(addr) { + Ok(()) => ExitCode::SUCCESS, + Err(_) => ExitCode::FAILURE, + } +} + +fn start(addr: &str) -> Result<(), Error> { + let mut term = Term::new(); + + term.setup_prompt(format!("{addr}> ").as_bytes()); + term.setup_hints(hints); + + while let Some(query) = input(&mut term) { + if query.is_empty() { + continue; + } + + let mut stream = match try_connect(addr) { + Ok(stream) => stream, + Err(_) => continue, + }; + + let expr = Expr::from_query(&query); + + if stream.write(&expr.encode()).is_err() { + println!("Couldn't connect to blom at {addr}"); + continue; + } + + let mut resp = BufReader::new(&stream); + + match Expr::from_bytes(&mut resp) { + Ok(resp) => println!("{resp}"), + Err(ProtoError::ConnectionClosed) => { + println!("Couldn't connect to blom at {addr}"); + continue; + } + Err(e) => { + println!("{e}"); + break; + } + } + } + + Ok(()) +} + +fn try_connect(addr: &str) -> Result<TcpStream, Error> { + match TcpStream::connect(addr) { + Ok(stream) => Ok(stream), + Err(_) => { + println!("Couldn't connect to blom at {addr}."); + Err(Error::Connect) + } + } +} + +fn input(term: &mut Term) -> Option<String> { + let line = term.edit()?; + let query = std::str::from_utf8(&line).unwrap().trim(); + + if query == "exit" { + return None; + } + + Some(query.to_string()) +} + +// TODO: Refactor +fn hints(line: &[u8]) -> &[u8] { + match line { + b"ECHO" | b"echo" => b" MESSAGE", + b"SET" | b"set" => b" BLOCK META", + b"GET" | b"get" => b" BLOCK", + b"DEL" | b"del" => b" BLOCK", + b"EXISTS" | b"exists" => b" BLOCK", + b"INFO" | b"info" => b" BLOCK", + b"PARENT" | b"parent" => b" BLOCK", + b"CHILDREN" | b"children" => b" BLOCK", + b"ECHO " | b"echo " => b"MESSAGE", + b"SET " | b"set " => b"BLOCK META", + b"GET " | b"get " => b"BLOCK", + b"DEL " | b"del " => b"BLOCK", + b"EXISTS " | b"exists " => b"BLOCK", + b"INFO " | b"info " => b"BLOCK", + b"PARENT " | b"parent " => b"BLOCK", + b"CHILDREN " | b"children " => b"BLOCK", + _ => b"", + } +} |