implement client ping (#108)

This commit is contained in:
Kim Chan
2022-08-25 17:10:32 +08:00
committed by GitHub
parent d3826795af
commit c1c3bcb465
4 changed files with 84 additions and 1 deletions

View File

@@ -26,6 +26,10 @@ struct Cli {
#[derive(Subcommand, Debug)]
enum Command {
Ping {
/// Message to ping
msg: Option<String>,
},
/// Get the value of key.
Get {
/// Name of key to get
@@ -85,6 +89,14 @@ async fn main() -> mini_redis::Result<()> {
// Process the requested command
match cli.command {
Command::Ping { msg } => {
let value = client.ping(msg).await?;
if let Ok(string) = str::from_utf8(&value) {
println!("\"{}\"", string);
} else {
println!("{:?}", value);
}
}
Command::Get { key } => {
if let Some(value) = client.get(&key).await? {
if let Ok(string) = str::from_utf8(&value) {

View File

@@ -2,7 +2,7 @@
//!
//! Provides an async connect and methods for issuing the supported commands.
use crate::cmd::{Get, Publish, Set, Subscribe, Unsubscribe};
use crate::cmd::{Get, Ping, Publish, Set, Subscribe, Unsubscribe};
use crate::{Connection, Frame};
use async_stream::try_stream;
@@ -87,6 +87,42 @@ pub async fn connect<T: ToSocketAddrs>(addr: T) -> crate::Result<Client> {
}
impl Client {
/// Ping to the server.
///
/// Returns PONG if no argument is provided, otherwise
/// return a copy of the argument as a bulk.
///
/// This command is often used to test if a connection
/// is still alive, or to measure latency.
///
/// # Examples
///
/// Demonstrates basic usage.
/// ```no_run
/// use mini_redis::client;
///
/// #[tokio::main]
/// async fn main() {
/// let mut client = client::connect("localhost:6379").await.unwrap();
///
/// let pong = client.ping(None).await.unwrap();
/// assert_eq!(b"PONG", &pong[..]);
/// }
/// ```
#[instrument(skip(self))]
pub async fn ping(&mut self, msg: Option<String>) -> crate::Result<Bytes> {
let frame = Ping::new(msg).into_frame();
debug!(request = ?frame);
self.connection.write_frame(&frame).await?;
match self.read_response().await? {
Frame::Simple(value) => Ok(value.into()),
Frame::Bulk(value) => Ok(value),
frame => Err(frame.to_error()),
}
}
/// Get the value of key.
///
/// If the key does not exist the special value `None` is returned.

View File

@@ -63,4 +63,17 @@ impl Ping {
Ok(())
}
/// Converts the command into an equivalent `Frame`.
///
/// This is called by the client when encoding a `Ping` command to send
/// to the server.
pub(crate) fn into_frame(self) -> Frame {
let mut frame = Frame::array();
frame.push_bulk(Bytes::from("ping".as_bytes()));
if let Some(msg) = self.msg {
frame.push_bulk(Bytes::from(msg));
}
frame
}
}

View File

@@ -3,6 +3,28 @@ use std::net::SocketAddr;
use tokio::net::TcpListener;
use tokio::task::JoinHandle;
/// A PING PONG test without message provided.
/// It should return "PONG".
#[tokio::test]
async fn ping_pong_without_message() {
let (addr, _) = start_server().await;
let mut client = client::connect(addr).await.unwrap();
let pong = client.ping(None).await.unwrap();
assert_eq!(b"PONG", &pong[..]);
}
/// A PING PONG test with message provided.
/// It should return the message.
#[tokio::test]
async fn ping_pong_with_message() {
let (addr, _) = start_server().await;
let mut client = client::connect(addr).await.unwrap();
let pong = client.ping(Some("你好世界".to_string())).await.unwrap();
assert_eq!("你好世界".as_bytes(), &pong[..]);
}
/// A basic "hello world" style test. A server instance is started in a
/// background task. A client instance is then established and set and get
/// commands are sent to the server. The response is then evaluated