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//!# use core::str::FromStr;
14//!# use core::net::SocketAddr;
15//!# use std_embedded_nal::Stack;
16//!# use std_embedded_time::StandardClock;
17//!# use embedded_redis::commands::hello::HelloCommand;
18//!# use embedded_redis::network::ConnectionHandler;
19//!#
20//! let mut stack = Stack::default();
21//! let clock = StandardClock::default();
22//!
23//! // RESP3 protocol is essential
24//! let mut connection_handler = ConnectionHandler::resp3(SocketAddr::from_str("127.0.0.1:6379").unwrap());
25//! let client = connection_handler.connect(&mut stack, Some(&clock)).unwrap();
26//!
27//! let command = HelloCommand{};
28//! let response = client.send(command).unwrap().wait().unwrap();
29//!
30//! assert_eq!("redis", response.server);
31//! assert_eq!("master", response.role);
32//! ```
33use crate::commands::helpers::{CmdStr, RespMap};
34use crate::commands::{Command, ResponseTypeError};
35use alloc::string::String;
36use alloc::vec::Vec;
37use redis_protocol::resp2::types::BytesFrame as Resp2Frame;
38use redis_protocol::resp3::types::{BytesFrame as Resp3Frame, RespVersion};
39
40/// Abstraction of HELLO command.
41pub struct HelloCommand {}
42
43impl Command<Resp3Frame> for HelloCommand {
44    type Response = HelloResponse;
45
46    fn encode(&self) -> Resp3Frame {
47        Resp3Frame::Hello {
48            version: RespVersion::RESP3,
49            auth: None,
50            setname: None,
51        }
52    }
53
54    fn eval_response(&self, frame: Resp3Frame) -> Result<Self::Response, ResponseTypeError> {
55        HelloResponse::try_from(frame)
56    }
57}
58
59impl Command<Resp2Frame> for HelloCommand {
60    type Response = HelloResponse;
61
62    fn encode(&self) -> Resp2Frame {
63        unimplemented!("Command requires RESP3");
64    }
65
66    fn eval_response(&self, _frame: Resp2Frame) -> Result<Self::Response, ResponseTypeError> {
67        unimplemented!("Command requires RESP3");
68    }
69}
70
71/// Mapped response to HELLO command
72#[derive(Debug)]
73pub struct HelloResponse {
74    pub server: String,
75    pub version: String,
76    pub protocol: i64,
77    pub id: i64,
78    pub mode: String,
79    pub role: String,
80    pub modules: Vec<Resp3Frame>,
81}
82
83impl TryFrom<Resp3Frame> for HelloResponse {
84    type Error = ResponseTypeError;
85
86    fn try_from(frame: Resp3Frame) -> Result<Self, Self::Error> {
87        let map = match frame {
88            Resp3Frame::Map { data, attributes: _ } => data,
89            _ => return Err(ResponseTypeError {}),
90        };
91
92        let map_cmd = RespMap::new(&map);
93
94        Ok(HelloResponse {
95            server: map_cmd.find_string("server").ok_or(ResponseTypeError {})?,
96            version: map_cmd.find_string("version").ok_or(ResponseTypeError {})?,
97            protocol: map_cmd.find_integer("proto").ok_or(ResponseTypeError {})?,
98            id: map_cmd.find_integer("id").ok_or(ResponseTypeError {})?,
99            mode: map_cmd.find_string("mode").ok_or(ResponseTypeError {})?,
100            role: map_cmd.find_string("role").ok_or(ResponseTypeError {})?,
101            modules: match map.get(&CmdStr::new("modules").to_blob()).ok_or(ResponseTypeError {})? {
102                Resp3Frame::Array { data, attributes: _ } => data.clone(),
103                _ => return Err(ResponseTypeError {}),
104            },
105        })
106    }
107}