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}