Skip to content

Commit f3996c9

Browse files
committed
Implement the SET & GET commands
1 parent 5722d92 commit f3996c9

File tree

7 files changed

+102
-37
lines changed

7 files changed

+102
-37
lines changed

src/cmd.rs

+25-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
use crate::protocol::Protocol;
1+
use std::sync::{Arc, Mutex};
2+
3+
use crate::{protocol::Protocol, storage::Storage};
24
use anyhow::Result;
35

46
pub enum Cmd {
57
Ping,
68
Echo(String),
7-
Unknown(),
9+
Get(String),
10+
Set(String, String),
811
}
912

1013
impl Cmd {
@@ -19,18 +22,34 @@ impl Cmd {
1922
Ok(match cmd[0].as_str() {
2023
"echo" => Cmd::Echo(cmd[1].clone()),
2124
"ping" => Cmd::Ping,
22-
_ => Cmd::Unknown(),
25+
"get" => Cmd::Get(cmd[1].clone()),
26+
"set" => Cmd::Set(cmd[1].clone(), cmd[2].clone()),
27+
_ => return Err(anyhow::anyhow!("unknown cmd {:?}", cmd[0])),
2328
})
2429
}
2530
_ => Err(anyhow::anyhow!("fail to parse as cmd for {:?}", protocol.0)),
2631
}
2732
}
2833

29-
pub fn run(self: &Self) -> Result<Protocol> {
34+
pub fn run(self: &Self, storage: &mut Arc<Mutex<Storage>>) -> Result<Protocol> {
3035
match self {
31-
Cmd::Echo(s) => Ok(Protocol::SimpleString(s.clone())),
3236
Cmd::Ping => Ok(Protocol::SimpleString("PONG".to_string())),
33-
_ => Err(anyhow::anyhow!("unknown cmd")),
37+
Cmd::Echo(s) => Ok(Protocol::SimpleString(s.clone())),
38+
Cmd::Get(k) => {
39+
let s = storage.lock().unwrap();
40+
Ok(if let Some(v) = s.get(k) {
41+
Protocol::SimpleString(v.clone())
42+
} else {
43+
Protocol::Null
44+
})
45+
},
46+
Cmd::Set(k, v) => {
47+
{
48+
let mut s = storage.lock().unwrap();
49+
s.set(k.clone(), v.clone());
50+
}
51+
Ok(Protocol::ok())
52+
}
3453
}
3554
}
3655
}

src/handler.rs

-28
This file was deleted.

src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
mod cmd;
2-
pub mod handler;
32
mod protocol;
3+
pub mod server;
4+
mod storage;

src/main.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![allow(unused_imports)]
22

3-
use redis_starter_rust::handler;
3+
use redis_starter_rust::server;
44

55
use tokio::io::{AsyncReadExt, AsyncWriteExt};
66
use tokio::net::TcpListener;
@@ -10,15 +10,17 @@ async fn main() {
1010
println!("Logs from your program will appear here!");
1111

1212
let listener = TcpListener::bind("127.0.0.1:6379").await.unwrap();
13+
let server = server::Server::new();
1314

1415
loop {
1516
let stream = listener.accept().await;
1617
match stream {
1718
Ok((stream, _)) => {
1819
println!("accepted new connection");
1920

21+
let mut sc = server.clone();
2022
tokio::spawn(async move {
21-
handler::handle(stream).await;
23+
sc.handle(stream).await;
2224
});
2325
}
2426
Err(e) => {

src/protocol.rs

+8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use anyhow::Result;
44
pub enum Protocol {
55
SimpleString(String),
66
BulkString(String),
7+
Null,
78
Array(Vec<Protocol>),
89
}
910

@@ -24,10 +25,16 @@ impl Protocol {
2425
}
2526
}
2627

28+
#[inline]
29+
pub fn ok() -> Self {
30+
Protocol::SimpleString("ok".to_string())
31+
}
32+
2733
pub fn decode(self: &Self) -> String {
2834
match self {
2935
Protocol::SimpleString(s) => s.to_string(),
3036
Protocol::BulkString(s) => s.to_string(),
37+
Protocol::Null => "".to_string(),
3138
Protocol::Array(s) => s
3239
.into_iter()
3340
.map(|x| x.decode())
@@ -48,6 +55,7 @@ impl Protocol {
4855
.join("")
4956
.as_str()
5057
}
58+
Protocol::Null => "$-1\r\n".to_string(),
5159
}
5260
}
5361

src/server.rs

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use core::str;
2+
use std::sync::Arc;
3+
use std::sync::Mutex;
4+
use tokio::io::AsyncReadExt;
5+
use tokio::io::AsyncWriteExt;
6+
7+
use crate::cmd::Cmd;
8+
use crate::storage::Storage;
9+
10+
#[derive(Clone)]
11+
pub struct Server {
12+
storage: Arc<Mutex<Storage>>,
13+
}
14+
15+
impl Server {
16+
pub fn new() -> Self {
17+
Server {
18+
storage: Arc::new(Mutex::new(Storage::new())),
19+
}
20+
}
21+
22+
pub async fn handle(self: &mut Self, mut stream: tokio::net::TcpStream) {
23+
let mut buf = [0; 512];
24+
loop {
25+
if let Ok(len) = stream.read(&mut buf).await {
26+
if len == 0 {
27+
println!("[handle] connection closed");
28+
return;
29+
}
30+
let s = str::from_utf8(&buf[..len]).unwrap();
31+
let cmd = Cmd::from(s).unwrap();
32+
let res = cmd.run(&mut self.storage).unwrap();
33+
println!("going to send response {}", res.encode());
34+
stream.write_all(res.encode().as_bytes()).await.unwrap();
35+
println!("finish processing");
36+
} else {
37+
println!("[handle] going to break");
38+
break;
39+
}
40+
}
41+
}
42+
}

src/storage.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use std::collections::HashMap;
2+
3+
pub struct Storage {
4+
set: HashMap<String, String>,
5+
}
6+
7+
impl Storage {
8+
pub fn new() -> Self {
9+
Storage {
10+
set: HashMap::new(),
11+
}
12+
}
13+
14+
pub fn get(self: &Self, k: &str) -> Option<&String> {
15+
self.set.get(k)
16+
}
17+
18+
pub fn set(self: &mut Self, k: String, v: String) {
19+
self.set.insert(k, v);
20+
}
21+
}

0 commit comments

Comments
 (0)