rudis_http/command/
mod.rs

1mod get;
2
3pub use get::Get;
4
5mod set;
6use httparse::Request;
7use serde_json::{Map, Result, Value};
8pub use set::{MultipleSet, Set};
9
10pub enum Command {
11    Set(Set),
12    Get(Get),
13    MultipleSet(MultipleSet),
14    Invalid,
15}
16
17#[derive(Debug)]
18struct Args {
19    valid: bool,
20    command: String,
21    key: String,
22    val: Option<String>,
23    kv: Option<Map<String, Value>>,
24}
25
26impl Args {
27    pub fn new_invalid(command_type: &str) -> Self {
28        Args {
29            valid: false,
30            command: String::from(command_type),
31            key: String::from(""),
32            val: None,
33            kv: None,
34        }
35    }
36}
37
38impl Command {
39    pub fn from_bytes(http_request_buff: &[u8]) -> Command {
40        if http_request_buff.len() == 0 {
41            return Command::Invalid;
42        }
43
44        let mut headers = [httparse::EMPTY_HEADER; 16];
45        let mut req = Request::new(&mut headers);
46        let result = req.parse(http_request_buff).unwrap();
47        let n = result.unwrap();
48
49        let arg = make_args(&req, http_request_buff, n);
50
51        match arg.command.as_str() {
52            "GET" => {
53                if arg.valid == false {
54                    return Command::Get(Get::new_invalid());
55                }
56                Command::Get(Get::from_key(arg.key))
57            }
58            "SET" => {
59                if arg.valid == false {
60                    return Command::Set(Set::new_invalid());
61                }
62                Command::Set(Set::from_key_val(arg.key, arg.val.unwrap()))
63            }
64            "MULTIPLE_SET" => {
65                if arg.valid == false {
66                    return Command::MultipleSet(MultipleSet::new_invalid());
67                }
68                let json_kv = arg.kv.unwrap();
69                if let Some(arg) = MultipleSet::from_json_kv(json_kv) {
70                    return Command::MultipleSet(arg);
71                } else {
72                    return Command::MultipleSet(MultipleSet::new_invalid());
73                }
74            }
75            _ => Command::Invalid,
76        }
77    }
78}
79
80fn make_args(req: &Request, request_buff: &[u8], idx_of_body: usize) -> Args {
81    let method = req.method.unwrap();
82    let all_path_vec = split_on_path(req.path.unwrap());
83
84    // using regular GET request (pass data through URL)
85    if method == "GET" {
86        let action = all_path_vec[0];
87        match action.to_uppercase().as_str() {
88            "GET" => {
89                if all_path_vec.len() < 2 || all_path_vec[1].is_empty() || all_path_vec.len() > 2 {
90                    return Args::new_invalid("GET");
91                }
92                let key = all_path_vec[1];
93                return Args {
94                    valid: true,
95                    command: String::from("GET"),
96                    key: String::from(key),
97                    val: None,
98                    kv: None,
99                };
100            }
101            "SET" => {
102                if all_path_vec.len() < 3
103                    || all_path_vec[1].is_empty()
104                    || all_path_vec[2].is_empty()
105                    || all_path_vec.len() > 3
106                {
107                    return Args::new_invalid("SET");
108                }
109                let key = all_path_vec[1];
110                let val = all_path_vec[2];
111                return Args {
112                    valid: true,
113                    command: String::from("SET"),
114                    key: String::from(key),
115                    val: Some(String::from(val)),
116                    kv: None,
117                };
118            }
119            _ => return Args::new_invalid("INVALID"),
120        }
121    } else if method == "POST" {
122        // using POST request (SET ONLY) that passes kv-pair through body
123        if all_path_vec.len() != 1 {
124            return Args::new_invalid("SET");
125        }
126        let body = request_buff[idx_of_body..].to_vec();
127        match parse_json(&body) {
128            Ok(value) => {
129                if let Some(obj) = value.as_object() {
130                    return Args {
131                        valid: true,
132                        command: String::from("MULTIPLE_SET"),
133                        key: String::from(""),
134                        val: None,
135                        kv: Some(obj.clone()),
136                    };
137                }
138                return Args::new_invalid("SET");
139            }
140            Err(_) => return Args::new_invalid("SET"),
141        }
142    }
143    Args::new_invalid("INVALID")
144}
145
146fn split_on_path(input: &str) -> Vec<&str> {
147    let all: Vec<&str> = input.split("/").collect();
148    if let Some((_, rest)) = all.split_first() {
149        return rest.to_vec();
150    }
151    all
152}
153
154fn parse_json(bytes: &[u8]) -> Result<Value> {
155    let value = serde_json::from_slice(bytes)?;
156    Ok(value)
157}