1use tracing::debug;
3
4use crate::connection::AdbConnection;
5use crate::device::AdbDevice;
6use crate::error::{AdbError, Result};
7use crate::models::{DeviceEvent, DeviceInfo, DeviceState, ForwardEntry};
8
9#[derive(Debug, Clone)]
11pub struct AdbServer {
12 host: String,
13 port: u16,
14}
15
16impl Default for AdbServer {
17 fn default() -> Self {
18 Self {
19 host: "127.0.0.1".into(),
20 port: 5037,
21 }
22 }
23}
24
25impl AdbServer {
26 pub fn new(host: impl Into<String>, port: u16) -> Self {
28 Self {
29 host: host.into(),
30 port,
31 }
32 }
33
34 pub async fn devices(&self) -> Result<Vec<DeviceInfo>> {
38 let mut conn = AdbConnection::connect(&self.host, self.port).await?;
39 conn.send_and_okay("host:devices").await?;
40 let data = conn.read_length_prefixed_string().await?;
41
42 let devices: Vec<DeviceInfo> = data
43 .lines()
44 .filter(|l| !l.is_empty())
45 .filter_map(|line| {
46 let mut parts = line.split_whitespace();
47 let serial = parts.next()?.to_string();
48 let state_str = parts.next().unwrap_or("unknown");
49 Some(DeviceInfo {
50 serial,
51 state: DeviceState::from(state_str),
52 })
53 })
54 .collect();
55
56 debug!("found {} device(s)", devices.len());
57 Ok(devices)
58 }
59
60 pub async fn device(&self) -> Result<AdbDevice> {
62 let devices = self.devices().await?;
63 let info = devices
64 .into_iter()
65 .find(|d| d.state.is_online())
66 .ok_or(AdbError::NoDevice)?;
67 Ok(AdbDevice::new(info.serial, &self.host, self.port))
68 }
69
70 pub async fn device_by_serial(&self, serial: &str) -> Result<AdbDevice> {
72 let devices = self.devices().await?;
73 let found = devices.iter().any(|d| d.serial == serial);
74 if found {
75 Ok(AdbDevice::new(serial, &self.host, self.port))
76 } else {
77 Err(AdbError::DeviceNotFound(serial.to_string()))
78 }
79 }
80
81 pub async fn resolve_device(&self, serial: Option<&str>) -> Result<AdbDevice> {
83 match serial {
84 Some(s) => self.device_by_serial(s).await,
85 None => self.device().await,
86 }
87 }
88
89 pub async fn version(&self) -> Result<u32> {
93 let mut conn = AdbConnection::connect(&self.host, self.port).await?;
94 conn.send_and_okay("host:version").await?;
95 let version_str = conn.read_length_prefixed_string().await?;
96 let version = u32::from_str_radix(version_str.trim(), 16)
97 .map_err(|_| AdbError::Parse(format!("cannot parse version: {version_str}")))?;
98 Ok(version)
99 }
100
101 pub async fn server_kill(&self) -> Result<()> {
103 let mut conn = AdbConnection::connect(&self.host, self.port).await?;
104 conn.send_and_okay("host:kill").await?;
105 debug!("ADB server killed");
106 Ok(())
107 }
108
109 pub async fn connect_device(&self, addr: &str) -> Result<String> {
113 let mut conn = AdbConnection::connect(&self.host, self.port).await?;
114 conn.send_and_okay(&format!("host:connect:{addr}")).await?;
115 let response = conn.read_length_prefixed_string().await?;
116 debug!("connect {addr}: {response}");
117 Ok(response)
118 }
119
120 pub async fn disconnect_device(&self, addr: &str) -> Result<String> {
122 let mut conn = AdbConnection::connect(&self.host, self.port).await?;
123 conn.send_and_okay(&format!("host:disconnect:{addr}")).await?;
124 let response = conn.read_length_prefixed_string().await?;
125 debug!("disconnect {addr}: {response}");
126 Ok(response)
127 }
128
129 pub async fn wait_for(
135 &self,
136 serial: Option<&str>,
137 state: &str,
138 timeout: std::time::Duration,
139 ) -> Result<()> {
140 let cmd = match serial {
141 Some(s) => format!("host-serial:{s}:wait-for-any-{state}"),
142 None => format!("host:wait-for-any-{state}"),
143 };
144 let host = self.host.clone();
145 let port = self.port;
146
147 let fut = async move {
148 let mut conn = AdbConnection::connect(&host, port).await?;
149 conn.send_and_okay(&cmd).await?;
150 Ok::<(), AdbError>(())
152 };
153
154 tokio::time::timeout(timeout, fut)
155 .await
156 .map_err(|_| AdbError::Timeout(format!("wait_for {state} timed out")))?
157 }
158
159 pub async fn track_devices(
164 &self,
165 ) -> Result<tokio::sync::mpsc::Receiver<Vec<DeviceEvent>>> {
166 let mut conn = AdbConnection::connect(&self.host, self.port).await?;
167 conn.send_and_okay("host:track-devices").await?;
168
169 let (tx, rx) = tokio::sync::mpsc::channel(16);
170
171 tokio::spawn(async move {
172 loop {
173 match conn.read_length_prefixed_string().await {
174 Ok(data) => {
175 let events: Vec<DeviceEvent> = data
176 .lines()
177 .filter(|l| !l.is_empty())
178 .filter_map(|line| {
179 let mut parts = line.split_whitespace();
180 let serial = parts.next()?.to_string();
181 let state =
182 DeviceState::from(parts.next().unwrap_or("unknown"));
183 Some(DeviceEvent { serial, state })
184 })
185 .collect();
186 if tx.send(events).await.is_err() {
187 break;
188 }
189 }
190 Err(_) => break,
191 }
192 }
193 });
194
195 debug!("tracking device events");
196 Ok(rx)
197 }
198
199 pub async fn forward_list_all(&self) -> Result<Vec<ForwardEntry>> {
206 let mut conn = AdbConnection::connect(&self.host, self.port).await?;
207 conn.send_and_okay("host:list-forward").await?;
208 let data = conn.read_length_prefixed_string().await?;
209
210 let entries: Vec<ForwardEntry> = data
211 .lines()
212 .filter(|l| !l.is_empty())
213 .filter_map(|line| {
214 let parts: Vec<&str> = line.split_whitespace().collect();
215 if parts.len() >= 3 {
216 Some(ForwardEntry {
217 serial: parts[0].to_string(),
218 local: parts[1].to_string(),
219 remote: parts[2].to_string(),
220 })
221 } else {
222 None
223 }
224 })
225 .collect();
226
227 Ok(entries)
228 }
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234
235 #[test]
236 fn test_default_server() {
237 let server = AdbServer::default();
238 assert_eq!(server.host, "127.0.0.1");
239 assert_eq!(server.port, 5037);
240 }
241
242 #[test]
243 fn test_parse_devices_output() {
244 let data = "emulator-5554\tdevice\n192.168.1.5:5555\toffline\n";
245 let devices: Vec<DeviceInfo> = data
246 .lines()
247 .filter(|l| !l.is_empty())
248 .filter_map(|line| {
249 let mut parts = line.split_whitespace();
250 let serial = parts.next()?.to_string();
251 let state_str = parts.next().unwrap_or("unknown");
252 Some(DeviceInfo {
253 serial,
254 state: DeviceState::from(state_str),
255 })
256 })
257 .collect();
258
259 assert_eq!(devices.len(), 2);
260 assert_eq!(devices[0].serial, "emulator-5554");
261 assert!(devices[0].state.is_online());
262 assert_eq!(devices[1].serial, "192.168.1.5:5555");
263 assert!(!devices[1].state.is_online());
264 }
265
266 #[test]
267 fn test_parse_track_devices_output() {
268 let data = "emulator-5554\tdevice\n192.168.1.5:5555\toffline\n";
269 let events: Vec<DeviceEvent> = data
270 .lines()
271 .filter(|l| !l.is_empty())
272 .filter_map(|line| {
273 let mut parts = line.split_whitespace();
274 let serial = parts.next()?.to_string();
275 let state = DeviceState::from(parts.next().unwrap_or("unknown"));
276 Some(DeviceEvent { serial, state })
277 })
278 .collect();
279
280 assert_eq!(events.len(), 2);
281 assert_eq!(events[0].serial, "emulator-5554");
282 assert!(events[0].state.is_online());
283 assert!(!events[1].state.is_online());
284 }
285}