Skip to content

Commit c1c3bcb

Browse files
authored
implement client ping (#108)
1 parent d382679 commit c1c3bcb

File tree

4 files changed

+84
-1
lines changed

4 files changed

+84
-1
lines changed

src/bin/cli.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ struct Cli {
2626

2727
#[derive(Subcommand, Debug)]
2828
enum Command {
29+
Ping {
30+
/// Message to ping
31+
msg: Option<String>,
32+
},
2933
/// Get the value of key.
3034
Get {
3135
/// Name of key to get
@@ -85,6 +89,14 @@ async fn main() -> mini_redis::Result<()> {
8589

8690
// Process the requested command
8791
match cli.command {
92+
Command::Ping { msg } => {
93+
let value = client.ping(msg).await?;
94+
if let Ok(string) = str::from_utf8(&value) {
95+
println!("\"{}\"", string);
96+
} else {
97+
println!("{:?}", value);
98+
}
99+
}
88100
Command::Get { key } => {
89101
if let Some(value) = client.get(&key).await? {
90102
if let Ok(string) = str::from_utf8(&value) {

src/client.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! Provides an async connect and methods for issuing the supported commands.
44
5-
use crate::cmd::{Get, Publish, Set, Subscribe, Unsubscribe};
5+
use crate::cmd::{Get, Ping, Publish, Set, Subscribe, Unsubscribe};
66
use crate::{Connection, Frame};
77

88
use async_stream::try_stream;
@@ -87,6 +87,42 @@ pub async fn connect<T: ToSocketAddrs>(addr: T) -> crate::Result<Client> {
8787
}
8888

8989
impl Client {
90+
/// Ping to the server.
91+
///
92+
/// Returns PONG if no argument is provided, otherwise
93+
/// return a copy of the argument as a bulk.
94+
///
95+
/// This command is often used to test if a connection
96+
/// is still alive, or to measure latency.
97+
///
98+
/// # Examples
99+
///
100+
/// Demonstrates basic usage.
101+
/// ```no_run
102+
/// use mini_redis::client;
103+
///
104+
/// #[tokio::main]
105+
/// async fn main() {
106+
/// let mut client = client::connect("localhost:6379").await.unwrap();
107+
///
108+
/// let pong = client.ping(None).await.unwrap();
109+
/// assert_eq!(b"PONG", &pong[..]);
110+
/// }
111+
/// ```
112+
#[instrument(skip(self))]
113+
pub async fn ping(&mut self, msg: Option<String>) -> crate::Result<Bytes> {
114+
let frame = Ping::new(msg).into_frame();
115+
debug!(request = ?frame);
116+
117+
self.connection.write_frame(&frame).await?;
118+
119+
match self.read_response().await? {
120+
Frame::Simple(value) => Ok(value.into()),
121+
Frame::Bulk(value) => Ok(value),
122+
frame => Err(frame.to_error()),
123+
}
124+
}
125+
90126
/// Get the value of key.
91127
///
92128
/// If the key does not exist the special value `None` is returned.

src/cmd/ping.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,17 @@ impl Ping {
6363

6464
Ok(())
6565
}
66+
67+
/// Converts the command into an equivalent `Frame`.
68+
///
69+
/// This is called by the client when encoding a `Ping` command to send
70+
/// to the server.
71+
pub(crate) fn into_frame(self) -> Frame {
72+
let mut frame = Frame::array();
73+
frame.push_bulk(Bytes::from("ping".as_bytes()));
74+
if let Some(msg) = self.msg {
75+
frame.push_bulk(Bytes::from(msg));
76+
}
77+
frame
78+
}
6679
}

tests/client.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,28 @@ use std::net::SocketAddr;
33
use tokio::net::TcpListener;
44
use tokio::task::JoinHandle;
55

6+
/// A PING PONG test without message provided.
7+
/// It should return "PONG".
8+
#[tokio::test]
9+
async fn ping_pong_without_message() {
10+
let (addr, _) = start_server().await;
11+
let mut client = client::connect(addr).await.unwrap();
12+
13+
let pong = client.ping(None).await.unwrap();
14+
assert_eq!(b"PONG", &pong[..]);
15+
}
16+
17+
/// A PING PONG test with message provided.
18+
/// It should return the message.
19+
#[tokio::test]
20+
async fn ping_pong_with_message() {
21+
let (addr, _) = start_server().await;
22+
let mut client = client::connect(addr).await.unwrap();
23+
24+
let pong = client.ping(Some("你好世界".to_string())).await.unwrap();
25+
assert_eq!("你好世界".as_bytes(), &pong[..]);
26+
}
27+
628
/// A basic "hello world" style test. A server instance is started in a
729
/// background task. A client instance is then established and set and get
830
/// commands are sent to the server. The response is then evaluated

0 commit comments

Comments
 (0)