rust_cache_server/
command.rs1use std::sync::Arc;
2use std::time::Duration;
3
4use crate::protocol::RespFrame;
5use crate::store::Store;
6
7pub async fn handle_command(store: Arc<Store>, frame: RespFrame) -> RespFrame {
8 let RespFrame::Array(Some(items)) = frame else {
9 return RespFrame::Error("ERR protocol error".into());
10 };
11
12 if items.is_empty() {
13 return RespFrame::Error("ERR empty command".into());
14 }
15
16 let cmd_name = match &items[0] {
17 RespFrame::BulkString(Some(b)) => String::from_utf8_lossy(b).to_ascii_uppercase(),
18 RespFrame::SimpleString(s) => s.to_ascii_uppercase(),
19 _ => return RespFrame::Error("ERR invalid command".into()),
20 };
21
22 match cmd_name.as_str() {
23 "PING" => RespFrame::SimpleString("PONG".into()),
24
25 "INFO" => {
26 let info = "redis_version:rust-cache-0.1.0\r\nrole:master\r\n";
29 RespFrame::BulkString(Some(info.as_bytes().to_vec()))
30 }
31
32 "GET" => {
33 if items.len() != 2 {
34 return RespFrame::Error("ERR wrong number of arguments for 'get' command".into());
35 }
36 let key = bulk_to_string(&items[1]);
37 match key {
38 None => RespFrame::Error("ERR invalid key".into()),
39 Some(k) => match store.get(&k) {
40 Some(v) => RespFrame::BulkString(Some(v)),
41 None => RespFrame::BulkString(None),
42 },
43 }
44 }
45
46 "SET" => {
47 if items.len() < 3 {
48 return RespFrame::Error("ERR wrong number of arguments for 'set' command".into());
49 }
50 let key = match bulk_to_string(&items[1]) {
51 Some(k) => k,
52 None => return RespFrame::Error("ERR invalid key".into()),
53 };
54 let val = match &items[2] {
55 RespFrame::BulkString(Some(b)) => b.clone(),
56 RespFrame::SimpleString(s) => s.clone().into_bytes(),
57 _ => return RespFrame::Error("ERR invalid value".into()),
58 };
59
60 let mut ttl: Option<Duration> = None;
62 if items.len() >= 5 {
63 if let RespFrame::BulkString(Some(flag)) = &items[3] {
64 if flag.eq_ignore_ascii_case(b"EX") {
65 if let RespFrame::BulkString(Some(sec_bytes)) = &items[4] {
66 if let Ok(sec_str) = std::str::from_utf8(sec_bytes) {
67 if let Ok(sec) = sec_str.parse::<u64>() {
68 ttl = Some(Duration::from_secs(sec));
69 }
70 }
71 }
72 }
73 }
74 }
75
76 match store.set(key, val, ttl) {
77 Ok(()) => RespFrame::SimpleString("OK".into()),
78 Err(()) => RespFrame::Error("ERR memory limit reached".into()),
79 }
80 }
81
82 "DEL" => {
83 if items.len() < 2 {
84 return RespFrame::Error("ERR wrong number of arguments for 'del' command".into());
85 }
86 let mut keys = Vec::with_capacity(items.len() - 1);
87 for it in &items[1..] {
88 if let Some(k) = bulk_to_string(it) {
89 keys.push(k);
90 }
91 }
92 let removed = store.del(&keys);
93 RespFrame::Integer(removed as i64)
94 }
95
96 "EXPIRE" => {
97 if items.len() != 3 {
98 return RespFrame::Error(
99 "ERR wrong number of arguments for 'expire' command".into(),
100 );
101 }
102 let key = match bulk_to_string(&items[1]) {
103 Some(k) => k,
104 None => return RespFrame::Error("ERR invalid key".into()),
105 };
106 let seconds = match &items[2] {
107 RespFrame::BulkString(Some(b)) => match std::str::from_utf8(b) {
108 Ok(s) => match s.parse::<u64>() {
109 Ok(v) => v,
110 Err(_) => return RespFrame::Error("ERR value is not an integer".into()),
111 },
112 Err(_) => return RespFrame::Error("ERR value is not an integer".into()),
113 },
114 _ => return RespFrame::Error("ERR value is not an integer".into()),
115 };
116
117 let ok = store.expire(&key, Duration::from_secs(seconds));
118 RespFrame::Integer(if ok { 1 } else { 0 })
119 }
120
121 "TTL" => {
122 if items.len() != 2 {
123 return RespFrame::Error("ERR wrong number of arguments for 'ttl' command".into());
124 }
125 let key = match bulk_to_string(&items[1]) {
126 Some(k) => k,
127 None => return RespFrame::Error("ERR invalid key".into()),
128 };
129 match store.ttl(&key) {
130 Some(d) => RespFrame::Integer(d.as_secs() as i64),
131 None => RespFrame::Integer(-2),
132 }
133 }
134
135 "KEYS" => {
136 if items.len() != 2 {
137 return RespFrame::Error("ERR wrong number of arguments for 'keys' command".into());
138 }
139 let pattern = match bulk_to_string(&items[1]) {
140 Some(p) => p,
141 None => return RespFrame::Error("ERR invalid pattern".into()),
142 };
143
144 let all_keys = store.keys();
145 let matched: Vec<RespFrame> = all_keys
146 .into_iter()
147 .filter(|k| pattern_match(&pattern, k))
148 .map(|k| RespFrame::BulkString(Some(k.into_bytes())))
149 .collect();
150
151 RespFrame::Array(Some(matched))
152 }
153
154 "FLUSHALL" | "CLEARALL" => {
155 if items.len() != 1 {
156 return RespFrame::Error(
157 "ERR wrong number of arguments for 'flushall' command".into(),
158 );
159 }
160 store.clear_all();
161 RespFrame::SimpleString("OK".into())
162 }
163
164 "INCR" => {
165 if items.len() != 2 {
166 return RespFrame::Error("ERR wrong number of arguments for 'incr' command".into());
167 }
168 let key = match bulk_to_string(&items[1]) {
169 Some(k) => k,
170 None => return RespFrame::Error("ERR invalid key".into()),
171 };
172 match store.incr_by(&key, 1, true) {
173 Some(val) => RespFrame::Integer(val),
174 None => RespFrame::Error("ERR value is not an integer or out of range".into()),
175 }
176 }
177
178 "DECR" => {
179 if items.len() != 2 {
180 return RespFrame::Error("ERR wrong number of arguments for 'decr' command".into());
181 }
182 let key = match bulk_to_string(&items[1]) {
183 Some(k) => k,
184 None => return RespFrame::Error("ERR invalid key".into()),
185 };
186 match store.incr_by(&key, -1, true) {
187 Some(val) => RespFrame::Integer(val),
188 None => RespFrame::Error("ERR value is not an integer or out of range".into()),
189 }
190 }
191
192 "INCRBY" => {
193 if items.len() != 3 {
194 return RespFrame::Error(
195 "ERR wrong number of arguments for 'incrby' command".into(),
196 );
197 }
198 let key = match bulk_to_string(&items[1]) {
199 Some(k) => k,
200 None => return RespFrame::Error("ERR invalid key".into()),
201 };
202 let increment = match &items[2] {
203 RespFrame::BulkString(Some(b)) => match std::str::from_utf8(b) {
204 Ok(s) => match s.parse::<i64>() {
205 Ok(v) => v,
206 Err(_) => {
207 return RespFrame::Error("ERR value is not an integer".into());
208 }
209 },
210 Err(_) => return RespFrame::Error("ERR value is not an integer".into()),
211 },
212 _ => return RespFrame::Error("ERR value is not an integer".into()),
213 };
214 match store.incr_by(&key, increment, true) {
215 Some(val) => RespFrame::Integer(val),
216 None => RespFrame::Error("ERR value is not an integer or out of range".into()),
217 }
218 }
219
220 "DECRBY" => {
221 if items.len() != 3 {
222 return RespFrame::Error(
223 "ERR wrong number of arguments for 'decrby' command".into(),
224 );
225 }
226 let key = match bulk_to_string(&items[1]) {
227 Some(k) => k,
228 None => return RespFrame::Error("ERR invalid key".into()),
229 };
230 let decrement = match &items[2] {
231 RespFrame::BulkString(Some(b)) => match std::str::from_utf8(b) {
232 Ok(s) => match s.parse::<i64>() {
233 Ok(v) => v,
234 Err(_) => {
235 return RespFrame::Error("ERR value is not an integer".into());
236 }
237 },
238 Err(_) => return RespFrame::Error("ERR value is not an integer".into()),
239 },
240 _ => return RespFrame::Error("ERR value is not an integer".into()),
241 };
242 match store.incr_by(&key, -decrement, true) {
243 Some(val) => RespFrame::Integer(val),
244 None => RespFrame::Error("ERR value is not an integer or out of range".into()),
245 }
246 }
247
248 _ => RespFrame::Error(format!("ERR unknown command '{cmd_name}'")),
249 }
250}
251
252fn bulk_to_string(frame: &RespFrame) -> Option<String> {
253 match frame {
254 RespFrame::BulkString(Some(b)) => String::from_utf8(b.clone()).ok(),
255 RespFrame::SimpleString(s) => Some(s.clone()),
256 _ => None,
257 }
258}
259
260fn pattern_match(pattern: &str, text: &str) -> bool {
261 if pattern == "*" {
263 return true;
264 }
265
266 let mut p_iter = pattern.chars().peekable();
267 let mut t_iter = text.chars().peekable();
268
269 let mut star: Option<(usize, usize)> = None;
270 let pattern_chars: Vec<char> = pattern.chars().collect();
271 let text_chars: Vec<char> = text.chars().collect();
272 let (mut i, mut j) = (0usize, 0usize);
273
274 while j < text_chars.len() {
275 if i < pattern_chars.len()
276 && (pattern_chars[i] == '?' || pattern_chars[i] == text_chars[j])
277 {
278 i += 1;
279 j += 1;
280 } else if i < pattern_chars.len() && pattern_chars[i] == '*' {
281 star = Some((i, j));
282 i += 1;
283 } else if let Some((si, sj)) = star {
284 i = si + 1;
285 j = sj + 1;
286 star = Some((si, j));
287 } else {
288 return false;
289 }
290 }
291
292 while i < pattern_chars.len() && pattern_chars[i] == '*' {
293 i += 1;
294 }
295
296 i == pattern_chars.len()
297}
298
299