1use std::convert::Infallible;
7use std::net::SocketAddr;
8
9use http_body_util::Full;
10use hyper::body::Bytes;
11use hyper::service::service_fn;
12use hyper::{Method, Request, Response, StatusCode};
13use hyper_util::rt::TokioIo;
14use socketioxide::SocketIo;
15use tokio::net::TcpListener;
16use tower::ServiceBuilder;
17use tracing::{error, info};
18
19use smcp_server_core::SmcpServerLayer;
20
21pub struct HyperServer {
23 pub layer: Option<SmcpServerLayer>,
24 pub addr: SocketAddr,
25}
26
27impl HyperServer {
28 pub fn new() -> Self {
30 Self {
31 layer: None,
32 addr: "127.0.0.1:0".parse().unwrap(),
33 }
34 }
35
36 pub fn with_layer(mut self, layer: SmcpServerLayer) -> Self {
38 self.layer = Some(layer);
39 self
40 }
41
42 pub async fn run(
44 self,
45 addr: SocketAddr,
46 ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
47 let layer = self.layer.ok_or("SMCP layer not configured")?;
48
49 info!("Starting SMCP server on {}", addr);
50
51 let listener = TcpListener::bind(addr).await?;
53 let local_addr = listener.local_addr()?;
54 info!("Server listening on {}", local_addr);
55
56 let service = ServiceBuilder::new()
58 .layer(layer.layer)
59 .service(service_fn(move |req| {
60 let io = layer.io.clone();
61 async move { handle_request(req, &io).await }
62 }));
63
64 loop {
66 let (stream, remote_addr) = listener.accept().await?;
67 info!("New connection from: {}", remote_addr);
68
69 let service = service.clone();
70 tokio::spawn(async move {
71 let io = TokioIo::new(stream);
72 if let Err(err) = hyper::server::conn::http1::Builder::new()
73 .serve_connection(io, service)
74 .with_upgrades()
75 .await
76 {
77 error!("Failed to serve connection: {}", err);
78 }
79 });
80 }
81 }
82}
83
84impl Default for HyperServer {
85 fn default() -> Self {
86 Self::new()
87 }
88}
89
90pub async fn handle_request(
92 req: Request<hyper::body::Incoming>,
93 _io: &SocketIo,
94) -> Result<Response<Full<Bytes>>, Infallible> {
95 let response = match (req.method(), req.uri().path()) {
96 (&Method::GET, "/") => Response::builder()
97 .status(StatusCode::OK)
98 .body(Full::new(Bytes::from("SMCP Server is running")))
99 .unwrap(),
100 (&Method::GET, "/health") => Response::builder()
101 .status(StatusCode::OK)
102 .body(Full::new(Bytes::from("{\"status\":\"ok\"}")))
103 .unwrap(),
104 (&Method::GET, "/socket.io/") => {
105 Response::builder()
107 .status(StatusCode::NOT_FOUND)
108 .body(Full::new(Bytes::from("Not found")))
109 .unwrap()
110 }
111 _ => Response::builder()
112 .status(StatusCode::NOT_FOUND)
113 .body(Full::new(Bytes::from("Not found")))
114 .unwrap(),
115 };
116
117 Ok(response)
118}
119
120pub struct HyperServerBuilder {
122 layer: Option<SmcpServerLayer>,
123 addr: Option<SocketAddr>,
124}
125
126impl HyperServerBuilder {
127 pub fn new() -> Self {
129 Self {
130 layer: None,
131 addr: None,
132 }
133 }
134
135 pub fn with_layer(mut self, layer: SmcpServerLayer) -> Self {
137 self.layer = Some(layer);
138 self
139 }
140
141 pub fn with_addr(mut self, addr: SocketAddr) -> Self {
143 self.addr = Some(addr);
144 self
145 }
146
147 pub fn build(self) -> HyperServer {
149 let mut server = HyperServer::new();
150 if let Some(layer) = self.layer {
151 server = server.with_layer(layer);
152 }
153 if let Some(addr) = self.addr {
154 server.addr = addr;
155 }
156 server
157 }
158}
159
160impl Default for HyperServerBuilder {
161 fn default() -> Self {
162 Self::new()
163 }
164}
165
166pub async fn run_server(addr: SocketAddr) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
168 let layer = smcp_server_core::SmcpServerBuilder::new()
170 .build_layer()
171 .map_err(|e| format!("Failed to build SMCP layer: {}", e))?;
172
173 let server = HyperServerBuilder::new()
174 .with_layer(layer)
175 .with_addr(addr)
176 .build();
177
178 server.run(addr).await
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 #[test]
186 fn test_hyper_server_creation() {
187 let server = HyperServer::new();
188 assert_eq!(server.addr, "127.0.0.1:0".parse().unwrap());
189 }
190
191 #[test]
192 fn test_hyper_server_builder() {
193 let builder = HyperServerBuilder::new();
194 assert!(builder.layer.is_none());
195 assert!(builder.addr.is_none());
196 }
197}