idevice/services/core_device/
diagnosticsservice.rs1use std::pin::Pin;
4
5use futures::Stream;
6use log::warn;
7
8use crate::{IdeviceError, ReadWrite, RsdService, obf};
9
10impl RsdService for DiagnostisServiceClient<Box<dyn ReadWrite>> {
11 fn rsd_service_name() -> std::borrow::Cow<'static, str> {
12 obf!("com.apple.coredevice.diagnosticsservice")
13 }
14
15 async fn from_stream(stream: Box<dyn ReadWrite>) -> Result<Self, IdeviceError> {
16 Ok(Self {
17 inner: super::CoreDeviceServiceClient::new(stream).await?,
18 })
19 }
20}
21
22pub struct DiagnostisServiceClient<R: ReadWrite> {
23 inner: super::CoreDeviceServiceClient<R>,
24}
25
26pub struct SysdiagnoseResponse<'a> {
27 pub preferred_filename: String,
28 pub stream: Pin<Box<dyn Stream<Item = Result<Vec<u8>, IdeviceError>> + 'a>>,
29 pub expected_length: usize,
30}
31
32impl<R: ReadWrite> DiagnostisServiceClient<R> {
33 pub async fn capture_sysdiagnose<'a>(
34 &'a mut self,
35 dry_run: bool,
36 ) -> Result<SysdiagnoseResponse<'a>, IdeviceError> {
37 let req = crate::plist!({
38 "options": {
39 "collectFullLogs": true
40 },
41 "isDryRun": dry_run
42 })
43 .into_dictionary()
44 .unwrap();
45
46 let res = self
47 .inner
48 .invoke_with_plist("com.apple.coredevice.feature.capturesysdiagnose", req)
49 .await?;
50
51 if let Some(len) = res
52 .as_dictionary()
53 .and_then(|x| x.get("fileTransfer"))
54 .and_then(|x| x.as_dictionary())
55 .and_then(|x| x.get("expectedLength"))
56 .and_then(|x| x.as_unsigned_integer())
57 && let Some(name) = res
58 .as_dictionary()
59 .and_then(|x| x.get("preferredFilename"))
60 .and_then(|x| x.as_string())
61 {
62 Ok(SysdiagnoseResponse {
63 stream: Box::pin(self.inner.inner.iter_file_chunks(len as usize, 0)),
64 preferred_filename: name.to_string(),
65 expected_length: len as usize,
66 })
67 } else {
68 warn!("Did not get expected responses from RemoteXPC");
69 Err(IdeviceError::UnexpectedResponse)
70 }
71 }
72}