From d6d764cfb9f10640a0b9ac14a8a37db71ea707e5 Mon Sep 17 00:00:00 2001 From: Sayan Nandan Date: Sun, 16 Aug 2020 19:45:58 +0530 Subject: [PATCH] Improve command line output for responses --- Cargo.lock | 28 +++++++ cli/src/protocol/deserializer.rs | 14 ---- cli/src/protocol/mod.rs | 10 --- corelib/Cargo.toml | 3 +- corelib/src/de.rs | 139 +++++++++++++++++++++++++++---- 5 files changed, 155 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39262d5d..bf9349b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,6 +55,7 @@ version = "0.4.0" dependencies = [ "bytes", "lazy_static", + "termion", ] [[package]] @@ -257,6 +258,12 @@ dependencies = [ "libc", ] +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" + [[package]] name = "parking_lot" version = "0.11.0" @@ -360,6 +367,15 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +dependencies = [ + "redox_syscall", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -428,6 +444,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "termion" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" +dependencies = [ + "libc", + "numtoa", + "redox_syscall", + "redox_termios", +] + [[package]] name = "tokio" version = "0.2.22" diff --git a/cli/src/protocol/deserializer.rs b/cli/src/protocol/deserializer.rs index 6600a7fc..a14664ff 100644 --- a/cli/src/protocol/deserializer.rs +++ b/cli/src/protocol/deserializer.rs @@ -29,7 +29,6 @@ use std::fmt; /// Errors that may occur while parsing responses from the server #[derive(Debug, PartialEq)] pub enum ClientResult { - RespCode(RespCodes, usize), InvalidResponse(usize), Response(Vec, usize), Empty(usize), @@ -39,20 +38,7 @@ pub enum ClientResult { impl fmt::Display for ClientResult { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use ClientResult::*; - use RespCodes::*; match self { - RespCode(r, _) => match r { - Okay => Ok(()), - NotFound => writeln!(f, "ERROR: Couldn't find the key"), - OverwriteError => writeln!(f, "ERROR: Existing values cannot be overwritten"), - PacketError => writeln!(f, "ERROR: An invalid request was sent"), - ActionError => writeln!(f, "ERROR: The action is not in the correct format"), - ServerError => writeln!(f, "ERROR: The server had an internal error"), - OtherError(e) => match e { - None => writeln!(f, "ERROR: An unknown error occurred"), - Some(e) => writeln!(f, "ERROR: {}", e), - }, - }, InvalidResponse(_) => write!(f, "ERROR: The server sent an invalid response"), Response(_, _) => unimplemented!(), Empty(_) => write!(f, ""), diff --git a/cli/src/protocol/mod.rs b/cli/src/protocol/mod.rs index 0cfd0cbb..53fa3401 100644 --- a/cli/src/protocol/mod.rs +++ b/cli/src/protocol/mod.rs @@ -77,16 +77,6 @@ impl Connection { } return; } - x @ ClientResult::RespCode(_, _) => { - match x { - ClientResult::RespCode(_, f) => { - self.buffer.advance(f); - } - _ => unimplemented!(), - } - eprint!("{}", x); - return; - } ClientResult::InvalidResponse(_) => { self.buffer.clear(); eprintln!("{}", ClientResult::InvalidResponse(0)); diff --git a/corelib/Cargo.toml b/corelib/Cargo.toml index 1b929527..c9cf001e 100644 --- a/corelib/Cargo.toml +++ b/corelib/Cargo.toml @@ -8,4 +8,5 @@ edition = "2018" [dependencies] lazy_static = "1.4.0" -bytes = "0.5.6" \ No newline at end of file +bytes = "0.5.6" +termion = "*" \ No newline at end of file diff --git a/corelib/src/de.rs b/corelib/src/de.rs index 1cdc968b..d3aec96e 100644 --- a/corelib/src/de.rs +++ b/corelib/src/de.rs @@ -23,6 +23,7 @@ //! The `de` module provides primitives for deserialization primitives for parsing //! query and response packets +use crate::terrapipe::RespCodes; use bytes::BytesMut; use std::fmt; use std::ops::Deref; @@ -184,32 +185,142 @@ pub struct DataGroup(pub Vec); impl fmt::Display for DataGroup { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use termion::{color, style}; /* TODO(@ohsayan): Implement proper formatting for the response. That is, for `!` print the respective error code, for `+` print the corresponding array or single-value */ - if self.0.len() == 0 { + if self.len() == 0 { + // The server returned a zero-sized array return write!(f, "[]"); } - if self.0.len() == 1 { - return write!(f, "{}", &self.0[0][1..]); - } - let mut it = self.0.iter().peekable(); - write!(f, "[")?; - while let Some(token) = it.next() { - if it.peek().is_some() { - write!(f, "\"{}\"", token)?; - write!(f, ", ")?; - } else { - write!(f, "\"{}\"", token)?; - write!(f, "]")?; + for token in self.iter() { + if token.len() == 0 { + write!(f, "\"\"")?; + continue; + } + let mut byter = token.bytes(); + match byter.next().unwrap() { + b'!' => { + // This is an error + match byter.next() { + Some(tok) => match RespCodes::from_utf8(tok) { + Some(code) => { + use RespCodes::*; + match code { + Okay => write!( + f, + "{}(Okay){}", + color::Fg(color::Rgb(2, 117, 216)), + style::Reset + )?, + NotFound => write!( + f, + "{}ERROR: Couldn't find the key{}", + color::Fg(color::LightRed), + style::Reset + )?, + OverwriteError => { + write!( + f, + "{}ERROR: Existing values cannot be overwritten{}", + color::Fg(color::LightRed), + style::Reset + )?; + } + PacketError => { + write!( + f, + "{}ERROR: An invalid request was sent{}", + color::Fg(color::LightRed), + style::Reset + )?; + } + ActionError => write!( + f, + "{}ERROR: The action is not in the correct format{}", + color::Fg(color::LightRed), + style::Reset + )?, + ServerError => write!( + f, + "{}(Server Error){}", + color::Fg(color::LightRed), + style::Reset + )?, + OtherError(_) => { + let rem = byter.collect::>(); + if rem.len() == 0 { + write!( + f, + "{}(Unknown Error){}", + color::Fg(color::LightRed), + style::Reset + )?; + } else { + write!( + f, + "{}({}){}", + color::Fg(color::LightRed), + String::from_utf8_lossy(&rem), + style::Reset + )?; + } + } + } + } + None => { + let rem = byter.collect::>(); + if rem.len() == 0 { + write!( + f, + "{}(Unknown Error){}", + color::Fg(color::LightRed), + style::Reset + )?; + } else { + write!( + f, + "{}({}{}){}", + tok, + color::Fg(color::LightRed), + String::from_utf8_lossy(&rem), + style::Reset + )?; + } + } + }, + None => write!( + f, + "{}(Unknown Error){}", + color::Fg(color::LightRed), + style::Reset + )?, + } + } + b'+' => { + // This is a positive response + let rem = byter.collect::>(); + write!(f, "\"{}\"", String::from_utf8_lossy(&rem))?; + } + x @ _ => { + // Unknown response + let rem = byter.collect::>(); + write!( + f, + "{}Unknown response: \"{}{}\"{}", + color::Fg(color::Rgb(255, 69, 0)), + x, + String::from_utf8_lossy(&rem), + style::Reset + )?; + } } } Ok(()) } } - impl IntoIterator for DataGroup { type Item = String; type IntoIter = std::vec::IntoIter;