embedded_redis/network/
handler.rs1use crate::commands::auth::AuthCommand;
2use crate::commands::builder::{CommandBuilder, ToStringOption};
3use crate::commands::hello::HelloCommand;
4use crate::commands::ping::PingCommand;
5use crate::commands::Command;
6use crate::network::buffer::Network;
7use crate::network::client::{Client, CommandErrors};
8use crate::network::handler::ConnectionError::TcpConnectionFailed;
9use crate::network::protocol::{Protocol, Resp2, Resp3};
10use crate::network::response::MemoryParameters;
11use alloc::string::{String, ToString};
12use core::marker::PhantomData;
13use core::net::SocketAddr;
14use embedded_nal_async::TcpConnect;
15use embedded_time::duration::Extensions;
16use embedded_time::duration::Microseconds;
17use embedded_time::Clock;
18
19#[derive(Debug, Eq, PartialEq)]
21pub enum ConnectionError {
22 TcpConnectionFailed,
24
25 AuthenticationError(CommandErrors),
27
28 ProtocolSwitchError(CommandErrors),
30}
31
32#[derive(Clone)]
34pub struct Credentials {
35 pub(crate) username: Option<String>,
36 pub(crate) password: String,
37}
38
39impl Credentials {
40 pub fn acl(username: &str, password: &str) -> Self {
43 Credentials {
44 username: Some(username.to_string()),
45 password: password.to_string(),
46 }
47 }
48
49 pub fn password_only(password: &str) -> Self {
52 Self {
53 username: None,
54 password: password.to_string(),
55 }
56 }
57}
58
59pub struct ConnectionHandler<N: TcpConnect, P: Protocol>
64where
65 HelloCommand: Command<<P as Protocol>::FrameType>,
66{
67 remote: SocketAddr,
69
70 authentication: Option<Credentials>,
72
73 timeout: Microseconds,
75
76 memory: MemoryParameters,
78
79 protocol: P,
81
82 use_ping: bool,
84
85 network: PhantomData<N>,
87}
88
89impl<N: TcpConnect> ConnectionHandler<N, Resp2> {
90 pub fn resp2(remote: SocketAddr) -> Self {
92 ConnectionHandler::new(remote, Resp2 {})
93 }
94}
95
96impl<N: TcpConnect> ConnectionHandler<N, Resp3> {
97 pub fn resp3(remote: SocketAddr) -> Self {
99 ConnectionHandler::new(remote, Resp3 {})
100 }
101}
102
103impl<N: TcpConnect, P: Protocol> ConnectionHandler<N, P>
104where
105 AuthCommand: Command<<P as Protocol>::FrameType>,
106 HelloCommand: Command<<P as Protocol>::FrameType>,
107 PingCommand: Command<<P as Protocol>::FrameType>,
108 <P as Protocol>::FrameType: ToStringOption,
109 <P as Protocol>::FrameType: From<CommandBuilder>,
110{
111 fn new(remote: SocketAddr, protocol: P) -> Self {
112 ConnectionHandler {
113 remote,
114 authentication: None,
115 timeout: 0.microseconds(),
116 memory: MemoryParameters::default(),
117 protocol,
118 use_ping: false,
119 network: PhantomData,
120 }
121 }
122
123 pub async fn connect<'a, C: Clock>(
125 &self,
126 network: &'a N,
127 clock: Option<&'a C>,
128 ) -> Result<Client<'a, N::Connection<'a>, C, P>, ConnectionError> {
129 let connection = network.connect(self.remote).await.map_err(|_| TcpConnectionFailed)?;
130
131 let mut client = Client {
132 network: Network::new(connection, self.protocol.clone(), self.memory.clone()),
133 timeout_duration: self.timeout,
134 clock,
135 hello_response: None,
136 };
137
138 client.hello_response = client.init(self.authentication.clone()).await?;
139
140 if self.use_ping {
141 client.ping().await.map_err(|_| TcpConnectionFailed)?;
142 }
143
144 Ok(client)
145 }
146}
147
148impl<N: TcpConnect, P: Protocol> ConnectionHandler<N, P>
149where
150 HelloCommand: Command<<P as Protocol>::FrameType>,
151{
152 pub fn timeout(&mut self, timeout: Microseconds) -> &mut Self {
154 self.timeout = timeout;
155 self
156 }
157
158 pub fn auth(&mut self, credentials: Credentials) -> &mut Self {
160 self.authentication = Some(credentials);
161 self
162 }
163
164 pub fn use_ping(&mut self) -> &mut Self {
166 self.use_ping = true;
167 self
168 }
169
170 pub fn memory(&mut self, parameters: MemoryParameters) -> &mut Self {
172 self.memory = parameters;
173 self
174 }
175}