use std::{error::Error, net::UdpSocket}; use rosc::{OscMessage, OscPacket}; pub struct OscServer { socket: UdpSocket, buf: Vec, } impl OscServer { pub fn new(addr: &str) -> std::io::Result { let socket = UdpSocket::bind(addr)?; socket.set_nonblocking(true)?; log::info!("listening for OSC on {}", addr); Ok(Self { socket, buf: vec![0u8; 0x10000], }) } /// Drains all pending OSC messages, calling `on_message` for each. /// Returns `true` if any messages were dispatched. pub fn poll( &mut self, mut on_message: impl FnMut(OscMessage) -> Result<(), Box>, ) -> bool { let mut received = false; loop { match self.socket.recv_from(&mut self.buf) { Ok((size, _addr)) => { let data = &self.buf[..size]; let res = rosc::decoder::decode_udp(data) .map_err(Box::from) .and_then(|(_, packet)| dispatch(packet, &mut on_message)); if let Err(e) = res { log::error!("{}", e); }; received = true; } Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => break, Err(e) => { log::error!("OSC recv error: {}", e); break; } } } received } /// Blocks until at least one OSC message arrives, then drains all pending. pub fn recv( &mut self, mut on_message: impl FnMut(OscMessage) -> Result<(), Box>, ) -> bool { self.socket.set_nonblocking(false).expect("set blocking"); match self.socket.recv_from(&mut self.buf) { Ok((size, _addr)) => { let data = &self.buf[..size]; let res = rosc::decoder::decode_udp(data) .map_err(Box::from) .and_then(|(_, packet)| dispatch(packet, &mut on_message)); if let Err(e) = res { log::error!("{}", e); }; } Err(e) => { log::error!("OSC recv error: {}", e); } } self.socket.set_nonblocking(true).expect("set nonblocking"); self.poll(on_message); true } } fn dispatch( packet: OscPacket, on_message: &mut impl FnMut(OscMessage) -> Result<(), E>, ) -> Result<(), E> { match packet { OscPacket::Message(msg) => on_message(msg)?, OscPacket::Bundle(bundle) => { for p in bundle.content { dispatch(p, on_message)?; } } } Ok(()) }