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 let address = SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), options.port());
33
34 let listener = TcpListener::bind(&address).await?;
36
37 info!(address = %address, "{} server listening", name);
39
40 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}