hyperion/
servers.rs

1use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
2
3use tokio::{
4    net::{TcpListener, TcpStream},
5    task::JoinHandle,
6};
7
8use crate::{global::Global, models::ServerConfig};
9
10pub mod boblight;
11pub mod flat;
12pub mod json;
13pub mod proto;
14
15pub struct ServerHandle {
16    join_handle: JoinHandle<()>,
17}
18
19pub async fn bind<T, E, F, H>(
20    name: &'static str,
21    options: T,
22    global: Global,
23    handle_client: H,
24) -> std::io::Result<ServerHandle>
25where
26    T: ServerConfig + Send + 'static,
27    F: futures::Future<Output = Result<(), E>> + Send + 'static,
28    E: From<std::io::Error> + std::fmt::Display + Send + 'static,
29    H: Fn((TcpStream, SocketAddr), Global) -> F + Send + 'static,
30{
31    // Compute binding address
32    let address = SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), options.port());
33
34    // Setup listener
35    let listener = TcpListener::bind(&address).await?;
36
37    // Notify we are listening
38    info!(address = %address, "{} server listening", name);
39
40    // Spawn accepting loop
41    let join_handle = tokio::spawn(async move {
42        let result: Result<(), _> = loop {
43            match listener.accept().await {
44                Ok(incoming) => {
45                    tokio::spawn({
46                        let peer_addr = incoming.1;
47                        let ft = handle_client(incoming, global.clone());
48
49                        async move {
50                            let result = ft.await;
51
52                            match result {
53                                Ok(_) => {
54                                    info!(peer_addr = %peer_addr, "client disconnected");
55                                }
56                                Err(error) => {
57                                    error!(peer_addr = %peer_addr, error = %error, "client error");
58                                }
59                            }
60                        }
61                    });
62                }
63                Err(error) => break Err(error),
64            }
65        };
66
67        if let Err(error) = result {
68            error!(error = %error, "{} server terminated", name);
69        }
70    });
71
72    Ok(ServerHandle { join_handle })
73}
74
75impl Drop for ServerHandle {
76    fn drop(&mut self) {
77        self.join_handle.abort();
78    }
79}