use crate::{Error, Result};
use aerox_config::ServerConfig;
use aerox_core::{App, Plugin};
use aerox_router::{Context, Router};
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
pub struct ServerBuilder {
config: ServerConfig,
router: Router,
plugins: Vec<Box<dyn Plugin>>,
}
impl ServerBuilder {
pub fn new() -> Self {
Self {
config: ServerConfig::default(),
router: Router::new(),
plugins: Vec::new(),
}
}
pub fn bind(addr: impl Into<String>) -> Self {
let addr_str = addr.into();
let (bind_addr, port) = parse_addr(&addr_str);
let mut config = ServerConfig::default();
config.bind_address = bind_addr;
config.port = port;
Self {
config,
router: Router::new(),
plugins: Vec::new(),
}
}
pub fn config(mut self, config: ServerConfig) -> Self {
self.config = config;
self
}
pub fn route<F>(mut self, msg_id: u16, handler: F) -> Self
where
F: Fn(Context) -> Pin<Box<dyn Future<Output = Result<()>> + Send>>
+ Send
+ Sync
+ 'static,
{
let wrapped_handler = move |ctx: Context| -> Pin<Box<dyn Future<Output = aerox_core::Result<()>> + Send>> {
let result = handler(ctx);
Box::pin(async move {
result.await.map_err(|e| match e {
Error::Core(err) => err,
#[cfg(feature = "client")]
Error::Client(err) => aerox_core::AeroXError::network(err.to_string()),
#[cfg(feature = "server")]
Error::Config(err) => aerox_core::AeroXError::config(err.to_string()),
Error::Io(err) => aerox_core::AeroXError::network(err.to_string()),
Error::Custom(msg) => aerox_core::AeroXError::network(msg),
})
})
};
let _ = self.router.add_route(msg_id, wrapped_handler);
self
}
pub fn plugin(mut self, plugin: impl Plugin + 'static) -> Self {
self.plugins.push(Box::new(plugin));
self
}
pub async fn run(self) -> Result<()> {
use aerox_config::ReactorConfig;
use aerox_network::TcpReactor;
use std::sync::Arc;
println!("AeroX 服务器启动中...");
println!("监听地址: {}", self.config.bind_addr());
let mut app = App::new().set_config(self.config.clone());
for plugin in self.plugins {
app = app.add_boxed_plugin(plugin);
}
let _app = app.build()?;
let router = Arc::new(self.router);
let reactor = TcpReactor::new(
self.config,
ReactorConfig::default(),
);
let reactor = reactor.with_router(router);
reactor.run().await?;
Ok(())
}
}
impl Default for ServerBuilder {
fn default() -> Self {
Self::new()
}
}
pub type Server = ServerBuilder;
fn parse_addr(addr: &str) -> (String, u16) {
if let Some((host, port)) = addr.split_once(':') {
let port = port.parse().unwrap_or(8080);
(host.to_string(), port)
} else {
(addr.to_string(), 8080)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_addr_with_port() {
let (host, port) = parse_addr("127.0.0.1:8080");
assert_eq!(host, "127.0.0.1");
assert_eq!(port, 8080);
}
#[test]
fn test_parse_addr_without_port() {
let (host, port) = parse_addr("127.0.0.1");
assert_eq!(host, "127.0.0.1");
assert_eq!(port, 8080); }
#[test]
fn test_server_builder_creation() {
let builder = ServerBuilder::new();
assert_eq!(builder.config.port, 8080);
}
#[test]
fn test_server_builder_bind() {
let builder = ServerBuilder::bind("127.0.0.1:9000");
assert_eq!(builder.config.bind_address, "127.0.0.1");
assert_eq!(builder.config.port, 9000);
}
}