apple_clis/ios_deploy/
detect.rs

1use super::IosDeployCLIInstance;
2use crate::prelude::*;
3
4impl IosDeployCLIInstance {
5	#[instrument(ret, skip_all)]
6	pub fn detect_devices(&self, config: &DetectDevicesConfig) -> Result<Vec<Device>> {
7		let mut command = self
8			.bossy_command()
9			.with_arg("--detect")
10			.with_arg("--json")
11			.with_args(["--timeout", config.timeout.to_string().as_str()]);
12
13		if !config.wifi {
14			command.add_arg("--no-wifi");
15		}
16
17		let output = match command.run_and_wait_for_string() {
18			Ok(output) => output,
19			Err(err) => {
20				if err.status().and_then(|s| s.code()) == Some(253) {
21					info!(exit_status = ?err.status(), "No devices detected, since ios-deploy exited with status code 253");
22					return Ok(vec![]);
23				}
24				Err(err)?
25			}
26		};
27
28		trace!(previous_output = %output, "Before processing ios-deploy JSON output");
29
30		// after every } close brace, adds a comma
31		// this is to handle { .. } \n { ... } even style messages
32		let output = format!("[{}]", output);
33		let output = output.replace("}{", "},{");
34
35		trace!(after_output = %output, "After processing ios-deploy JSON output");
36
37		#[derive(Debug, Deserialize)]
38		struct Event {
39			#[serde(rename(deserialize = "Interface"))]
40			interface: DeviceInterface,
41
42			#[serde(rename(deserialize = "Device"))]
43			device: DeviceDetected,
44		}
45
46		#[derive(Debug, Deserialize)]
47		struct DeviceDetected {
48			#[serde(rename(deserialize = "DeviceIdentifier"))]
49			device_identifier: String,
50
51			#[serde(rename(deserialize = "DeviceName"))]
52			device_name: String,
53
54			#[serde(rename(deserialize = "modelName"))]
55			model_name: ModelName,
56		}
57
58		let events = match serde_json::from_str::<Vec<Event>>(&output) {
59			Ok(events) => events,
60			Err(err) => {
61				error!(%output, "Failed to parse JSON output from ios-deploy");
62				Err(err)?
63			}
64		};
65		let devices = events
66			.into_iter()
67			.map(|event| Device {
68				device_name: event.device.device_name,
69				device_identifier: event.device.device_identifier,
70				model_name: event.device.model_name,
71				interface: event.interface,
72			})
73			.collect();
74
75		Ok(devices)
76	}
77}
78
79#[derive(Debug)]
80#[cfg_attr(feature = "cli", derive(clap::Args))]
81pub struct DetectDevicesConfig {
82	#[cfg_attr(feature = "cli", clap(long, default_value_t = 1))]
83	pub timeout: u8,
84
85	#[cfg_attr(feature = "cli", clap(long, default_value_t = false))]
86	pub wifi: bool,
87}
88
89impl Default for DetectDevicesConfig {
90	#[instrument(level = "trace", skip())]
91	fn default() -> Self {
92		DetectDevicesConfig {
93			timeout: 1,
94			wifi: true,
95		}
96	}
97}
98
99#[derive(Debug, Serialize, Deserialize)]
100pub struct Device {
101	pub device_identifier: String,
102	pub device_name: String,
103	pub model_name: ModelName,
104	pub interface: DeviceInterface,
105}
106
107#[derive(Debug, Serialize, Deserialize)]
108#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
109pub enum DeviceInterface {
110	Usb,
111	Wifi,
112}