#![allow(clippy::tabs_in_doc_comments)]
use std::{
io,
net::SocketAddr,
pin::Pin,
sync::Arc,
task::{Context, Poll}
};
use futures_core::Stream;
use rosc::OscPacket;
use tokio::net::{ToSocketAddrs, UdpSocket};
mod definitions;
mod error;
pub mod message;
pub extern crate rosc;
mod udp;
use self::udp::UDPSocketStream;
pub use self::{
definitions::*,
error::{Error, Result},
message::{ApplyBlendShapes, BlendShape, BoneTransform, DeviceTransform, Message, RootTransform, State, Time, parse}
};
pub(crate) trait IntoOSCMessage {
fn into_osc_message(self) -> rosc::OscMessage;
}
pub trait IntoOSCPacket {
fn into_osc_packet(self) -> rosc::OscPacket;
}
impl<T> IntoOSCPacket for T
where
T: IntoOSCMessage
{
fn into_osc_packet(self) -> rosc::OscPacket {
rosc::OscPacket::Message(self.into_osc_message())
}
}
impl IntoOSCPacket for rosc::OscBundle {
fn into_osc_packet(self) -> rosc::OscPacket {
rosc::OscPacket::Bundle(self)
}
}
#[derive(Debug)]
pub struct VMCSocket {
socket: UDPSocketStream
}
impl VMCSocket {
pub fn new(socket: UdpSocket) -> Self {
let socket = UDPSocketStream::new(socket);
Self { socket }
}
pub async fn bind<A: ToSocketAddrs>(addr: A) -> Result<Self> {
let socket = UdpSocket::bind(addr).await?;
Ok(Self::new(socket))
}
pub async fn connect<A: ToSocketAddrs>(&self, addrs: A) -> Result<()> {
self.socket().connect(addrs).await?;
Ok(())
}
pub async fn send_to<A: ToSocketAddrs, P: IntoOSCPacket>(&self, packet: P, addrs: A) -> Result<()> {
let buf = rosc::encoder::encode(&packet.into_osc_packet())?;
let n = self.socket().send_to(&buf[..], addrs).await?;
check_len(&buf[..], n)
}
pub async fn send<P: IntoOSCPacket>(&self, packet: P) -> Result<()> {
let buf = rosc::encoder::encode(&packet.into_osc_packet())?;
let n = self.socket().send(&buf[..]).await?;
check_len(&buf[..], n)
}
pub fn sender(&self) -> VMCSender {
VMCSender::new(self.socket.clone_inner())
}
pub fn socket(&self) -> &UdpSocket {
self.socket.get_ref()
}
pub fn local_addr(&self) -> Result<SocketAddr> {
let addr = self.socket().local_addr()?;
Ok(addr)
}
}
impl Stream for VMCSocket {
type Item = Result<(OscPacket, SocketAddr)>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let packet = match Pin::new(&mut self.socket).poll_next(cx) {
Poll::Ready(packet) => packet,
Poll::Pending => return Poll::Pending
};
let message = packet.map(|packet| match packet {
Err(err) => Err(err.into()),
Ok((buf, peer_addr)) => rosc::decoder::decode_udp(&buf[..]).map_err(|e| e.into()).map(|p| (p.1, peer_addr))
});
Poll::Ready(message)
}
}
#[derive(Clone, Debug)]
pub struct VMCSender {
socket: Arc<UdpSocket>
}
impl VMCSender {
fn new(socket: Arc<UdpSocket>) -> Self {
Self { socket }
}
pub async fn send_to<A: ToSocketAddrs, P: IntoOSCPacket>(&self, packet: P, addrs: A) -> Result<()> {
let buf = rosc::encoder::encode(&packet.into_osc_packet())?;
let n = self.socket().send_to(&buf[..], addrs).await?;
check_len(&buf[..], n)
}
pub async fn send<P: IntoOSCPacket>(&self, packet: P) -> Result<()> {
let buf = rosc::encoder::encode(&packet.into_osc_packet())?;
let n = self.socket().send(&buf[..]).await?;
check_len(&buf[..], n)
}
pub fn socket(&self) -> &UdpSocket {
&self.socket
}
}
#[macro_export]
macro_rules! performer {
() => {
$crate::_create_performer("127.0.0.1:0", "127.0.0.1:39539")
};
(bind = $bind:expr) => {
$crate::_create_performer($bind, "127.0.0.1:39539")
};
(bind_port = $bind_port:expr) => {
$crate::_create_performer(format!("127.0.0.1:{}", $bind_port), "127.0.0.1:39539")
};
($addr:expr) => {
$crate::_create_performer("127.0.0.1:0", $addr)
};
($addr:expr, bind = $bind:expr) => {
$crate::_create_performer($bind, $addr)
};
($addr:expr, bind_port = $bind_port:expr) => {
$crate::_create_performer(format!("127.0.0.1:{}", $bind_port), $addr)
};
}
#[doc(hidden)]
pub async fn _create_performer(bind: impl ToSocketAddrs, addr: impl ToSocketAddrs) -> Result<VMCSocket> {
let socket = VMCSocket::bind(bind).await?;
socket.connect(addr).await?;
Ok(socket)
}
#[macro_export]
macro_rules! marionette {
() => {
$crate::_create_marionette("127.0.0.1:39539")
};
($addr:expr) => {
$crate::_create_marionette($addr)
};
}
#[doc(hidden)]
pub async fn _create_marionette(addr: impl ToSocketAddrs) -> Result<VMCSocket> {
let socket = VMCSocket::bind(addr).await?;
Ok(socket)
}
fn check_len(buf: &[u8], len: usize) -> Result<()> {
if len != buf.len() {
Err(io::Error::new(io::ErrorKind::Interrupted, "UDP packet not fully sent").into())
} else {
Ok(())
}
}