next_web_utils/common/
command.rs

1use std::{
2    io::{BufRead, BufReader, Error, ErrorKind},
3    process::{Command, Stdio},
4};
5
6use std::sync::mpsc::Sender;
7
8///Command utility for executing system commands
9/// 系统命令执行工具类
10#[derive(Debug)]
11pub struct CommandUtil;
12
13/// 运行命令工具类
14impl CommandUtil {
15    //! 运行命令 例如 linux shell 命令
16    /// Execute system command and return output
17    /// 执行系统命令并返回输出
18    ///
19    /// # Arguments
20    /// - `program`: Command name (e.g. "ls")
21    /// - `args`: Command arguments vector
22    ///
23    /// # Returns
24    /// - Ok(String): Command output
25    /// - Err(Error): Execution failure
26    pub fn exec(program: &str, args: Vec<&str>) -> Result<String, Error> {
27        // run the ls command
28
29        let output = Command::new(program).args(args).output()?;
30
31        if !output.status.success() {
32            return Err(std::io::Error::new(
33                std::io::ErrorKind::Other,
34                "Command failed",
35            ));
36        }
37
38        Ok(String::from_utf8_lossy(&output.stdout).into_owned())
39    }
40
41    /// Execute command from string format
42    /// 从字符串格式执行命令
43    ///
44    /// Example:
45    /// ```
46    /// CommandUtil::exec_from_str("ls -l")
47    /// ```
48    pub fn exec_from_str(command: &str) -> Result<String, Error> {
49        let mut args = command.split_whitespace();
50        let program = args.next().unwrap_or("");
51        let args: Vec<&str> = args.collect::<Vec<&str>>();
52        return Self::exec(program, args);
53    }
54
55    /// Execute command with fallback function
56    /// 带后备函数的命令执行
57    ///
58    /// # Parameters
59    /// - `fallback`: Function to call when command fails
60    pub fn exec_and_fallback<F>(command: &str, fallback: F) -> Result<String, Error>
61    where
62        F: FnOnce(),
63    {
64        match Self::exec_from_str(command) {
65            Ok(s) => Ok(s),
66            Err(e) => {
67                fallback();
68                Err(e)
69            }
70        }
71    }
72
73    /// 执行命令并将持续输出通过通道发送。
74    ///
75    /// # 参数
76    /// - `command`: 要执行的命令字符串。
77    /// - `sender`: 一个 `Sender<String>`,用于发送命令的输出。
78    /// - `block`: 是否阻塞当前线程以等待命令完成。
79    ///
80    /// # 返回值
81    /// 如果命令执行成功,则返回 `Ok(())`;否则返回错误 <button class="citation-flag" data-index="1">。
82    /// Execute command and stream output through channel
83    /// 执行命令并通过通道流式传输输出
84    ///
85    /// # Parameters
86    /// - `command`: Full command string
87    /// - `sender`: Channel sender for output lines
88    /// - `block`: Block thread until completion
89    ///
90    /// # Channel Behavior
91    /// - Sends output line by line
92    /// - Closes channel when command completes
93    pub fn exec_to_channel(
94        command: &str,
95        sender: Sender<String>,
96        block: bool,
97    ) -> Result<(), Error> {
98        // 分割命令字符串为程序名和参数
99        let mut args = command.split_whitespace();
100        let program = args.next().unwrap_or("");
101        let args: Vec<&str> = args.collect();
102
103        // 启动子进程并捕获标准输出
104        let mut child = Command::new(program)
105            .args(args)
106            .stdout(Stdio::piped()) // 捕获标准输出
107            .spawn()?;
108
109        // 获取子进程的标准输出流
110        let stdout = child.stdout.take().ok_or_else(|| {
111            Error::new(
112                ErrorKind::Other,
113                "Unable to obtain the standard output of the child process",
114            )
115        })?;
116
117        // 使用缓冲区逐行读取子进程的输出
118        let mut reader = BufReader::new(stdout);
119
120        let mut func = move || -> Result<(), Error> {
121            loop {
122                let mut buffer = String::new();
123                let bytes_read = reader.read_line(&mut buffer)?; // 读取一行输出
124                if bytes_read == 0 {
125                    break; // 子进程输出结束
126                }
127
128                // 将读取到的内容通过通道发送
129                if sender.send(buffer.clone()).is_err() {
130                    break; // 如果发送失败,退出循环
131                }
132            }
133
134            // 等待子进程结束
135            let _ = child.wait()?;
136            Ok(())
137        };
138
139        if block {
140            func() // 阻塞模式下直接运行
141        } else {
142            std::thread::spawn(func); // 非阻塞模式下在新线程中运行
143            Ok(())
144        }
145    }
146}