1use serde::{Deserialize, Serialize};
2use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
3
4use crate::mux::MuxError;
5
6pub fn encode_message(payload: &[u8], tag: u32) -> Vec<u8> {
7 let total = 16 + payload.len();
8 let mut buf = Vec::with_capacity(total);
9 buf.extend_from_slice(&(total as u32).to_le_bytes());
10 buf.extend_from_slice(&1u32.to_le_bytes()); buf.extend_from_slice(&8u32.to_le_bytes()); buf.extend_from_slice(&tag.to_le_bytes());
13 buf.extend_from_slice(payload);
14 buf
15}
16
17pub async fn send_plist<W, T>(writer: &mut W, value: &T, tag: u32) -> Result<(), MuxError>
18where
19 W: AsyncWrite + Unpin,
20 T: Serialize,
21{
22 let mut plist_bytes = Vec::new();
23 plist::to_writer_xml(&mut plist_bytes, value).map_err(|e| MuxError::Protocol(e.to_string()))?;
24 let msg = encode_message(&plist_bytes, tag);
25 writer.write_all(&msg).await?;
26 writer.flush().await?;
27 Ok(())
28}
29
30pub async fn recv_plist<R, T>(reader: &mut R) -> Result<T, MuxError>
31where
32 R: AsyncRead + Unpin,
33 T: for<'de> Deserialize<'de>,
34{
35 let mut header = [0u8; 16];
36 reader.read_exact(&mut header).await?;
37 let length = u32::from_le_bytes(header[0..4].try_into().unwrap()) as usize;
38 if length < 16 {
39 return Err(MuxError::Protocol(format!(
40 "invalid message length: {length}"
41 )));
42 }
43 let mut payload = vec![0u8; length - 16];
44 reader.read_exact(&mut payload).await?;
45 let value = plist::from_bytes(&payload).map_err(|e| MuxError::Protocol(e.to_string()))?;
46 Ok(value)
47}
48
49#[derive(Serialize)]
52#[serde(rename_all = "PascalCase")]
53pub(crate) struct ListDevicesRequest {
54 pub message_type: &'static str,
55 pub prog_name: &'static str,
56 pub client_version_string: &'static str,
57}
58
59#[derive(Debug, Deserialize)]
60#[serde(rename_all = "PascalCase")]
61pub(crate) struct DeviceList {
62 pub device_list: Vec<DeviceEntryRaw>,
63}
64
65#[derive(Debug, Deserialize, Clone)]
66#[serde(rename_all = "PascalCase")]
67pub(crate) struct DeviceEntryRaw {
68 #[serde(rename = "DeviceID")]
69 pub device_id: u32,
70 pub properties: DevicePropertiesRaw,
71}
72
73#[derive(Debug, Deserialize, Clone)]
74#[serde(rename_all = "PascalCase")]
75pub(crate) struct DevicePropertiesRaw {
76 pub serial_number: String,
77 pub connection_type: String,
78 pub product_id: Option<u16>,
79}
80
81#[derive(Serialize)]
84#[serde(rename_all = "PascalCase")]
85pub(crate) struct ReadPairRecordRequest {
86 pub message_type: &'static str,
87 pub prog_name: &'static str,
88 pub client_version_string: &'static str,
89 pub bundle_id: &'static str,
90 #[serde(rename = "kLibUSBMuxVersion")]
91 pub lib_usbmux_version: u32,
92 #[serde(rename = "PairRecordID")]
93 pub pair_record_id: String,
94}
95
96#[derive(Serialize)]
99#[serde(rename_all = "PascalCase")]
100pub(crate) struct ReadBuidRequest {
101 pub message_type: &'static str,
102 pub prog_name: &'static str,
103 pub client_version_string: &'static str,
104 pub bundle_id: &'static str,
105 #[serde(rename = "kLibUSBMuxVersion")]
106 pub lib_usbmux_version: u32,
107}
108
109#[derive(Debug, Deserialize)]
110#[serde(rename_all = "PascalCase")]
111pub(crate) struct ReadBuidResponse {
112 #[serde(rename = "BUID")]
113 pub buid: String,
114}
115
116#[derive(Serialize)]
119#[serde(rename_all = "PascalCase")]
120pub(crate) struct ConnectRequest {
121 pub message_type: &'static str,
122 pub prog_name: &'static str,
123 pub client_version_string: &'static str,
124 pub bundle_id: &'static str,
125 #[serde(rename = "kLibUSBMuxVersion")]
126 pub lib_usbmux_version: u32,
127 #[serde(rename = "DeviceID")]
128 pub device_id: u32,
129 pub port_number: u16,
130}
131
132#[derive(Debug, Deserialize)]
133#[serde(rename_all = "PascalCase")]
134pub(crate) struct ConnectResponse {
135 #[allow(dead_code)]
136 pub message_type: String,
137 pub number: u32,
138}
139
140#[derive(Serialize)]
143#[serde(rename_all = "PascalCase")]
144pub(crate) struct ListenRequest {
145 pub message_type: &'static str,
146 pub prog_name: &'static str,
147 pub client_version_string: &'static str,
148}
149
150#[derive(Debug, Deserialize)]
151#[serde(rename_all = "PascalCase")]
152pub(crate) struct DeviceEvent {
153 pub message_type: String,
154 #[serde(rename = "DeviceID")]
155 pub device_id: u32,
156 pub properties: Option<DevicePropertiesRaw>,
157}