bairelay_wake_server/
lib.rs1pub mod config;
7pub mod packet;
8pub mod registry;
9pub mod route;
10
11mod middleman;
12mod register;
13
14use std::io;
15use std::net::SocketAddr;
16
17pub use config::WakeServerConfig;
18
19#[derive(Debug, thiserror::Error)]
21pub enum WakeServerError {
22 #[error("wake server failed to bind to {addr}: {source}")]
24 Bind { addr: SocketAddr, source: io::Error },
25
26 #[error("wake server socket error: {0}")]
28 Socket(#[from] io::Error),
29
30 #[error("BcUdp framing error: {0}")]
32 Frame(#[from] bairelay_neolink_core::Error),
33
34 #[error("BcUdp XML error: {0}")]
36 Xml(#[from] quick_xml::de::DeError),
37
38 #[error("invalid wake-server config: {0}")]
40 Config(String),
41
42 #[error("wake server received unexpected BcUdp packet kind: {kind}")]
44 UnexpectedPacketKind { kind: &'static str },
45}
46
47use std::sync::Arc;
48use tokio::net::UdpSocket;
49use tokio_util::sync::CancellationToken;
50
51pub fn make_registry() -> Arc<registry::CameraRegistry> {
55 Arc::new(registry::CameraRegistry::new())
56}
57
58pub async fn run_with_sockets(
65 cfg: config::RuntimeConfig,
66 registry: Arc<registry::CameraRegistry>,
67 middleman_sock: UdpSocket,
68 register_sock: UdpSocket,
69 cancel: CancellationToken,
70) -> Result<(), WakeServerError> {
71 let middleman_sock = Arc::new(middleman_sock);
72 let register_sock = Arc::new(register_sock);
73
74 let anchors = Arc::new(registry::SessionAnchors::new());
78
79 let register_local = register_sock
80 .local_addr()
81 .map_err(WakeServerError::Socket)?;
82
83 let mid = {
87 let sock = Arc::clone(&middleman_sock);
88 let cancel = cancel.clone();
89 let bind = cfg.bind;
90 let anchors = Arc::clone(&anchors);
91 tokio::spawn(
92 async move { middleman::run(sock, register_local, bind, anchors, cancel).await },
93 )
94 };
95 let reg = {
96 let sock = Arc::clone(®ister_sock);
97 let cancel = cancel.clone();
98 let registry = Arc::clone(®istry);
99 let anchors = Arc::clone(&anchors);
100 let cfg = cfg.clone();
101 tokio::spawn(async move { register::run(sock, registry, anchors, cfg, cancel).await })
102 };
103
104 let res: Result<(), WakeServerError> = tokio::select! {
105 r = mid => match r {
106 Ok(inner) => inner,
107 Err(join_err) => Err(WakeServerError::Config(format!("middleman join: {join_err}"))),
108 },
109 r = reg => match r {
110 Ok(inner) => inner,
111 Err(join_err) => Err(WakeServerError::Config(format!("register join: {join_err}"))),
112 },
113 };
114 cancel.cancel();
115 res
116}
117
118pub async fn run(
123 cfg: config::RuntimeConfig,
124 registry: Arc<registry::CameraRegistry>,
125 cancel: CancellationToken,
126) -> Result<(), WakeServerError> {
127 let middleman_addr = std::net::SocketAddr::new(cfg.bind, cfg.middleman_port);
128 let register_addr = std::net::SocketAddr::new(cfg.bind, cfg.register_port);
129 let middleman =
130 UdpSocket::bind(middleman_addr)
131 .await
132 .map_err(|source| WakeServerError::Bind {
133 addr: middleman_addr,
134 source,
135 })?;
136 let register =
137 UdpSocket::bind(register_addr)
138 .await
139 .map_err(|source| WakeServerError::Bind {
140 addr: register_addr,
141 source,
142 })?;
143 run_with_sockets(cfg, registry, middleman, register, cancel).await
144}
145
146#[cfg(test)]
147mod error_tests {
148 use super::*;
149 use std::net::Ipv4Addr;
150
151 #[test]
152 fn bind_error_displays_addr_and_source() {
153 let addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 9999);
154 let source = io::Error::new(io::ErrorKind::AddrInUse, "in use");
155 let err = WakeServerError::Bind { addr, source };
156 let s = format!("{err}");
157 assert!(s.contains("9999"));
158 assert!(s.contains("in use"));
159 }
160}