kotoba_server_core/
server.rs

1//! HTTP server implementation
2
3use axum::{
4    Router,
5    extract::Request,
6    http::{HeaderMap, StatusCode},
7    response::{IntoResponse, Response},
8};
9use hyper::server::conn::http1;
10use hyper_util::rt::TokioIo;
11use std::net::SocketAddr;
12use tokio::net::TcpListener;
13use tower::Service;
14use tower_http::cors::{CorsLayer, Any};
15use tower_http::trace::TraceLayer;
16
17use crate::{ServerError, Result};
18
19/// Server configuration
20#[derive(Debug, Clone)]
21pub struct ServerConfig {
22    pub host: String,
23    pub port: u16,
24    pub cors_enabled: bool,
25    pub tracing_enabled: bool,
26}
27
28impl Default for ServerConfig {
29    fn default() -> Self {
30        Self {
31            host: "127.0.0.1".to_string(),
32            port: 8100,
33            cors_enabled: true,
34            tracing_enabled: true,
35        }
36    }
37}
38
39/// HTTP server builder
40#[derive(Debug)]
41pub struct ServerBuilder {
42    config: ServerConfig,
43    router: Router,
44}
45
46impl ServerBuilder {
47    pub fn new() -> Self {
48        Self {
49            config: ServerConfig::default(),
50            router: Router::new(),
51        }
52    }
53
54    pub fn config(mut self, config: ServerConfig) -> Self {
55        self.config = config;
56        self
57    }
58
59    pub fn router(mut self, router: Router) -> Self {
60        self.router = router;
61        self
62    }
63
64    pub fn host(mut self, host: impl Into<String>) -> Self {
65        self.config.host = host.into();
66        self
67    }
68
69    pub fn port(mut self, port: u16) -> Self {
70        self.config.port = port;
71        self
72    }
73
74    pub fn cors_enabled(mut self, enabled: bool) -> Self {
75        self.config.cors_enabled = enabled;
76        self
77    }
78
79    pub fn tracing_enabled(mut self, enabled: bool) -> Self {
80        self.config.tracing_enabled = enabled;
81        self
82    }
83
84    pub fn build(self) -> Result<HttpServer> {
85        let mut router = self.router;
86
87        // Add CORS middleware
88        if self.config.cors_enabled {
89            router = router.layer(
90                CorsLayer::new()
91                    .allow_origin(Any)
92                    .allow_methods(Any)
93                    .allow_headers(Any),
94            );
95        }
96
97        // Add tracing middleware
98        if self.config.tracing_enabled {
99            router = router.layer(TraceLayer::new_for_http());
100        }
101
102        Ok(HttpServer {
103            config: self.config,
104            router,
105        })
106    }
107}
108
109/// HTTP server instance
110#[derive(Debug)]
111pub struct HttpServer {
112    config: ServerConfig,
113    router: Router,
114}
115
116impl HttpServer {
117    pub fn builder() -> ServerBuilder {
118        ServerBuilder::new()
119    }
120
121    pub async fn serve(self) -> Result<()> {
122        let addr = format!("{}:{}", self.config.host, self.config.port)
123            .parse::<SocketAddr>()
124            .map_err(|e| ServerError::Config(format!("Invalid address: {}", e)))?;
125
126        let listener = TcpListener::bind(&addr).await?;
127        tracing::info!("🌐 Kotoba HTTP Server listening on {}", listener.local_addr()?);
128
129        loop {
130            let (stream, _) = listener.accept().await?;
131            let io = TokioIo::new(stream);
132            let router = self.router.clone();
133
134            let tower_service = hyper_util::service::TowerToHyperService::new(router);
135            tokio::task::spawn(async move {
136                if let Err(err) = http1::Builder::new()
137                    .serve_connection(io, tower_service)
138                    .await
139                {
140                    tracing::error!("Error serving connection: {:?}", err);
141                }
142            });
143        }
144    }
145
146    pub fn router(&self) -> &Router {
147        &self.router
148    }
149
150    pub fn config(&self) -> &ServerConfig {
151        &self.config
152    }
153}