161 lines
4.5 KiB
Rust
161 lines
4.5 KiB
Rust
|
|
use crate::{
|
||
|
|
cli::ServeCommand,
|
||
|
|
config::GurtConfig,
|
||
|
|
server::FileServerBuilder,
|
||
|
|
Result,
|
||
|
|
};
|
||
|
|
use async_trait::async_trait;
|
||
|
|
use colored::Colorize;
|
||
|
|
use tracing::{error, info};
|
||
|
|
|
||
|
|
#[async_trait]
|
||
|
|
pub trait CommandHandler {
|
||
|
|
async fn execute(&self) -> Result<()>;
|
||
|
|
}
|
||
|
|
|
||
|
|
pub struct CommandHandlerBuilder {
|
||
|
|
logging_initialized: bool,
|
||
|
|
verbose: bool,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl CommandHandlerBuilder {
|
||
|
|
pub fn new() -> Self {
|
||
|
|
Self {
|
||
|
|
logging_initialized: false,
|
||
|
|
verbose: false,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn with_logging(mut self, verbose: bool) -> Self {
|
||
|
|
self.verbose = verbose;
|
||
|
|
self
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn initialize_logging(mut self) -> Self {
|
||
|
|
if !self.logging_initialized {
|
||
|
|
let level = if self.verbose {
|
||
|
|
tracing::Level::DEBUG
|
||
|
|
} else {
|
||
|
|
tracing::Level::INFO
|
||
|
|
};
|
||
|
|
|
||
|
|
tracing_subscriber::fmt()
|
||
|
|
.with_max_level(level)
|
||
|
|
.init();
|
||
|
|
|
||
|
|
self.logging_initialized = true;
|
||
|
|
}
|
||
|
|
self
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn build_serve_handler(self, serve_cmd: ServeCommand) -> ServeCommandHandler {
|
||
|
|
ServeCommandHandler::new(serve_cmd)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Default for CommandHandlerBuilder {
|
||
|
|
fn default() -> Self {
|
||
|
|
Self::new()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub struct ServeCommandHandler {
|
||
|
|
serve_cmd: ServeCommand,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl ServeCommandHandler {
|
||
|
|
pub fn new(serve_cmd: ServeCommand) -> Self {
|
||
|
|
Self { serve_cmd }
|
||
|
|
}
|
||
|
|
|
||
|
|
fn validate_command(&self) -> Result<()> {
|
||
|
|
if !self.serve_cmd.dir.exists() {
|
||
|
|
return Err(crate::ServerError::InvalidPath(
|
||
|
|
format!("Directory does not exist: {}", self.serve_cmd.dir.display())
|
||
|
|
));
|
||
|
|
}
|
||
|
|
|
||
|
|
if !self.serve_cmd.dir.is_dir() {
|
||
|
|
return Err(crate::ServerError::InvalidPath(
|
||
|
|
format!("Path is not a directory: {}", self.serve_cmd.dir.display())
|
||
|
|
));
|
||
|
|
}
|
||
|
|
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
|
||
|
|
fn build_server_config(&self) -> Result<GurtConfig> {
|
||
|
|
let mut config_builder = GurtConfig::builder();
|
||
|
|
|
||
|
|
if let Some(config_file) = &self.serve_cmd.config {
|
||
|
|
config_builder = config_builder.from_file(config_file)?;
|
||
|
|
}
|
||
|
|
|
||
|
|
let config = config_builder
|
||
|
|
.merge_cli_args(&self.serve_cmd)
|
||
|
|
.build()?;
|
||
|
|
|
||
|
|
Ok(config)
|
||
|
|
}
|
||
|
|
|
||
|
|
fn display_startup_info(&self, config: &GurtConfig) {
|
||
|
|
println!("{}", "GURT Protocol Server".bright_cyan().bold());
|
||
|
|
println!("{} {}", "Version".bright_blue(), config.server.protocol_version);
|
||
|
|
println!("{} {}", "Listening on".bright_blue(), config.address());
|
||
|
|
println!("{} {}", "Serving from".bright_blue(), config.server.base_directory.display());
|
||
|
|
|
||
|
|
if config.tls.is_some() {
|
||
|
|
println!("{}", "TLS encryption enabled".bright_green());
|
||
|
|
}
|
||
|
|
|
||
|
|
if let Some(logging) = &config.logging {
|
||
|
|
println!("{} {}", "Log level".bright_blue(), logging.level);
|
||
|
|
if logging.log_requests {
|
||
|
|
println!("{}", "Request logging enabled".bright_green());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if let Some(security) = &config.security {
|
||
|
|
println!("{} {} req/min", "Rate limit".bright_blue(), security.rate_limit_requests);
|
||
|
|
if !security.deny_files.is_empty() {
|
||
|
|
println!("{} {} patterns", "File restrictions".bright_blue(), security.deny_files.len());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if let Some(headers) = &config.headers {
|
||
|
|
if !headers.is_empty() {
|
||
|
|
println!("{} {} headers", "Custom headers".bright_blue(), headers.len());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
println!("{} {}", "Max connections".bright_blue(), config.server.max_connections);
|
||
|
|
println!("{} {}", "Max message size".bright_blue(), config.server.max_message_size);
|
||
|
|
println!();
|
||
|
|
}
|
||
|
|
|
||
|
|
async fn start_server(&self, config: &GurtConfig) -> Result<()> {
|
||
|
|
let server = FileServerBuilder::new(config.clone()).build()?;
|
||
|
|
|
||
|
|
info!("Starting GURT server on {}", config.address());
|
||
|
|
|
||
|
|
if let Err(e) = server.listen(&config.address()).await {
|
||
|
|
error!("Server error: {}", e);
|
||
|
|
std::process::exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[async_trait]
|
||
|
|
impl CommandHandler for ServeCommandHandler {
|
||
|
|
async fn execute(&self) -> Result<()> {
|
||
|
|
self.validate_command()?;
|
||
|
|
|
||
|
|
let config = self.build_server_config()?;
|
||
|
|
|
||
|
|
self.display_startup_info(&config);
|
||
|
|
self.start_server(&config).await
|
||
|
|
}
|
||
|
|
}
|