idevice/services/core_device/
diagnosticsservice.rs

1// Jackson Coxson
2
3use 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}