Skip to content

Commit 4714808

Browse files
authored
Merge pull request #17 from Miaxos/feat-add-get-name
Feat: Add client get name
2 parents 82a5e13 + 58705c7 commit 4714808

File tree

4 files changed

+101
-2
lines changed

4 files changed

+101
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use super::super::parse::Parse;
2+
use crate::application::server::connection::WriteConnection;
3+
use crate::application::server::context::Context;
4+
use crate::application::server::frame::Frame;
5+
6+
/// The CLIENT GETNAME returns the name of the current connection as set by
7+
/// CLIENT SETNAME. Since every new connection starts without an associated
8+
/// name, if no name was assigned a null bulk reply is returned.
9+
#[derive(Debug, Default)]
10+
pub struct ClientGetName {}
11+
12+
impl ClientGetName {
13+
pub fn new() -> ClientGetName {
14+
ClientGetName {}
15+
}
16+
17+
pub(crate) fn parse_frames(
18+
parse: &mut Parse,
19+
) -> anyhow::Result<ClientGetName> {
20+
parse.finish()?;
21+
Ok(ClientGetName::new())
22+
}
23+
24+
pub(crate) async fn apply(
25+
self,
26+
dst: &mut WriteConnection,
27+
ctx: Context,
28+
) -> anyhow::Result<()> {
29+
let name = ctx.connection.name().await;
30+
31+
let response = match name {
32+
Some(name) => Frame::Bulk(name.into_bytes()),
33+
None => Frame::Null,
34+
};
35+
dst.write_frame(&response).await?;
36+
37+
Ok(())
38+
}
39+
}
40+
41+
#[cfg(test)]
42+
mod tests {
43+
use std::io::Cursor;
44+
45+
use bytes::BytesMut;
46+
use redis_async::resp::{RespCodec, RespValue};
47+
use redis_async::resp_array;
48+
use tokio_util::codec::Encoder;
49+
50+
use crate::application::server::cmd::Command;
51+
use crate::application::server::frame::Frame;
52+
53+
fn parse_cmd(obj: RespValue) -> anyhow::Result<Command> {
54+
let mut bytes = BytesMut::new();
55+
let mut codec = RespCodec;
56+
codec.encode(obj, &mut bytes).unwrap();
57+
58+
let mut bytes = Cursor::new(bytes.freeze());
59+
let frame = Frame::parse(&mut bytes)?;
60+
let client_list = Command::from_frame(frame)?;
61+
Ok(client_list)
62+
}
63+
64+
#[test]
65+
fn ensure_parsing() {
66+
let entry: RespValue = resp_array!["CLIENT", "GETNAME"];
67+
let client_cmd = parse_cmd(entry).unwrap();
68+
insta::assert_debug_snapshot!(client_cmd, @r###"
69+
Client(
70+
GetName(
71+
ClientGetName,
72+
),
73+
)
74+
"###);
75+
}
76+
77+
#[test]
78+
fn ensure_parsing_too_much() {
79+
let entry: RespValue = resp_array!["CLIENT", "GETNAME", "BLBL"];
80+
let client_cmd = parse_cmd(entry);
81+
assert!(client_cmd.is_err());
82+
let client_cmd = client_cmd.unwrap_err();
83+
insta::assert_debug_snapshot!(client_cmd, @r###"
84+
Other(
85+
"protocol error; expected end of frame, but there was more",
86+
)
87+
"###);
88+
}
89+
}

app/roster/src/application/server/cmd/client/mod.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::application::server::connection::WriteConnection;
66
use crate::application::server::context::Context;
77
use crate::application::server::frame::Frame;
88

9+
mod get_name;
910
mod id;
1011
mod info;
1112
mod list;
@@ -16,16 +17,19 @@ mod set_name;
1617
pub enum Client {
1718
Help,
1819
SetInfo(set_info::ClientSetInfo),
20+
Info(info::ClientInfo),
1921
SetName(set_name::ClientSetName),
22+
GetName(get_name::ClientGetName),
2023
List(list::ClientList),
2124
Id(id::ClientID),
22-
Info(info::ClientInfo),
2325
}
2426

2527
// TODO(@miaxos): This is a simple implementation of the HELP to have the
2628
// associated test, but the idea is to change it to an autogenerated help based
2729
// on commands available and the documentation of the structure.
2830
const HELP_TEXT: &str = r#"CLIENT <subcommand> [<arg> [value] [opt] ...]. subcommands are:
31+
GETNAME
32+
Return the name of the current connection.
2933
ID
3034
Return the ID of the current connection.
3135
INFO
@@ -65,6 +69,9 @@ impl SubcommandRegistry for Client {
6569
"setname" => Command::Client(Client::SetName(
6670
set_name::ClientSetName::parse_frames(&mut parse)?,
6771
)),
72+
"getname" => Command::Client(Client::GetName(
73+
get_name::ClientGetName::parse_frames(&mut parse)?,
74+
)),
6875
"id" => Command::Client(Client::Id(id::ClientID::parse_frames(
6976
&mut parse,
7077
)?)),
@@ -120,6 +127,7 @@ impl CommandExecution for Client {
120127
Client::Help => Client::help(dst, ctx).await,
121128
Client::SetInfo(cmd) => cmd.apply(dst, ctx).await,
122129
Client::SetName(cmd) => cmd.apply(dst, ctx).await,
130+
Client::GetName(cmd) => cmd.apply(dst, ctx).await,
123131
Client::Id(cmd) => cmd.apply(dst, ctx).await,
124132
Client::Info(cmd) => cmd.apply(dst, ctx).await,
125133
Client::List(cmd) => cmd.apply(dst, ctx).await,

app/roster/tests/client.rs

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ pub async fn test_simple_client_help() {
3131

3232
insta::assert_display_snapshot!(joined, @r###"
3333
CLIENT <subcommand> [<arg> [value] [opt] ...]. subcommands are:
34+
GETNAME
35+
Return the name of the current connection.
3436
ID
3537
Return the ID of the current connection.
3638
INFO

docs/cmd_list.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ the command or open an issue.
3939
- [ ] BZPOPMAX
4040
- [ ] BZPOPMIN
4141
- [ ] CLIENT CACHING
42-
- [ ] CLIENT GETNAME
42+
- [x] CLIENT GETNAME
4343
- [ ] CLIENT GETREDIR
4444
- [x] CLIENT HELP
4545
- [x] CLIENT ID

0 commit comments

Comments
 (0)