1use tokio::{
2 io::{AsyncReadExt, AsyncWriteExt},
3 net::{TcpStream, ToSocketAddrs},
4};
5
6mod err;
7pub use err::{Error, Result};
8
9#[derive(Debug)]
10pub struct Client {
11 conn: TcpStream,
12}
13
14impl Client {
15 pub async fn connect<A: ToSocketAddrs>(addr: A) -> Result<Self> {
16 let conn = TcpStream::connect(addr).await?;
17 Ok(Self { conn })
18 }
19
20 pub async fn set(&mut self, k: &str, v: &str) -> Result<()> {
22 let cmd = format!(
23 "*3\r\n${cmd_len}\r\nSET\r\n${k_len}\r\n{k}\r\n${v_len}\r\n{v}\r\n",
24 cmd_len = 3,
25 k_len = k.len(),
26 v_len = v.len(),
27 );
28
29 self.conn.write_all(cmd.as_bytes()).await?;
31 self.conn.flush().await?;
32
33 let mut buf = [0; 512];
35 let size = self.conn.read(&mut buf).await?;
36
37 let resp = String::from_utf8_lossy(&buf[..size]);
38 if resp.starts_with("+OK") {
39 Ok(())
40 } else {
41 Err(Error::Custom(resp.to_string()))
42 }
43 }
44
45 pub async fn get(&mut self, k: &str) -> Result<Option<String>> {
47 let cmd = format!(
48 "*2\r\n${cmd_len}\r\nGET\r\n${k_len}\r\n{k}\r\n",
49 cmd_len = 3,
50 k_len = k.len(),
51 );
52
53 self.conn.write_all(cmd.as_bytes()).await?;
55 self.conn.flush().await?;
56
57 let mut buf = [0; 512];
59 let size = self.conn.read(&mut buf).await?;
60
61 let resp = String::from_utf8_lossy(&buf[..size]);
62 if resp.starts_with("$-1") {
63 Ok(None)
64 } else {
65 let parts = resp.split("\r\n").collect::<Vec<_>>();
66 Ok(Some(parts[1].to_string()))
67 }
68 }
69}