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