Skip to main content

embedded_redis/commands/
hello.rs

1//! Abstraction of HELLO command.
2//!
3//! For general information about this command, see the [Redis documentation](<https://redis.io/commands/hello/>).
4//!
5//! *As this command is executed automatically during connection initialization, there is usually no
6//! need for manual execution.
7//! Response of HELLO command may be retrieved from [Client](crate::network::Client#method.get_hello_response)*
8//! # Basic usage
9//! **Requires RESP3 protocol usage, panics on RESP2**
10//!
11//! Response is mapped to [HelloResponse].
12//! ```
13//! # async_std::task::block_on(async {
14//!# use core::str::FromStr;
15//!# use core::net::SocketAddr;
16//!# use std_embedded_nal_async::Stack;
17//!# use std_embedded_time::StandardClock;
18//!# use embedded_redis::commands::hello::HelloCommand;
19//!# use embedded_redis::network::ConnectionHandler;
20//!#
21//! let stack = Stack::default();
22//! let clock = StandardClock::default();
23//!
24//! // RESP3 protocol is essential
25//! let mut connection_handler = ConnectionHandler::resp3(SocketAddr::from_str("127.0.0.1:6379").unwrap());
26//! let client = connection_handler.connect(&stack, Some(&clock)).await.unwrap();
27//!
28//! let command = HelloCommand{};
29//! let response = client.send(command).await.unwrap();
30//!
31//! assert_eq!("redis", response.server);
32//! assert_eq!("master", response.role);
33//! # });
34//! ```
35use crate::commands::helpers::{CmdStr, RespMap};
36use crate::commands::{Command, ResponseTypeError};
37use alloc::string::String;
38use alloc::vec::Vec;
39use redis_protocol::resp2::types::BytesFrame as Resp2Frame;
40use redis_protocol::resp3::types::{BytesFrame as Resp3Frame, RespVersion};
41
42/// Abstraction of HELLO command.
43pub struct HelloCommand {}
44
45impl Command<Resp3Frame> for HelloCommand {
46    type Response = HelloResponse;
47
48    fn encode(&self) -> Resp3Frame {
49        Resp3Frame::Hello {
50            version: RespVersion::RESP3,
51            auth: None,
52            setname: None,
53        }
54    }
55
56    fn eval_response(&self, frame: Resp3Frame) -> Result<Self::Response, ResponseTypeError> {
57        HelloResponse::try_from(frame)
58    }
59}
60
61impl Command<Resp2Frame> for HelloCommand {
62    type Response = HelloResponse;
63
64    fn encode(&self) -> Resp2Frame {
65        unimplemented!("Command requires RESP3");
66    }
67
68    fn eval_response(&self, _frame: Resp2Frame) -> Result<Self::Response, ResponseTypeError> {
69        unimplemented!("Command requires RESP3");
70    }
71}
72
73/// Mapped response to HELLO command
74#[derive(Debug)]
75pub struct HelloResponse {
76    pub server: String,
77    pub version: String,
78    pub protocol: i64,
79    pub id: i64,
80    pub mode: String,
81    pub role: String,
82    pub modules: Vec<Resp3Frame>,
83}
84
85impl TryFrom<Resp3Frame> for HelloResponse {
86    type Error = ResponseTypeError;
87
88    fn try_from(frame: Resp3Frame) -> Result<Self, Self::Error> {
89        let map = match frame {
90            Resp3Frame::Map { data, attributes: _ } => data,
91            _ => return Err(ResponseTypeError {}),
92        };
93
94        let map_cmd = RespMap::new(&map);
95
96        Ok(HelloResponse {
97            server: map_cmd.find_string("server").ok_or(ResponseTypeError {})?,
98            version: map_cmd.find_string("version").ok_or(ResponseTypeError {})?,
99            protocol: map_cmd.find_integer("proto").ok_or(ResponseTypeError {})?,
100            id: map_cmd.find_integer("id").ok_or(ResponseTypeError {})?,
101            mode: map_cmd.find_string("mode").ok_or(ResponseTypeError {})?,
102            role: map_cmd.find_string("role").ok_or(ResponseTypeError {})?,
103            modules: match map.get(&CmdStr::new("modules").to_blob()).ok_or(ResponseTypeError {})? {
104                Resp3Frame::Array { data, attributes: _ } => data.clone(),
105                _ => return Err(ResponseTypeError {}),
106            },
107        })
108    }
109}