use std::env;
use std::future::Future;
use std::os::windows::process::CommandExt;
use std::path::Path;
use std::process::Output;
use std::process::Stdio;
use tokio::io::{AsyncBufReadExt, BufReader}; 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>;
fn exec(&self, args: Vec<String>) -> Result<Output, String>;
fn change_shell(&mut self,shell:bool);
}
const CREATE_NO_WINDOW: u32 = 0x08000000;
#[derive(Debug, Clone)]
pub struct ADBCmd {
pub cmd: String,
pub is_shell: bool,
}
impl ADBCmdTrait for ADBCmd {
fn new(cmd: String, is_shell: bool) -> Self {
let mut run_cmd = cmd.clone();
if cmd == "adb".to_string() {
let resoureces: std::path::PathBuf = env::current_exe().expect("无法获取可执行文件路径");
let adb_resources = resoureces
.parent()
.unwrap()
.join("resources")
.join("adb")
.join("adb.exe");
if adb_resources.exists() {
run_cmd = adb_resources.to_string_lossy().to_string();
}
}
ADBCmd { cmd:run_cmd, is_shell }
}
fn change_shell(&mut self,shell:bool) {
self.is_shell=shell;
}
fn create_cmd(self) -> Command {
let mut command = Command::new(self.cmd);
if self.is_shell {
command.arg("shell");
}
command
}
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()
.creation_flags(CREATE_NO_WINDOW)
.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);
}
}
}
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
.creation_flags(CREATE_NO_WINDOW)
.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)
}
}
fn exec(&self, args: Vec<String>) -> Result<Output, 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));
child
}
async fn get_var_arg(self, args: Vec<String>) -> bool {
let res = self.run(args);
match res {
Ok(_) => true,
Err(_) => false,
}
}
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")),
}
}
}