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