1use crate::Result;
7use axum::Router;
8
9#[derive(Debug, Clone)]
11pub struct ServerConfig {
12 pub bind_addr: String,
14 pub protocol: HttpProtocol,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum HttpProtocol {
21 Http1,
23 Http2,
25 Http3,
27}
28
29impl Default for ServerConfig {
30 fn default() -> Self {
31 Self {
32 bind_addr: "0.0.0.0:8080".to_string(),
33 protocol: HttpProtocol::Http1,
34 }
35 }
36}
37
38impl ServerConfig {
39 pub fn new(bind_addr: impl Into<String>, protocol: HttpProtocol) -> Self {
41 Self {
42 bind_addr: bind_addr.into(),
43 protocol,
44 }
45 }
46}
47
48#[async_trait::async_trait]
50pub trait HttpServer {
51 async fn serve(router: Router, config: ServerConfig) -> Result<()>;
53}
54
55#[derive(Debug)]
57pub struct ServerBuilder {
58 router: Router,
59 config: ServerConfig,
60}
61
62impl ServerBuilder {
63 pub fn new(router: Router) -> Self {
65 Self {
66 router,
67 config: ServerConfig::default(),
68 }
69 }
70
71 pub fn bind(mut self, addr: impl Into<String>) -> Self {
73 self.config.bind_addr = addr.into();
74 self
75 }
76
77 pub fn version(mut self, version: u8) -> Self {
79 self.config.protocol = match version {
80 1 => HttpProtocol::Http1,
81 2 => HttpProtocol::Http2,
82 3 => HttpProtocol::Http3,
83 _ => {
84 tracing::warn!("Invalid HTTP version {}, defaulting to HTTP/1.1", version);
85 HttpProtocol::Http1
86 }
87 };
88 self
89 }
90
91 pub async fn serve(self) -> Result<()> {
93 match self.config.protocol {
94 HttpProtocol::Http1 => Http1Server::serve(self.router, self.config).await,
95 HttpProtocol::Http2 => Http2Server::serve(self.router, self.config).await,
96 HttpProtocol::Http3 => Http3Server::serve(self.router, self.config).await,
97 }
98 }
99}
100
101pub struct Http1Server;
103
104#[async_trait::async_trait]
105impl HttpServer for Http1Server {
106 async fn serve(router: Router, config: ServerConfig) -> Result<()> {
107 let listener = tokio::net::TcpListener::bind(&config.bind_addr)
108 .await
109 .map_err(|e| {
110 crate::X402Error::config(format!("Failed to bind to {}: {}", config.bind_addr, e))
111 })?;
112
113 tracing::info!(
114 "🚀 HTTP/1.1 server listening on http://{}",
115 config.bind_addr
116 );
117
118 axum::serve(listener, router)
119 .await
120 .map_err(|e| crate::X402Error::config(format!("Server error: {}", e)))?;
121
122 Ok(())
123 }
124}
125
126pub struct Http2Server;
128
129#[async_trait::async_trait]
130impl HttpServer for Http2Server {
131 async fn serve(router: Router, config: ServerConfig) -> Result<()> {
132 let listener = tokio::net::TcpListener::bind(&config.bind_addr)
135 .await
136 .map_err(|e| {
137 crate::X402Error::config(format!("Failed to bind to {}: {}", config.bind_addr, e))
138 })?;
139
140 tracing::info!(
141 "🚀 HTTP/2 server listening on https://{} (with TLS)",
142 config.bind_addr
143 );
144 tracing::warn!("HTTP/2 requires TLS configuration. Consider using axum with TLS support.");
145
146 axum::serve(listener, router)
147 .await
148 .map_err(|e| crate::X402Error::config(format!("Server error: {}", e)))?;
149
150 Ok(())
151 }
152}
153
154pub struct Http3Server;
156
157#[async_trait::async_trait]
158impl HttpServer for Http3Server {
159 async fn serve(router: Router, config: ServerConfig) -> Result<()> {
160 #[cfg(feature = "http3")]
161 {
162 use crate::http3::Http3Config;
163
164 let http3_config = Http3Config::new(&config.bind_addr);
165 crate::http3::create_http3_server(http3_config, router).await
166 }
167
168 #[cfg(not(feature = "http3"))]
169 {
170 let _ = (router, config); Err(crate::X402Error::config(
172 "HTTP/3 support is not enabled. Compile with 'http3' feature flag.".to_string(),
173 ))
174 }
175 }
176}
177
178pub fn create_server(router: Router) -> ServerBuilder {
180 ServerBuilder::new(router)
181}
182
183#[cfg(test)]
184mod tests {
185 use super::*;
186
187 #[test]
188 fn test_server_config_default() {
189 let config = ServerConfig::default();
190 assert_eq!(config.bind_addr, "0.0.0.0:8080");
191 assert_eq!(config.protocol, HttpProtocol::Http1);
192 }
193
194 #[test]
195 fn test_server_config_new() {
196 let config = ServerConfig::new("127.0.0.1:3000", HttpProtocol::Http3);
197 assert_eq!(config.bind_addr, "127.0.0.1:3000");
198 assert_eq!(config.protocol, HttpProtocol::Http3);
199 }
200
201 #[tokio::test]
202 async fn test_server_builder() {
203 let router = Router::new();
204
205 let builder = ServerBuilder::new(router.clone()).bind("127.0.0.1:0");
207 assert_eq!(builder.config.bind_addr, "127.0.0.1:0");
208 assert_eq!(builder.config.protocol, HttpProtocol::Http1);
209
210 let builder = ServerBuilder::new(router.clone())
212 .bind("127.0.0.1:0")
213 .version(2);
214 assert_eq!(builder.config.protocol, HttpProtocol::Http2);
215
216 let builder = ServerBuilder::new(router).bind("127.0.0.1:0").version(3);
218 assert_eq!(builder.config.protocol, HttpProtocol::Http3);
219 }
220}