adb_utils/
manager.rs

1use crate::{ADBCommand, ADBPathCommand, ADBResult};
2use std::process::Command;
3
4/// Center struct where adb commands are built, sent and parsed
5#[derive(Default)]
6pub struct ADBManager {
7    connected: Vec<(String, u32)>,
8    path: Option<String>,
9}
10
11impl ADBManager {
12    pub fn new() -> ADBManager {
13        ADBManager {
14            connected: vec![],
15            path: None,
16        }
17    }
18
19    /// Establish a connection to a device via TCP/IP
20    pub fn connect(&mut self, ip: &str, port: u32) -> Result<(), String> {
21        let mut command = Command::new("cmd");
22        command
23            .arg("/c")
24            .arg(format!("adb connect {}:{}", ip, port));
25        match command.output() {
26            Ok(s) => {
27                if s.status.success() && !String::from_utf8(s.stdout).unwrap().contains("failed") {
28                    self.connected.push((ip.to_owned(), port));
29                    return Ok(());
30                }
31                Err(s.status.to_string())
32            }
33            Err(e) => Err(e.to_string()),
34        }
35    }
36
37    /// Set the current working directory for all future commands where a path on the
38    /// remote is needed
39    pub fn cwd(&mut self, path: &str) {
40        if !path.ends_with('/') {
41            self.path = Some(path.to_owned() + "/");
42        } else {
43            self.path = Some(path.to_owned());
44        }
45    }
46
47    /// Execute an arbitrary command
48    pub fn execute(&self, cmd: &mut impl ADBCommand) -> Result<ADBResult, String> {
49        let command = cmd.build()?;
50        let result = self.execute_impl(command)?;
51        Ok(cmd.process_output(result))
52    }
53
54    /// Execute an arbitrary path command
55    pub fn execute_path_based(&self, cmd: &mut impl ADBPathCommand) -> Result<ADBResult, String> {
56        cmd.path(self.path.clone());
57        let command = cmd.build()?;
58        let result = self.execute_impl(command)?;
59        Ok(cmd.process_output(result))
60    }
61
62    fn execute_impl(&self, command: &mut Command) -> Result<ADBResult, String> {
63        match command.output() {
64            Ok(ok) => {
65                if ok.status.success() {
66                    Ok(ADBResult {
67                        data: String::from_utf8(ok.stdout).unwrap(),
68                    })
69                } else {
70                    Err(ok.status.to_string()
71                        + &String::from_utf8(ok.stdout).unwrap()
72                        + &String::from_utf8(ok.stderr).unwrap())
73                }
74            }
75            Err(e) => Err(e.to_string()),
76        }
77    }
78
79    /// Disconnect from given TCP/IP device
80    pub fn disconnect(&mut self, ip: &str, port: u32) {
81        Self::disconnect_one(ip, port);
82        if let Some(index) = self
83            .connected
84            .iter()
85            .position(|x| *x == (ip.to_owned(), port))
86        {
87            self.connected.remove(index);
88        }
89    }
90
91    fn disconnect_one(ip: &str, port: u32) {
92        let mut command = Command::new("adb");
93        command
94            .arg("disconnect")
95            .arg(format!("{ip}:{port}"))
96            .output()
97            .ok();
98    }
99
100    /// Disconnect all connected devices
101    pub fn disconnect_all(&mut self) {
102        self.connected
103            .iter()
104            .for_each(|(ip, port)| Self::disconnect_one(ip, *port));
105    }
106}
107
108impl Drop for ADBManager {
109    fn drop(&mut self) {
110        self.disconnect_all();
111    }
112}