1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use std::future::Future;
use std::path::Path;
use std::process::Child;
use std::process::Stdio;

use tokio::io::{AsyncBufReadExt, BufReader}; // 确保导入所需的trait
use tokio::process::Command;
pub trait ADBCmdTrait {
    fn new(cmd: String, is_shell: bool) -> Self;
    fn create_cmd(self) -> Command;
    async fn run_async<F>(&self, args: Vec<String>, fnc: F)
    where
        F: FnMut(String) -> String + 'static;
    fn run(&self, args: Vec<String>) -> Result<String, String>;
    fn get_var_arg(self, args: Vec<String>) -> impl Future<Output = bool>;
    fn get_file_path(path: &str) -> Result<String, String>;
}

/// ADBCmd allows you to execute adb commands asynchronously.
#[derive(Debug, Clone)]
pub struct ADBCmd {
    cmd: String,
    is_shell: bool,
}
impl ADBCmdTrait for ADBCmd {
    fn new(cmd: String, is_shell: bool) -> Self {
        ADBCmd { cmd, is_shell }
    }
    fn create_cmd(self) -> Command {
        let mut command = Command::new(self.cmd);
        if self.is_shell {
            command.arg("shell");
        }
        command
    }
    // run_async runs the given adb command asynchronously.
    /// ```no_run
    ///
    /// use std::process::Command;
    ///
    /// use ADB::cmd::ADBCmd;
    ///
    /// let adb_cmd = ADBCmd::new();
    /// #[tokio::main]
    /// adb_cmd.run_async(vec!["devices".to_string()], |line| {
    ///     println!("{}", line);
    ///     line
    /// }).await;
    /// ```
    async fn run_async<F>(&self, args: Vec<String>, mut fnc: F)
    where
        F: FnMut(String) -> String + 'static,
    {
        let mut cmd = <ADBCmd as Clone>::clone(&self)
            .create_cmd()
            .arg("/c")
            .args(args)
            .stdout(std::process::Stdio::piped()) // 将标准输出重定向到管道
            .spawn() // 启动子进程
            .expect("failed to execute command");

        if let Some(stdout) = cmd.stdout.take() {
            let reader = BufReader::new(stdout);
            let mut lines = reader.lines();

            while let Ok(Some(line)) = lines.next_line().await {
                let _result = fnc(line);
                // 这里你可以直接使用 `result`,或者根据需要做进一步的处理
            }
        }
    }
    /// run runs the given adb command synchronously.
    /// ```no_run
    /// use std::process::Command;
    ///
    /// use ADB::cmd::ADBCmd;
    ///
    /// let adb_cmd = ADBCmd::new("cmd".to_string(),false);
    ///
    /// let result = adb_cmd.run(vec!["devices".to_string()]);
    /// ```
    fn run(&self, args: Vec<String>) -> Result<String, String> {
        let mut output = std::process::Command::new("cmd");
        output.arg("/C");
        output.arg(&self.cmd);
        if self.is_shell {
            output.arg("shell".to_string());
        }
        output.args(args);
        let child = output
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .output()
            .map_err(|err| format!("Failed command : {}", err))?;
        let stdout: String = String::from_utf8_lossy(&child.stdout).to_string();
        let stderr: String = String::from_utf8_lossy(&child.stderr).to_string();

        if !stderr.is_empty() {
            Err(stderr)
        } else {
            Ok(stdout)
        }
    }

    /// Get variable on command
    /// ```no_run
    ///  let mut arg=String::from("mmi");
    ///  let exec_args=vec![];
    ///  let args= vec![
    ///     "ls".to_string(),
    ///     "/system/bin/sxrmmi".to_string()
    ///     ]
    ///  let _prefix= ADBCmd::new("adb",false).get_var_arg(args);
    ///  if _prefix.is_ok(){
    ///      arg = format!("{}{}","sxr".to_string(),arg);
    ///  }else{
    ///      arg = format!("{}{}","ssnwt".to_string(),arg);
    ///  }
    ///  exec_args.push(arg);
    ///  exec_args.push("stop".to_string());
    ///  let res= ADBCmd::new("adb",false).run(exec_args);
    ///  
    /// ```
    async fn get_var_arg(self, args: Vec<String>) -> bool {
        let res = self.run(args);
        match res {
            Ok(_) => true,
            Err(_) => false,
        }
    }
    /// 获取文件路径
    /// ```no_run
    ///  let res= ADBCmd::new("adb",false).get_file_path("./resources/file.xml");
    /// ```
    fn get_file_path(path: &str) -> Result<String, String> {
        let mut _custom_path = Path::new(path).canonicalize();
        match _custom_path {
            Ok(p) => Ok(p.as_os_str().to_string_lossy().to_string()),
            Err(_err) => Err(format!("The file path does not exist or is incorrect")),
        }
    }
}