Skip to content

Commit 6513e52

Browse files
authored
support PING command for easy testing (#90)
Signed-off-by: tison <[email protected]>
1 parent ebe4e1f commit 6513e52

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

src/cmd/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ pub use set::Set;
1010
mod subscribe;
1111
pub use subscribe::{Subscribe, Unsubscribe};
1212

13+
mod ping;
14+
pub use ping::Ping;
15+
1316
mod unknown;
1417
pub use unknown::Unknown;
1518

@@ -25,6 +28,7 @@ pub enum Command {
2528
Set(Set),
2629
Subscribe(Subscribe),
2730
Unsubscribe(Unsubscribe),
31+
Ping(Ping),
2832
Unknown(Unknown),
2933
}
3034

@@ -58,6 +62,7 @@ impl Command {
5862
"set" => Command::Set(Set::parse_frames(&mut parse)?),
5963
"subscribe" => Command::Subscribe(Subscribe::parse_frames(&mut parse)?),
6064
"unsubscribe" => Command::Unsubscribe(Unsubscribe::parse_frames(&mut parse)?),
65+
"ping" => Command::Ping(Ping::parse_frames(&mut parse)?),
6166
_ => {
6267
// The command is not recognized and an Unknown command is
6368
// returned.
@@ -95,6 +100,7 @@ impl Command {
95100
Publish(cmd) => cmd.apply(db, dst).await,
96101
Set(cmd) => cmd.apply(db, dst).await,
97102
Subscribe(cmd) => cmd.apply(db, dst, shutdown).await,
103+
Ping(cmd) => cmd.apply(dst).await,
98104
Unknown(cmd) => cmd.apply(dst).await,
99105
// `Unsubscribe` cannot be applied. It may only be received from the
100106
// context of a `Subscribe` command.
@@ -110,6 +116,7 @@ impl Command {
110116
Command::Set(_) => "set",
111117
Command::Subscribe(_) => "subscribe",
112118
Command::Unsubscribe(_) => "unsubscribe",
119+
Command::Ping(_) => "ping",
113120
Command::Unknown(cmd) => cmd.get_name(),
114121
}
115122
}

src/cmd/ping.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use crate::{Connection, Frame, Parse, ParseError};
2+
use bytes::Bytes;
3+
use tracing::{debug, instrument};
4+
5+
/// Returns PONG if no argument is provided, otherwise
6+
/// return a copy of the argument as a bulk.
7+
///
8+
/// This command is often used to test if a connection
9+
/// is still alive, or to measure latency.
10+
#[derive(Debug, Default)]
11+
pub struct Ping {
12+
/// optional message to be returned
13+
msg: Option<String>,
14+
}
15+
16+
impl Ping {
17+
/// Create a new `Ping` command with optional `msg`.
18+
pub fn new(msg: Option<String>) -> Ping {
19+
Ping { msg }
20+
}
21+
22+
/// Parse a `Ping` instance from a received frame.
23+
///
24+
/// The `Parse` argument provides a cursor-like API to read fields from the
25+
/// `Frame`. At this point, the entire frame has already been received from
26+
/// the socket.
27+
///
28+
/// The `PING` string has already been consumed.
29+
///
30+
/// # Returns
31+
///
32+
/// Returns the `Ping` value on success. If the frame is malformed, `Err` is
33+
/// returned.
34+
///
35+
/// # Format
36+
///
37+
/// Expects an array frame containing `PING` and an optional message.
38+
///
39+
/// ```text
40+
/// PING [message]
41+
/// ```
42+
pub(crate) fn parse_frames(parse: &mut Parse) -> crate::Result<Ping> {
43+
match parse.next_string() {
44+
Ok(msg) => Ok(Ping::new(Some(msg))),
45+
Err(ParseError::EndOfStream) => Ok(Ping::default()),
46+
Err(e) => Err(e.into()),
47+
}
48+
}
49+
50+
/// Apply the `Ping` command and return the message.
51+
///
52+
/// The response is written to `dst`. This is called by the server in order
53+
/// to execute a received command.
54+
#[instrument(skip(self, dst))]
55+
pub(crate) async fn apply(self, dst: &mut Connection) -> crate::Result<()> {
56+
let response = match self.msg {
57+
None => Frame::Simple("PONG".to_string()),
58+
Some(msg) => Frame::Bulk(Bytes::from(msg)),
59+
};
60+
61+
// Write the response back to the client
62+
dst.write_frame(&response).await?;
63+
64+
Ok(())
65+
}
66+
}

0 commit comments

Comments
 (0)