1use std::net::SocketAddr;
2use std::sync::Arc;
3
4use tokio::net::UdpSocket;
5
6use crate::error::Error;
7use crate::osc::{self, OscMessage, OscPacket};
8
9type Handler = Arc<dyn Fn(OscMessage, SocketAddr) + Send + Sync + 'static>;
10
11pub struct OscServer {
14 socket: Arc<UdpSocket>,
15 handlers: Vec<(String, Handler)>,
16 buffer_size: usize,
17}
18
19impl OscServer {
20 pub async fn bind(addr: impl tokio::net::ToSocketAddrs) -> Result<Self, Error> {
22 let socket = UdpSocket::bind(addr).await?;
23 Ok(Self {
24 socket: Arc::new(socket),
25 handlers: Vec::new(),
26 buffer_size: 65536,
27 })
28 }
29
30 pub fn handle<F>(&mut self, pattern: impl Into<String>, f: F)
32 where
33 F: Fn(OscMessage, SocketAddr) + Send + Sync + 'static,
34 {
35 self.handlers.push((pattern.into(), Arc::new(f)));
36 }
37
38 pub fn set_buffer_size(&mut self, size: usize) {
40 self.buffer_size = size;
41 }
42
43 pub fn local_addr(&self) -> Result<SocketAddr, Error> {
45 Ok(self.socket.local_addr()?)
46 }
47
48 pub async fn run(&self) -> Result<(), Error> {
50 let mut buf = vec![0u8; self.buffer_size];
51 loop {
52 let (n, src) = self.socket.recv_from(&mut buf).await?;
53 let data = &buf[..n];
54 match osc::decode(data) {
55 Ok(packet) => {
56 if let Err(e) = self.dispatch(packet, src) {
57 log::warn!("dispatch error: {}", e);
58 }
59 }
60 Err(e) => {
61 log::warn!("failed to decode OSC packet from {}: {}", src, e);
62 }
63 }
64 }
65 }
66
67 fn dispatch(&self, packet: OscPacket, src: SocketAddr) -> Result<(), Error> {
68 match packet {
69 OscPacket::Message(msg) => {
70 for (pattern, handler) in &self.handlers {
71 if osc::pattern_match(pattern, &msg.addr) {
72 handler(msg.clone(), src);
73 }
74 }
75 Ok(())
76 }
77 OscPacket::Bundle(bundle) => {
78 for p in bundle.packets {
79 self.dispatch(p, src)?;
80 }
81 Ok(())
82 }
83 }
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use crate::osc::{OscBundle, OscMessage, OscPacket, OscType, TimeTag};
91 use std::sync::atomic::{AtomicBool, Ordering};
92 use std::sync::Arc;
93
94 #[test]
95 fn test_pattern_registration() {
96 let server = OscServer::bind("127.0.0.1:0");
97 let rt = tokio::runtime::Builder::new_current_thread()
98 .enable_io()
99 .build()
100 .unwrap();
101 let mut server = rt.block_on(server).unwrap();
102
103 let called = Arc::new(AtomicBool::new(false));
104 let called_clone = called.clone();
105
106 server.handle("/test", move |_msg, _src| {
107 called_clone.store(true, Ordering::SeqCst);
108 });
109
110 assert_eq!(server.handlers.len(), 1);
111
112 let msg = OscMessage {
113 addr: "/test".into(),
114 args: vec![OscType::Int(42)],
115 };
116
117 server
118 .dispatch(OscPacket::Message(msg), "127.0.0.1:0".parse().unwrap())
119 .unwrap();
120
121 assert!(called.load(Ordering::SeqCst));
122 }
123
124 #[test]
125 fn test_dispatch_bundle_unwraps() {
126 let server = OscServer::bind("127.0.0.1:0");
127 let rt = tokio::runtime::Builder::new_current_thread()
128 .enable_io()
129 .build()
130 .unwrap();
131 let mut server = rt.block_on(server).unwrap();
132
133 let count = Arc::new(std::sync::atomic::AtomicUsize::new(0));
134 let count_clone = count.clone();
135
136 server.handle("/*", move |_msg, _src| {
137 count_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
138 });
139
140 let bundle = OscBundle {
141 timetag: TimeTag::immediate(),
142 packets: vec![
143 OscPacket::Message(OscMessage {
144 addr: "/a".into(),
145 args: vec![],
146 }),
147 OscPacket::Message(OscMessage {
148 addr: "/b".into(),
149 args: vec![],
150 }),
151 ],
152 };
153
154 server
155 .dispatch(OscPacket::Bundle(bundle), "127.0.0.1:0".parse().unwrap())
156 .unwrap();
157
158 assert_eq!(count.load(std::sync::atomic::Ordering::SeqCst), 2);
159 }
160
161 #[test]
162 fn test_no_handler_match() {
163 let server = OscServer::bind("127.0.0.1:0");
164 let rt = tokio::runtime::Builder::new_current_thread()
165 .enable_io()
166 .build()
167 .unwrap();
168 let mut server = rt.block_on(server).unwrap();
169
170 server.handle("/audio/volume", |_msg, _src| {});
171
172 let msg = OscMessage {
173 addr: "/mixer/pan".into(),
174 args: vec![],
175 };
176
177 let result = server.dispatch(OscPacket::Message(msg), "127.0.0.1:0".parse().unwrap());
178 assert!(result.is_ok());
179 }
180
181 #[test]
182 fn test_set_buffer_size() {
183 let server = OscServer::bind("127.0.0.1:0");
184 let rt = tokio::runtime::Builder::new_current_thread()
185 .enable_io()
186 .build()
187 .unwrap();
188 let mut server = rt.block_on(server).unwrap();
189 server.set_buffer_size(1024);
190 assert_eq!(server.buffer_size, 1024);
191 }
192
193 #[test]
194 fn test_local_addr() {
195 let server = OscServer::bind("127.0.0.1:0");
196 let rt = tokio::runtime::Builder::new_current_thread()
197 .enable_io()
198 .build()
199 .unwrap();
200 let server = rt.block_on(server).unwrap();
201 let addr = server.local_addr().unwrap();
202 assert!(addr.port() > 0);
203 }
204}