Skip to main content

undis/
connection.rs

1//! Redis connection.
2//!
3//! For more information, see the [`Connection`](Connection) type.
4
5use std::marker::Unpin;
6
7use futures_core::future::BoxFuture;
8use serde::{Deserialize, Serialize};
9use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadHalf, WriteHalf};
10
11use crate::command;
12use crate::resp3::{de, from_msg, ser_cmd, token, write_cmd, Reader, Value};
13
14/// A stateful connection to the Redis server.
15#[derive(Debug)]
16pub struct Connection<T> {
17    transport: T,
18    sender: SendCtx,
19    receiver: ReceiveCtx,
20}
21
22/// The sending-half of the connection.
23/// Can be used as a building block for higher abstractions.
24#[derive(Debug)]
25pub struct ConnectionSendHalf<T> {
26    transport: WriteHalf<T>,
27    sender: SendCtx,
28}
29
30/// The receiving-half of the connection.
31/// Can be used as a building block for higher abstractions.
32#[derive(Debug)]
33pub struct ConnectionReceiveHalf<T> {
34    transport: ReadHalf<T>,
35    receiver: ReceiveCtx,
36}
37
38#[derive(Debug)]
39struct SendCtx {
40    buf: Vec<u8>,
41    count: u64,
42}
43
44#[derive(Debug)]
45struct ReceiveCtx {
46    reader: Reader,
47    count: u64,
48}
49
50/// Errors that occur when communicating with the Redis server.
51#[derive(Debug, thiserror::Error)]
52#[error(transparent)]
53pub struct Error(#[from] pub Box<ErrorKind>);
54
55/// Internal representation of the [`Error`](Error) type.
56#[derive(Debug, thiserror::Error)]
57pub enum ErrorKind {
58    /// IO error.
59    #[error("io error")]
60    Io(#[from] std::io::Error),
61    /// Tokenize error.
62    #[error("tokenize error")]
63    Tokenize(#[from] token::Error),
64    /// Serialize error.
65    #[error("serialize error")]
66    Serialize(#[from] ser_cmd::Error),
67    /// Deserialize error.
68    #[error("deserialize error")]
69    Deserialize(#[from] de::Error),
70    /// Invalid message order.
71    /// The client receives a response from the server for the request that hasn't been sent yet.
72    #[error("invalid message order")]
73    InvalidMessageOrder,
74}
75
76impl<T: AsyncRead + AsyncWrite + Unpin> Connection<T> {
77    /// Connect to the Redis server using the `transport`.
78    ///
79    /// On success, returns the `Connection` and `HELLO` command's response
80    /// as a [`Value`](crate::resp3::Value) which contains the server's metadata.
81    pub async fn new(transport: T) -> Result<(Self, Value), Error> {
82        Self::with_args(transport, None, None, None).await
83    }
84
85    /// Connects to the Redis server using the `transport` and parameters.
86    /// See the [`Builder`](crate::client::Builder)'s methods for the usage of each parameter.
87    pub async fn with_args(
88        transport: T,
89        auth: Option<(&str, &str)>,
90        setname: Option<&str>,
91        select: Option<u32>,
92    ) -> Result<(Self, Value), Error> {
93        let mut chan = Connection {
94            transport,
95            sender: SendCtx {
96                buf: Vec::new(),
97                count: 0,
98            },
99            receiver: ReceiveCtx {
100                reader: Reader::new(),
101                count: 0,
102            },
103        };
104
105        let auth = auth.map(|(username, password)| ("AUTH", username, password));
106        let setname = setname.map(|clientname| ("SETNAME", clientname));
107        let resp = chan.raw_command(&("HELLO", 3, auth, setname)).await?;
108
109        if let Some(db) = select {
110            let serde::de::IgnoredAny = chan.raw_command(&("SELECT", db)).await?;
111        }
112
113        Ok((chan, resp))
114    }
115
116    /// Sends a command without waiting for a response.
117    ///
118    /// Returns a one-based index of the command sent from this connection.
119    pub async fn send<Req: Serialize>(&mut self, request: Req) -> Result<u64, Error> {
120        self.sender.send(&mut self.transport, request).await
121    }
122
123    /// Wait until a response arrives.
124    ///
125    /// Returns an optional one-based index of the response arrived from this connection.
126    /// This index can be useful for matching a command and its corresponding response.
127    ///
128    /// The index is `None` for the [`Push`](crate::resp3::token::Token::Push) message
129    /// since it does not have a corresponding command.
130    ///
131    /// It's guaranteed that `.message()` returns `Some(msg)` after this method returns `Ok(idx)`.
132    pub async fn wait_response(&mut self) -> Result<Option<u64>, Error> {
133        self.receiver.wait_response(&mut self.transport).await
134    }
135
136    /// Get the last response received.
137    pub fn response(&self) -> Option<token::Message<'_>> {
138        self.receiver.response()
139    }
140
141    /// Sends any command and get a response.
142    ///
143    /// Both command and response are serialized/deserialized using [`serde`](serde).
144    /// See [`CommandSerializer`](crate::resp3::ser_cmd::CommandSerializer)
145    /// and [`Deserializer`](crate::resp3::de::Deserializer) for details.
146    ///
147    /// Returned response may contain a reference to the connection's internal receive buffer.
148    pub async fn raw_command<'de, Req: Serialize, Resp: Deserialize<'de>>(
149        &'de mut self,
150        request: Req,
151    ) -> Result<Resp, Error> {
152        let req_cnt = self.send(request).await?;
153
154        loop {
155            match self.wait_response().await? {
156                // push message
157                None => continue,
158                // response from some previous request
159                // maybe due to the cancelation
160                Some(cnt) if cnt < req_cnt => continue,
161                // response from a future request??
162                Some(cnt) if cnt > req_cnt => return Err(ErrorKind::InvalidMessageOrder.into()),
163                // response from the very request
164                Some(_) => break,
165            }
166        }
167
168        // at this point the receiver always stores the non-push message
169        Ok(from_msg(self.receiver.response().unwrap())?)
170    }
171
172    /// Splits the connection into send/receive halves.
173    /// Can be used as a building block for higher abstractions.
174    pub fn split(self) -> (ConnectionSendHalf<T>, ConnectionReceiveHalf<T>) {
175        let (read, write) = tokio::io::split(self.transport);
176        (
177            ConnectionSendHalf {
178                transport: write,
179                sender: self.sender,
180            },
181            ConnectionReceiveHalf {
182                transport: read,
183                receiver: self.receiver,
184            },
185        )
186    }
187}
188
189impl<T: AsyncRead + AsyncWrite + Send + Unpin> command::RawCommandMut for Connection<T> {
190    fn raw_command<'de, Req, Resp>(
191        &'de mut self,
192        request: Req,
193    ) -> BoxFuture<'de, Result<Resp, Error>>
194    where
195        Req: Serialize + Send + 'de,
196        Resp: Deserialize<'de> + 'de,
197    {
198        Box::pin(self.raw_command(request))
199    }
200}
201
202impl<T: AsyncWrite + Unpin> ConnectionSendHalf<T> {
203    /// Sends a command without waiting for a response.
204    ///
205    /// Returns a one-based index of the command sent from this connection.
206    pub async fn send<Req: Serialize>(&mut self, request: Req) -> Result<u64, Error> {
207        self.sender.send(&mut self.transport, request).await
208    }
209
210    /// Checks if two halves are from the same [`Connection`](Connection).
211    pub fn is_pair_of(&self, other: &ConnectionReceiveHalf<T>) -> bool {
212        other.transport.is_pair_of(&self.transport)
213    }
214
215    /// Merge two halves that have been split.
216    ///
217    /// # Panic
218    ///
219    /// Panics if the `self` and the `other` are not from the same [`Connection`](Connection).
220    pub fn unsplit(self, other: ConnectionReceiveHalf<T>) -> Connection<T> {
221        let transport = other.transport.unsplit(self.transport);
222
223        Connection {
224            transport,
225            sender: self.sender,
226            receiver: other.receiver,
227        }
228    }
229}
230
231impl<T: AsyncRead + Unpin> ConnectionReceiveHalf<T> {
232    /// Wait until a response arrives.
233    ///
234    /// Returns an optional one-based index of the response arrived from this connection.
235    /// This index can be useful for matching a command and its corresponding response.
236    ///
237    /// The index is `None` for the [`Push`](crate::resp3::token::Token::Push) message
238    /// since it does not have a corresponding command.
239    ///
240    /// It's guaranteed that `.message()` returns `Some(msg)` after this method returns `Ok(idx)`.
241    pub async fn wait_response(&mut self) -> Result<Option<u64>, Error> {
242        self.receiver.wait_response(&mut self.transport).await
243    }
244
245    /// Get the last response received.
246    pub fn response(&self) -> Option<token::Message<'_>> {
247        self.receiver.response()
248    }
249}
250
251impl SendCtx {
252    async fn send<T, Req>(&mut self, transport: &mut T, request: Req) -> Result<u64, Error>
253    where
254        T: AsyncWrite + Unpin,
255        Req: Serialize,
256    {
257        let cmd = write_cmd(&mut self.buf, &request)?;
258        transport.write_all(cmd).await?;
259
260        self.count += 1;
261        Ok(self.count)
262    }
263}
264
265impl ReceiveCtx {
266    async fn wait_response<T>(&mut self, transport: &mut T) -> Result<Option<u64>, Error>
267    where
268        T: AsyncRead + Unpin,
269    {
270        while self.reader.message_not_ready()? {
271            transport.read_buf(self.reader.buf()).await?;
272        }
273
274        // at this point the reader always stores the message
275        let msg = self.reader.message().unwrap();
276
277        let count = match msg.head() {
278            // server push message doesn't belong to the request-response mapping
279            token::Token::Push(_) => None,
280            _ => {
281                self.count += 1;
282                Some(self.count)
283            }
284        };
285
286        Ok(count)
287    }
288
289    fn response(&self) -> Option<token::Message<'_>> {
290        self.reader.message()
291    }
292}
293
294impl From<ErrorKind> for Error {
295    fn from(err: ErrorKind) -> Self {
296        Self(Box::new(err))
297    }
298}
299
300impl From<std::io::Error> for Error {
301    fn from(err: std::io::Error) -> Self {
302        Self(Box::new(err.into()))
303    }
304}
305
306impl From<token::Error> for Error {
307    fn from(err: token::Error) -> Self {
308        Self(Box::new(err.into()))
309    }
310}
311
312impl From<ser_cmd::Error> for Error {
313    fn from(err: ser_cmd::Error) -> Self {
314        Self(Box::new(err.into()))
315    }
316}
317
318impl From<de::Error> for Error {
319    fn from(err: de::Error) -> Self {
320        Self(Box::new(err.into()))
321    }
322}