Skip to main content

xtap_core_lib/shell/
dispatch.rs

1/*
2 * shell/dispatch.rs
3 * Project: core_lib
4 * Description: argv → 运行模式的纯解析路由(无外部依赖)
5 *
6 * 规则:
7 * - 第一个参数为 `serve`  → Mode::Serve,支持 --host / --port 覆盖默认值
8 * - 第一个参数为 `gui`    → Mode::Gui(仅 `gui` feature 下存在该分支)
9 * - 其余                   → Mode::Command(原样透传,交给 app 的命令处理器)
10 */
11
12use super::Mode;
13
14/// serve 模式默认监听地址。
15pub const DEFAULT_HOST: &str = "127.0.0.1";
16/// serve 模式默认端口。
17pub const DEFAULT_PORT: u16 = 9876;
18
19/// 把去掉 argv[0] 后的参数解析成运行 [`Mode`]。
20pub fn parse(args: &[String]) -> Mode {
21    match args.first().map(String::as_str) {
22        Some("serve") => parse_serve(&args[1..]),
23        #[cfg(feature = "gui")]
24        Some("gui") => Mode::Gui,
25        _ => Mode::Command(args.to_vec()),
26    }
27}
28
29fn parse_serve(rest: &[String]) -> Mode {
30    let mut host = DEFAULT_HOST.to_string();
31    let mut port = DEFAULT_PORT;
32    let mut i = 0;
33    while i < rest.len() {
34        match rest[i].as_str() {
35            "--host" => {
36                if let Some(v) = rest.get(i + 1) {
37                    host = v.clone();
38                    i += 1;
39                }
40            }
41            "--port" => {
42                if let Some(v) = rest.get(i + 1) {
43                    if let Ok(p) = v.parse::<u16>() {
44                        port = p;
45                    }
46                    i += 1;
47                }
48            }
49            _ => {}
50        }
51        i += 1;
52    }
53    Mode::Serve { host, port }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    fn v(items: &[&str]) -> Vec<String> {
61        items.iter().map(|s| s.to_string()).collect()
62    }
63
64    #[test]
65    fn serve_defaults() {
66        match parse(&v(&["serve"])) {
67            Mode::Serve { host, port } => {
68                assert_eq!(host, DEFAULT_HOST);
69                assert_eq!(port, DEFAULT_PORT);
70            }
71            _ => panic!("expected Serve"),
72        }
73    }
74
75    #[test]
76    fn serve_overrides() {
77        match parse(&v(&["serve", "--host", "0.0.0.0", "--port", "8080"])) {
78            Mode::Serve { host, port } => {
79                assert_eq!(host, "0.0.0.0");
80                assert_eq!(port, 8080);
81            }
82            _ => panic!("expected Serve"),
83        }
84    }
85
86    #[test]
87    fn command_passthrough() {
88        match parse(&v(&["search", "foo", "-t", "3"])) {
89            Mode::Command(argv) => assert_eq!(argv, v(&["search", "foo", "-t", "3"])),
90            _ => panic!("expected Command"),
91        }
92    }
93
94    #[test]
95    fn empty_is_command() {
96        match parse(&v(&[])) {
97            Mode::Command(argv) => assert!(argv.is_empty()),
98            _ => panic!("expected Command"),
99        }
100    }
101}