Skip to content

Commit bbb80c3

Browse files
authored
apply client/cli polish (#15)
Continuation of #11. Refines the client structure and implements GET. `clap` is decoupled from the lib code. This is done to avoid any CLI parsing concerns to leak into the lib. The main motivation for this is to allow the reader to focus on Tokio concerns and not CLI parsing concerns.
1 parent 7bd7086 commit bbb80c3

File tree

17 files changed

+297
-210
lines changed

17 files changed

+297
-210
lines changed

Cargo.lock

Lines changed: 24 additions & 31 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ name = "mini-redis"
55
version = "0.1.0"
66

77
[dependencies]
8-
anyhow = "1.0.27"
98
atoi = "0.3.2"
109
bytes = "0.5.4"
1110
clap = { git = "https://github.com/clap-rs/clap/" }

src/bin/cli.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
use mini_redis::{client, DEFAULT_PORT};
2+
3+
use bytes::Bytes;
4+
use clap::Clap;
5+
use std::num::ParseIntError;
6+
use std::str;
7+
use std::time::Duration;
8+
9+
#[derive(Clap, Debug)]
10+
#[clap(name = "mini-redis-cli", version = env!("CARGO_PKG_VERSION"), author = env!("CARGO_PKG_AUTHORS"), about = "Issue Redis commands")]
11+
struct Cli {
12+
#[clap(subcommand)]
13+
command: Command,
14+
15+
#[clap(name = "hostname", long = "--host", default_value = "127.0.0.1")]
16+
host: String,
17+
18+
#[clap(name = "port", long = "--port", default_value = DEFAULT_PORT)]
19+
port: String,
20+
}
21+
22+
#[derive(Clap, Debug)]
23+
enum Command {
24+
/// Get the value of key.
25+
Get {
26+
/// Name of key to get
27+
key: String
28+
},
29+
/// Set key to hold the string value.
30+
Set {
31+
/// Name of key to set
32+
key: String,
33+
34+
/// Value to set.
35+
#[clap(parse(from_str = bytes_from_str))]
36+
value: Bytes,
37+
38+
/// Expire the value after specified amount of time
39+
#[clap(parse(try_from_str = duration_from_ms_str))]
40+
expires: Option<Duration>,
41+
},
42+
}
43+
44+
/// Entry point for CLI tool.
45+
///
46+
/// The `[tokio::main]` annotation signals that the Tokio runtime should be
47+
/// started when the function is called. The body of the function is executed
48+
/// within the newly spawned runtime.
49+
///
50+
/// `basic_scheduler` is used here to avoid spawning background threads. The CLI
51+
/// tool use case benefits more by being lighter instead of multi-threaded.
52+
#[tokio::main(basic_scheduler)]
53+
async fn main() -> mini_redis::Result<()> {
54+
// Enable logging
55+
tracing_subscriber::fmt::try_init()?;
56+
57+
// Parse command line arguments
58+
let cli = Cli::parse();
59+
60+
// Get the remote address to connect to
61+
let addr = format!("{}:{}", cli.host, cli.port);
62+
63+
// Establish a connection
64+
let mut client = client::connect(&addr).await?;
65+
66+
match cli.command {
67+
Command::Get { key } => {
68+
if let Some(value) = client.get(&key).await? {
69+
if let Ok(string) = str::from_utf8(&value) {
70+
println!("\"{}\"", string);
71+
} else {
72+
println!("{:?}", value);
73+
}
74+
} else {
75+
println!("(nil)");
76+
}
77+
}
78+
Command::Set { key, value, expires: None } => {
79+
client.set(&key, value).await?;
80+
println!("OK");
81+
}
82+
Command::Set { key, value, expires: Some(expires) } => {
83+
client.set_expires(&key, value, expires).await?;
84+
println!("OK");
85+
}
86+
}
87+
88+
Ok(())
89+
}
90+
91+
fn duration_from_ms_str(src: &str) -> Result<Duration, ParseIntError> {
92+
let ms = src.parse::<u64>()?;
93+
Ok(Duration::from_millis(ms))
94+
}
95+
96+
fn bytes_from_str(src: &str) -> Bytes {
97+
Bytes::from(src.to_string())
98+
}

src/bin/client.rs

Lines changed: 0 additions & 49 deletions
This file was deleted.

src/bin/server.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use anyhow::{anyhow, Result};
2-
use clap::Clap;
31
use mini_redis::{server, DEFAULT_PORT};
42

3+
use clap::Clap;
4+
55
#[tokio::main]
6-
pub async fn main() -> Result<()> {
6+
pub async fn main() -> mini_redis::Result<()> {
77
// enable logging
88
// see https://docs.rs/tracing for more info
9-
tracing_subscriber::fmt::try_init().map_err(|e| anyhow!("{:?}", e))?;
9+
tracing_subscriber::fmt::try_init()?;
1010

1111
let cli = Cli::parse();
1212
let port = cli.port.unwrap_or(DEFAULT_PORT.to_string());

0 commit comments

Comments
 (0)