use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use peertalk::{connect_to_device, DeviceEvent, DeviceId, DeviceListener}; use std::error::Error; use std::fmt; use std::io::{Error as IoError, Read, Write}; #[macro_use] extern crate log; const PT_PORT: u16 = 2345; const PT_VERSION: u32 = 1; const PT_FRAME_TYPE_DEVICE_INFO: u32 = 100; const PT_FRAME_TYPE_TEXT_MSG: u32 = 101; const PT_FRAME_TYPE_PING: u32 = 102; const PT_FRAME_TYPE_PONG: u32 = 103; fn main() { pretty_env_logger::formatted_builder() .filter(None, log::LevelFilter::Trace) .init(); let listener = DeviceListener::new().expect("Failed to create device listener, no Apple Mobile Support?"); loop { match listener.next_event() { Some(event) => process_event(event), None => std::thread::sleep(std::time::Duration::from_secs(5)), } } } fn process_event(event: DeviceEvent) { debug!("Event: {:?}", event); match event { DeviceEvent::Attached(info) => { info!("Device attached: {:?}", info); info!("Attempting to connect..."); start_example(info.device_id, PT_PORT); } DeviceEvent::Detached(device_id) => { info!("Device {} detached", device_id); } DeviceEvent::Paired(device_id) => { info!("Device {} was paired", device_id); } } } fn start_example(device_id: DeviceId, port: u16) { let mut socket = connect_to_device(device_id, port).expect("Failed to create device connection"); // say hi let hi = PTFrame::text("Hello from Rust!"); hi.write_into(&mut socket).unwrap(); loop { // wait for data from device match PTFrame::from_reader(&mut socket) { Ok(frame) => process_frame(frame), Err(e) => error!("Error reading frame: {}", e), } } } fn process_frame(frame: PTFrame) { // print out text if it's device info or text msg type if frame.frame_type == PT_FRAME_TYPE_DEVICE_INFO { // binary plist? let reader = std::io::Cursor::new(frame.payload); let info: plist::Value = plist::Value::from_reader(reader).unwrap(); info!("Got device info: {:?}", info); } else if frame.frame_type == PT_FRAME_TYPE_TEXT_MSG { if let Ok(string) = std::str::from_utf8(&frame.payload[4..]) { info!("Got text payload: {}", string); } else { error!("Failed to read payload of {} bytes", frame.payload.len()); } } else if frame.frame_type == PT_FRAME_TYPE_PING { info!("Ping!"); } else if frame.frame_type == PT_FRAME_TYPE_PONG { info!("Pong!"); } } // peertalk frame example protocol #[derive(Debug)] pub enum FrameError { IoError(IoError), } impl fmt::Display for FrameError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { FrameError::IoError(e) => write!(f, "IoError: {}", e), } } } impl Error for FrameError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { FrameError::IoError(e) => Some(e), } } } impl From for FrameError { fn from(error: IoError) -> Self { FrameError::IoError(error) } } type Result = ::std::result::Result; #[derive(Debug)] struct PTFrame { version: u32, frame_type: u32, tag: u32, // payload_size: u32, payload: Vec, } impl PTFrame { fn text(text: &str) -> PTFrame { /*typedef struct _PTExampleTextFrame { uint32_t length; uint8_t utf8text[0]; } PTExampleTextFrame;*/ let mut payload = Vec::with_capacity(text.len() + 4); payload.write_u32::(text.len() as u32).unwrap(); payload.write_all(text.as_bytes()).unwrap(); PTFrame { version: PT_VERSION, frame_type: PT_FRAME_TYPE_TEXT_MSG, tag: 0, payload, } } fn write_into(&self, writer: &mut W) -> Result<()> where W: Write, { writer.write_u32::(self.version).unwrap(); writer.write_u32::(self.frame_type).unwrap(); writer.write_u32::(self.tag).unwrap(); writer .write_u32::(self.payload.len() as u32) .unwrap(); writer.write_all(&self.payload[..]).unwrap(); Ok(()) } fn from_reader(reader: &mut R) -> Result where R: Read, { let version = reader.read_u32::()?; let frame_type = reader.read_u32::()?; let tag = reader.read_u32::()?; let payload_size = reader.read_u32::()?; let payload = if payload_size > 0 { let mut payload = vec![0; payload_size as usize]; reader.read_exact(&mut payload)?; payload } else { vec![] }; let frame = PTFrame { version, frame_type, tag, payload, }; Ok(frame) } }