inn_common/
cli.rs

1//-------------------------------------------------------------------
2// MIT License
3// Copyright (c) 2022 black-mongo
4// @author CameronYang
5// @doc
6//  inn_cli tool using RESP(https://redis.io/docs/reference/protocol-spec/) to communication
7//
8// @end
9// Created : 2022-04-18T23:22:42+08:00
10//-------------------------------------------------------------------
11use log::error;
12use std::cmp::Ordering;
13#[derive(Debug, Clone, PartialEq)]
14pub enum Cli {
15    // +OK\r\n
16    SimpleString(String),
17    // -Error Message\r\n
18    Errors(String),
19    // :10\r\n
20    Integers(i64),
21    // $6\r\nhello\r\n
22    // An empty string
23    // $0\r\n\r\n
24    BulkString(String),
25    // "$-1\r\n"
26    NullBulkString,
27    // *-1\r\n
28    NullArrays,
29    // An empty arrays
30    // "*0\r\n"
31    // [1,2,3,4,hello]
32    // *5\r\n
33    // :1\r\n
34    // :2\r\n
35    // :3\r\n
36    // :4\r\n
37    // $5\r\n
38    // hello\r\n
39    Arrays(Vec<Cli>),
40}
41impl Cli {
42    fn parse(org: &str) -> (Cli, &str) {
43        let mut str = org.splitn(2, "\r\n");
44        let first = str.next();
45        let second = str.next();
46        if let Some(first) = first {
47            match first.as_bytes()[0] {
48                b'+' => (Cli::SimpleString(first[1..].into()), second.unwrap_or("")),
49                b'-' => (Cli::Errors(first[1..].into()), second.unwrap_or("")),
50                b':' => {
51                    let i = &first[1..];
52                    (
53                        Cli::Integers(i.parse::<i64>().unwrap_or(0)),
54                        second.unwrap_or(""),
55                    )
56                }
57                b'$' => {
58                    let len = &first[1..];
59                    let len: i64 = len.parse::<i64>().unwrap_or(-10);
60                    match len.cmp(&-1) {
61                        Ordering::Equal => (Cli::NullBulkString, second.unwrap_or("")),
62                        Ordering::Less => {
63                            error!("Cli parse Bulk String Invalid len = {}, str = {}", len, org);
64                            (Cli::NullBulkString, "")
65                        }
66                        Ordering::Greater => {
67                            let second = second.unwrap_or("");
68                            let second_len = second.len();
69                            let len = len as usize;
70                            if len > second_len || len + 2 > second_len {
71                                error!(
72                                    "Cli parse Bulk String Invalid len = {}, str = {}",
73                                    len, org
74                                );
75                                (Cli::NullBulkString, "")
76                            } else {
77                                (
78                                    Cli::BulkString(second[..len as usize].into()),
79                                    second[len as usize + 2..].into(),
80                                )
81                            }
82                        }
83                    }
84                }
85                b'*' => {
86                    let len = &first[1..];
87                    let len: i64 = len.parse::<i64>().unwrap_or(-10);
88                    match len.cmp(&-1) {
89                        Ordering::Equal => (Cli::NullArrays, second.unwrap_or("")),
90                        Ordering::Less => {
91                            error!("Cli parse Arrays Invalid len = {}, str = {}", len, org);
92                            (Cli::NullArrays, "")
93                        }
94                        Ordering::Greater => {
95                            let mut arrays = vec![];
96                            let mut remain = second.unwrap_or("");
97                            for _i in 0..len {
98                                if !remain.is_empty() {
99                                    let (cli, other) = Cli::parse(remain);
100                                    remain = other;
101                                    arrays.push(cli);
102                                }
103                            }
104                            (Cli::Arrays(arrays), remain)
105                        }
106                    }
107                }
108                _ => {
109                    error!("Cli parse Invalid {}", org);
110                    (Cli::NullArrays, "")
111                }
112            }
113        } else {
114            error!("Cli parse Invalid {}", org);
115            (Cli::NullArrays, "")
116        }
117    }
118}
119impl From<String> for Cli {
120    fn from(str: String) -> Self {
121        let (cli, _) = Cli::parse(&str);
122        cli
123    }
124}
125impl From<Cli> for String {
126    fn from(cli: Cli) -> Self {
127        match cli {
128            Cli::SimpleString(simple) => format!("+{}\r\n", simple),
129            Cli::Errors(errors) => format!("-{}\r\n", errors),
130            Cli::Integers(int) => format!(":{}\r\n", int),
131            Cli::BulkString(bulk) => format!("${}\r\n{}\r\n", bulk.len(), bulk),
132            Cli::NullBulkString => "$-1\r\n".into(),
133            Cli::NullArrays => "*-1\r\n".into(),
134            Cli::Arrays(arrays) if arrays.is_empty() => "*0\r\n".into(),
135            Cli::Arrays(arrays) => {
136                let mut rs = format!("*{}\r\n", arrays.len());
137                for row in arrays {
138                    let str: String = row.into();
139                    rs += &str;
140                }
141                rs
142            }
143        }
144    }
145}
146impl From<Vec<u8>> for Cli {
147    fn from(bytes: Vec<u8>) -> Self {
148        if let Ok(str) = String::from_utf8(bytes) {
149            str.into()
150        } else {
151            error!("Cli Bytes to String error invalid utf8");
152            Cli::NullArrays
153        }
154    }
155}
156impl From<Cli> for Vec<u8> {
157    fn from(cli: Cli) -> Self {
158        let str: String = cli.into();
159        str.into_bytes()
160    }
161}
162
163impl From<Cli> for Vec<String> {
164    fn from(msg: Cli) -> Self {
165        let mut rs: Vec<String> = vec![];
166        match msg {
167            Cli::Arrays(list) => {
168                for i in list {
169                    match i {
170                        Cli::SimpleString(ss) | Cli::BulkString(ss) | Cli::Errors(ss) => {
171                            rs.push(ss);
172                        }
173                        Cli::Integers(int) => {
174                            rs.push(int.to_string());
175                        }
176                        _ => {}
177                    }
178                }
179            }
180            Cli::SimpleString(ss) | Cli::BulkString(ss) | Cli::Errors(ss) => {
181                rs.push(ss);
182            }
183            Cli::Integers(int) => {
184                rs.push(int.to_string());
185            }
186            _ => {}
187        }
188        rs
189    }
190}
191impl From<Vec<String>> for Cli {
192    fn from(msg: Vec<String>) -> Self {
193        let mut rs = vec![];
194        for str in msg {
195            rs.push(Cli::BulkString(str));
196        }
197        Cli::Arrays(rs)
198    }
199}