xref: /DragonReach/src/parse/parse_util/mod.rs (revision 4e851715e713d4b9f10926924b8a727bd7cc6cb3)
1 use crate::{
2     contants::{AF_INET, AF_INET6, IPV4_MIN_MTU, IPV6_MIN_MTU, PRIO_MAX, PRIO_MIN},
3     error::ParseError,
4     task::cmdtask::CmdTask,
5     unit::{Unit, Url},
6     FileDescriptor,
7 };
8 //use drstd::std;
9 use std::{format, fs, path::Path, rc::Rc, string::String, string::ToString, vec, vec::Vec};
10 
11 use super::{parse_service::ServiceParser, BASE_IEC, BASE_SI, SEC_UNIT_TABLE};
12 
13 #[derive(PartialEq)]
14 pub enum SizeBase {
15     IEC,
16     Si,
17 }
18 
19 pub struct UnitParseUtil;
20 
21 impl UnitParseUtil {
22     /// @brief 解析布尔值
23     ///
24     /// 将传入的字符串解析为布尔值
25     /// "yes","y","1","true","t","on"均可表示true
26     /// "no","n","0","false","f","off"均可表示false
27     ///
28     /// @param s 需解析的字符串
29     ///
30     /// @return 解析成功则返回Ok(解析后的值),否则返回Err
31     pub fn parse_boolean(s: &str) -> Result<bool, ParseError> {
32         let t_table: Vec<&str> = vec!["yes", "y", "1", "true", "t", "on"];
33         let f_table: Vec<&str> = vec!["no", "n", "0", "false", "f", "off"];
34 
35         if t_table.contains(&s) {
36             return Ok(true);
37         } else if f_table.contains(&s) {
38             return Ok(false);
39         }
40 
41         return Err(ParseError::EINVAL);
42     }
43 
44     /// @brief 解析pid
45     ///
46     /// 将传入的字符串解析为pid
47     ///
48     /// @param s 需解析的字符串
49     ///
50     /// @return 解析成功则返回Ok(解析后的值),否则返回Err
51     pub fn parse_pid(s: &str) -> Result<i32, ParseError> {
52         let s = s.trim();
53         //先使用u64变换
54         let pid_ul = match s.parse::<u64>() {
55             Ok(val) => val,
56             Err(_) => {
57                 return Err(ParseError::EINVAL);
58             }
59         };
60         let pid: i32 = pid_ul as i32;
61 
62         if (pid as u64) != pid_ul {
63             //如果在从pid_t转换为u64之后与之前不等,则说明发生了截断,返回错误
64             return Err(ParseError::ERANGE);
65         }
66 
67         if pid < 0 {
68             //pid小于0不合法
69             return Err(ParseError::EINVAL);
70         }
71 
72         return Ok(pid);
73     }
74 
75     /// @brief 解析pid
76     ///
77     /// 将传入的字符串解析为mode_t
78     ///
79     /// @param s 需解析的字符串
80     ///
81     /// @return 解析成功则返回Ok(解析后的值),否则返回Err
82     pub fn parse_mode(s: &str) -> Result<u32, ParseError> {
83         let s = s.trim();
84         let m = match u32::from_str_radix(s, 8) {
85             Ok(val) => val,
86             Err(_) => {
87                 return Err(ParseError::EINVAL);
88             }
89         };
90 
91         //如果模式大于权限的最大值则为非法权限,返回错误
92         if m > 0o7777 {
93             return Err(ParseError::ERANGE);
94         }
95 
96         return Ok(m);
97     }
98 
99     /// @brief 解析网络接口索引
100     ///
101     /// 将传入的字符串解析为网络接口索引具体值
102     ///
103     /// @param s 需解析的字符串
104     ///
105     /// @return 解析成功则返回Ok(解析后的值),否则返回Err
106     pub fn parse_ifindex(s: &str) -> Result<i32, ParseError> {
107         let s = s.trim();
108         let ret: i32 = match s.parse::<i32>() {
109             Ok(val) => val,
110             Err(_) => {
111                 return Err(ParseError::EINVAL);
112             }
113         };
114 
115         if ret <= 0 {
116             return Err(ParseError::EINVAL);
117         }
118 
119         return Ok(ret);
120     }
121 
122     /// @brief 解析最大传输单元(MTU)
123     ///
124     /// 将传入的字符串解析为具体值
125     ///
126     /// @param s 需解析的字符串
127     ///
128     /// @param family 网络地址族
129     ///
130     /// @return 解析成功则返回Ok(解析后的值),否则返回Err
131     pub fn parse_mtu(s: &str, family: i32) -> Result<u32, ParseError> {
132         let s = s.trim();
133         let mtu = match s.parse::<u64>() {
134             Ok(val) => val,
135             Err(_) => {
136                 //针对非法字符出错时
137                 return Err(ParseError::EINVAL);
138             }
139         };
140 
141         //针对数据溢出时的报错
142         if mtu > u32::MAX as u64 {
143             return Err(ParseError::ERANGE);
144         }
145 
146         let mtu: u32 = mtu as u32;
147 
148         let mut min_mtu: u32 = 0;
149         //判断mtu是否合法
150         if family == AF_INET6 {
151             min_mtu = IPV6_MIN_MTU;
152         } else if family == AF_INET {
153             min_mtu = IPV4_MIN_MTU;
154         } else {
155             return Err(ParseError::EINVAL);
156         }
157 
158         return Ok(mtu);
159     }
160 
161     /// @brief 解析Size
162     ///
163     /// 将传入的字符串解析为具体的字节数
164     /// 可支持IEC二进制后缀,也可支持SI十进制后缀
165     ///
166     /// @param s 需解析的字符串
167     ///
168     /// @param base 设置为IEC二进制后缀或者SI十进制后缀
169     ///
170     /// @return 解析成功则返回Ok(解析后的值),否则返回Err
171     pub fn parse_size(s: &str, base: SizeBase) -> Result<u64, ParseError> {
172         let s = s.trim();
173         //将s分解为数字和后缀部分
174         let (number_str, suffix) = match s.find(|c: char| !c.is_digit(10) && c != '.') {
175             Some(mid) => s.split_at(mid),
176             None => (s, ""),
177         };
178 
179         //获得数字部分的整数和小数部分
180         let (integer, fraction) = match number_str.find(".") {
181             Some(mid) => {
182                 let (integer, fraction) = number_str.split_at(mid);
183                 let integer = integer.parse::<u64>().unwrap();
184                 let fraction = match fraction[1..].parse::<u64>() {
185                     Ok(val) => val,
186                     Err(_) => {
187                         return Err(ParseError::EINVAL);
188                     }
189                 };
190                 (integer, fraction)
191             }
192             None => (number_str.parse::<u64>().unwrap(), 0),
193         };
194 
195         //从表中查找到后缀所对应的字节倍数
196         let mut factor: u64 = 0;
197         if base == SizeBase::IEC {
198             factor = match BASE_IEC.get(suffix) {
199                 Some(val) => *val,
200                 None => {
201                     return Err(ParseError::EINVAL);
202                 }
203             }
204         } else if base == SizeBase::Si {
205             factor = match BASE_SI.get(suffix) {
206                 Some(val) => *val,
207                 None => {
208                     return Err(ParseError::EINVAL);
209                 }
210             }
211         }
212 
213         Ok(integer * factor + (fraction * factor) / (10u64.pow(fraction.to_string().len() as u32)))
214     }
215 
216     /// @brief 解析扇区大小
217     ///
218     /// 将传入的字符串解析为具体的扇区大小
219     /// 若扇区大小小于512或者大于4096,将会返回错误,若扇区大小不为2的幂,返回错误。
220     ///
221     /// @param s 需解析的字符串
222     ///
223     /// @return 解析成功则返回Ok(解析后的值),否则返回Err
224     pub fn parse_sector_size(s: &str) -> Result<u64, ParseError> {
225         let s = s.trim();
226         let size: u64 = match s.parse::<u64>() {
227             Ok(val) => val,
228             Err(_) => {
229                 return Err(ParseError::EINVAL);
230             }
231         };
232 
233         if size < 512 || size > 4096 {
234             return Err(ParseError::ERANGE);
235         }
236 
237         //判断是否为2的幂,如果不是则报错
238         if (size & (size - 1)) != 0 {
239             return Err(ParseError::EINVAL);
240         }
241 
242         return Ok(size);
243     }
244 
245     /// @brief 解析范围
246     ///
247     /// 将传入的字符串解析为具体的范围
248     ///
249     /// @param s 需解析的字符串
250     ///
251     /// @return 解析成功则返回Ok(解析后的值),否则返回Err
252     pub fn parse_range(s: &str) -> Result<(u32, u32), ParseError> {
253         let mid = match s.find('-') {
254             Some(val) => val,
255             None => {
256                 //如果字符串中没有'-'符号,则表示一个值,所以范围两端都为该值
257                 let s = s.trim();
258                 let ret = match s.parse::<u32>() {
259                     Ok(val) => val,
260                     Err(_) => {
261                         return Err(ParseError::EINVAL);
262                     }
263                 };
264                 return Ok((ret, ret));
265             }
266         };
267 
268         //若字符串中存在'-',则分别解析为u32,解析失败则报错
269         let (l, r) = s.split_at(mid);
270 
271         let l = l.trim();
272         let l = match l.parse::<u32>() {
273             Ok(val) => val,
274             Err(_) => {
275                 return Err(ParseError::EINVAL);
276             }
277         };
278         let r = r.trim();
279         let r = match r.parse::<u32>() {
280             Ok(val) => val,
281             Err(_) => {
282                 return Err(ParseError::EINVAL);
283             }
284         };
285 
286         return Ok((l, r));
287     }
288 
289     /// @brief 解析文件描述符
290     ///
291     /// 将传入的字符串解析为文件描述符fd
292     ///
293     /// @param s 需解析的字符串
294     ///
295     /// @return 解析成功则返回Ok(解析后的值),否则返回Err
296     pub fn parse_fd(s: &str) -> Result<FileDescriptor, ParseError> {
297         let s = s.trim();
298         let fd = match s.parse::<i32>() {
299             Ok(val) => val,
300             Err(_) => {
301                 return Err(ParseError::EINVAL);
302             }
303         };
304 
305         if fd < 0 {
306             return Err(ParseError::EBADF);
307         }
308 
309         return Ok(FileDescriptor(fd as usize));
310     }
311 
312     /// @brief 解析nice
313     ///
314     /// 将传入的字符串解析为nice
315     ///
316     /// @param s 需解析的字符串
317     ///
318     /// @return 解析成功则返回Ok(解析后的值),否则返回Err
319     pub fn parse_nice(s: &str) -> Result<i8, ParseError> {
320         let s = s.trim();
321         let nice = match s.parse::<i8>() {
322             Ok(val) => val,
323             Err(_) => {
324                 return Err(ParseError::EINVAL);
325             }
326         };
327 
328         if nice > PRIO_MAX || nice < PRIO_MIN {
329             return Err(ParseError::ERANGE);
330         }
331 
332         return Ok(nice);
333     }
334 
335     /// @brief 解析端口号
336     ///
337     /// 将传入的字符串解析为端口号
338     ///
339     /// @param s 需解析的字符串
340     ///
341     /// @return 解析成功则返回Ok(解析后的值),否则返回Err
342     pub fn parse_ip_port(s: &str) -> Result<u16, ParseError> {
343         let s = s.trim();
344         let port = match s.parse::<u16>() {
345             Ok(val) => val,
346             Err(_) => {
347                 return Err(ParseError::EINVAL);
348             }
349         };
350 
351         if port == 0 {
352             return Err(ParseError::EINVAL);
353         }
354 
355         return Ok(port);
356     }
357 
358     /// @brief 解析端口范围
359     ///
360     /// 将传入的字符串解析为端口范围
361     ///
362     /// @param s 需解析的字符串
363     ///
364     /// @return 解析成功则返回Ok((u16,u16)),否则返回Err
365     pub fn parse_ip_port_range(s: &str) -> Result<(u16, u16), ParseError> {
366         let (l, h) = Self::parse_range(s)?;
367 
368         let l = l as u16;
369         let h = h as u16;
370         if l <= 0 || l >= 65535 || h <= 0 || h >= 65535 {
371             return Err(ParseError::EINVAL);
372         }
373 
374         return Ok((l, h));
375     }
376 
377     /// @brief 解析OOM(Out-of-Memory)分数调整值
378     ///
379     /// 将传入的字符串解析为OOM(Out-of-Memory)分数调整值
380     ///
381     /// @param s 需解析的字符串
382     ///
383     /// @return 解析成功则返回Ok(u32),否则返回Err
384     pub fn parse_ip_prefix_length(s: &str) -> Result<u32, ParseError> {
385         let len = match s.parse::<u32>() {
386             Ok(val) => val,
387             Err(_) => {
388                 return Err(ParseError::EINVAL);
389             }
390         };
391 
392         if len > 128 {
393             return Err(ParseError::ERANGE);
394         }
395 
396         return Ok(len);
397     }
398 
399     /// @brief 目前为简单的分割字符串,并未提供严谨的Url解析
400     ///
401     /// 将传入的字符串解析为Url结构体的Vec,若Url非法则返回错误
402     ///
403     /// @param s 需解析的字符串
404     ///
405     /// @return 解析成功则返回Ok(Url),否则返回Err
406     pub fn parse_url(s: &str) -> Result<Vec<Url>, ParseError> {
407         let mut url = Url::default();
408         let url_strs = s.split_whitespace().collect::<Vec<&str>>();
409         let mut urls = Vec::new();
410         for s in url_strs {
411             urls.push(Url {
412                 url_string: String::from(s),
413             })
414         }
415         return Ok(urls);
416     }
417 
418     /// @brief 将对应的str解析为对应Unit
419     ///
420     /// 将传入的字符串解析为Unit,解析失败返回错误
421     ///
422     /// @param path 需解析的文件
423     ///
424     /// @return 解析成功则返回Ok(Rc<dyn Unit>),否则返回Err
425     pub fn parse_unit<T: Unit>(path: &str) -> Result<Rc<T>, ParseError> {
426         return T::from_path(path);
427     }
428 
429     /// @brief 将对应的str解析为Rc<dyn Unit>
430     ///
431     /// 将传入的字符串解析为Rc<dyn Unit>,解析失败返回错误
432     ///
433     /// @param path 需解析的文件
434     ///
435     /// @return 解析成功则返回Ok(Rc<dyn Unit>),否则返回Err
436     pub fn parse_unit_no_type(path: &str) -> Result<Rc<dyn Unit>, ParseError> {
437         let idx = match path.rfind('.') {
438             Some(val) => val,
439             None => {
440                 return Err(ParseError::EINVAL);
441             }
442         };
443 
444         if idx == path.len() - 1 {
445             //处理非法文件xxxx. 类型
446             return Err(ParseError::EINVAL);
447         }
448 
449         let suffix = &path[idx + 1..];
450 
451         //通过文件后缀分发给不同类型的Unit解析器解析
452         let unit = match suffix {
453             "service" => ServiceParser::parse(path)?,
454             _ => {
455                 return Err(ParseError::EINVAL);
456             }
457         };
458 
459         return Ok(unit);
460     }
461 
462     /// @brief 将对应的str解析为对应CmdTask
463     ///
464     /// 将传入的字符串解析为CmdTask组,解析失败返回错误
465     ///
466     /// @param path 需解析的文件
467     ///
468     /// @return 解析成功则返回Ok(Vec<CmdTask>>),否则返回Err
469     pub fn parse_cmd_task(s: &str) -> Result<Vec<CmdTask>, ParseError> {
470         //分拆成单词Vec
471         let cmds = s.split_whitespace().collect::<Vec<&str>>();
472         let mut tasks = Vec::new();
473         let mut i = 0;
474         while i < cmds.len() {
475             let mut cmd_task = CmdTask {
476                 path: String::new(),
477                 cmd: String::new(),
478                 ignore: false,
479             };
480             //匹配到这里时,这个单词肯定是路径,若路径以-开头则设置ignore
481             cmd_task.ignore = cmds[i].starts_with('-');
482 
483             //获取到一个CmdTask的路径部分
484             let mut path = "";
485             if cmd_task.ignore {
486                 path = &cmds[i][1..];
487             } else {
488                 path = &cmds[i];
489             }
490 
491             //得到的非绝对路径则不符合语法要求,报错
492             if !UnitParseUtil::is_absolute_path(path) {
493                 return Err(ParseError::EINVAL);
494             }
495 
496             cmd_task.path = String::from(path);
497 
498             //i += 1,继续匹配下一个单词
499             i += 1;
500             let mut cmd_str = String::new();
501             while i < cmds.len() && !UnitParseUtil::is_absolute_path(cmds[i]) {
502                 //命令可能会有多个单词,将多个命令整理成一个
503                 let cmd = cmds[i];
504                 cmd_str = format!("{} {}", cmd_str, cmd);
505                 i += 1;
506             }
507             cmd_task.cmd = cmd_str;
508             tasks.push(cmd_task);
509             //经过while到这里之后,cmds[i]对应的单词一点是路径,i不需要加一
510         }
511         return Ok(tasks);
512     }
513 
514     /// @brief 判断是否为绝对路径
515     ///
516     /// @param path 路径
517     ///
518     /// @return 解析成功则返回true,否则返回false
519     pub fn is_absolute_path(path: &str) -> bool {
520         let path = Path::new(path);
521         path.is_absolute()
522     }
523 
524     /// @brief 将对应的str解析为us(微秒)
525     ///
526     /// 将传入的字符串解析为秒数,解析失败返回错误
527     ///
528     /// @param path 需解析的文件
529     ///
530     /// @return 解析成功则返回Ok(u64),否则返回Err
531     pub fn parse_sec(s: &str) -> Result<u64, ParseError> {
532         //下列参数分别记录整数部分,小数部分以及单位
533         let mut integer: u64 = 0;
534         let mut frac: u64 = 0;
535         let mut unit: &str = "";
536 
537         match s.find('.') {
538             Some(idx) => {
539                 //解析整数部分
540                 integer = match s[..idx].parse::<u64>() {
541                     Ok(val) => val,
542                     Err(_) => return Err(ParseError::EINVAL),
543                 };
544                 //获得小数+单位的字符串
545                 let frac_and_unit = &s[(idx + 1)..];
546                 match frac_and_unit.find(|c: char| !c.is_digit(10)) {
547                     Some(val) => {
548                         //匹配小数部分
549                         frac = match frac_and_unit[..val].parse::<u64>() {
550                             Ok(val) => val,
551                             Err(_) => return Err(ParseError::EINVAL),
552                         };
553                         //单位部分
554                         unit = &frac_and_unit[val..];
555                     }
556                     None => {
557                         //没有单位的情况,直接匹配小数
558                         frac = match frac_and_unit.parse::<u64>() {
559                             Ok(val) => val,
560                             Err(_) => return Err(ParseError::EINVAL),
561                         };
562                         unit = "";
563                     }
564                 };
565             }
566             None => {
567                 //没有小数点则直接匹配整数部分和单位部分
568                 match s.find(|c: char| !c.is_digit(10)) {
569                     Some(idx) => {
570                         integer = match s[..idx].parse::<u64>() {
571                             Ok(val) => val,
572                             Err(_) => return Err(ParseError::EINVAL),
573                         };
574                         unit = &s[idx..];
575                     }
576                     None => {
577                         integer = match s.parse::<u64>() {
578                             Ok(val) => val,
579                             Err(_) => return Err(ParseError::EINVAL),
580                         };
581                         unit = "";
582                     }
583                 };
584             }
585         };
586 
587         //从时间单位转换表中获取到单位转换为ns的倍数
588         let factor = match SEC_UNIT_TABLE.get(unit) {
589             Some(val) => val,
590             None => {
591                 return Err(ParseError::EINVAL);
592             }
593         };
594 
595         //计算ns
596         return Ok(integer * factor + (frac * factor) / (10u64.pow(frac.to_string().len() as u32)));
597     }
598 
599     /// @brief 判断对应路径是否为目录
600     ///
601     /// @param path 路径
602     ///
603     /// @return true/false
604     pub fn is_dir(path: &str) -> bool {
605         if let Ok(metadata) = fs::metadata(path) {
606             if metadata.is_dir() {
607                 return true;
608             }
609             return false;
610         }
611         return false;
612     }
613 }
614