Initial codebase structure
- Complete Gemini server implementation with logging - Add comprehensive documentation (README.md, AGENTS.md) - Implement certificate management guidelines - Add .gitignore for security and build artifacts - All unit tests passing (14/14) - Ready for production deployment
This commit is contained in:
commit
1ed443ff2a
10 changed files with 639 additions and 0 deletions
105
src/main.rs
Normal file
105
src/main.rs
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
mod config;
|
||||
mod tls;
|
||||
mod request;
|
||||
mod server;
|
||||
mod logging;
|
||||
|
||||
use clap::Parser;
|
||||
use rustls::ServerConfig;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio_rustls::TlsAcceptor;
|
||||
use logging::init_logging;
|
||||
|
||||
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
/// Path to config file
|
||||
#[arg(short, long)]
|
||||
config: Option<String>,
|
||||
|
||||
/// Directory to serve files from
|
||||
#[arg(short, long)]
|
||||
root: Option<String>,
|
||||
|
||||
/// Path to certificate file
|
||||
#[arg(short, long)]
|
||||
cert: Option<String>,
|
||||
|
||||
/// Path to private key file
|
||||
#[arg(short, long)]
|
||||
key: Option<String>,
|
||||
|
||||
/// Port to listen on
|
||||
#[arg(short, long)]
|
||||
port: Option<u16>,
|
||||
|
||||
/// Hostname for the server
|
||||
#[arg(short = 'H', long)]
|
||||
host: Option<String>,
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let args = Args::parse();
|
||||
|
||||
// Load config
|
||||
let config_path = args.config.as_deref().unwrap_or("/etc/pollux/config.toml");
|
||||
let config = config::load_config(config_path).unwrap_or(config::Config {
|
||||
root: None,
|
||||
cert: None,
|
||||
key: None,
|
||||
host: None,
|
||||
port: None,
|
||||
log_level: None,
|
||||
});
|
||||
|
||||
// Initialize logging
|
||||
let log_level = config.log_level.as_deref().unwrap_or("info");
|
||||
init_logging(log_level);
|
||||
|
||||
// Merge config with args (args take precedence)
|
||||
let root = args.root.or(config.root).expect("root is required");
|
||||
let cert = args.cert.or(config.cert).expect("cert is required");
|
||||
let key = args.key.or(config.key).expect("key is required");
|
||||
let host = args.host.or(config.host).unwrap_or_else(|| "0.0.0.0".to_string());
|
||||
let port = args.port.or(config.port).unwrap_or(1965);
|
||||
|
||||
// Validate directory
|
||||
let dir_path = Path::new(&root);
|
||||
if !dir_path.exists() || !dir_path.is_dir() {
|
||||
eprintln!("Error: Directory '{}' does not exist or is not a directory", root);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
// Load TLS certificates
|
||||
let certs = tls::load_certs(&cert).unwrap();
|
||||
let key = tls::load_private_key(&key).unwrap();
|
||||
|
||||
let config = ServerConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_no_client_auth()
|
||||
.with_single_cert(certs, key).unwrap();
|
||||
|
||||
let acceptor = TlsAcceptor::from(Arc::new(config));
|
||||
|
||||
let listener = TcpListener::bind(format!("{}:{}", host, port)).await.unwrap();
|
||||
println!("Server listening on {}:{}", host, port);
|
||||
|
||||
loop {
|
||||
let (stream, _) = listener.accept().await.unwrap();
|
||||
let acceptor = acceptor.clone();
|
||||
let dir = root.clone();
|
||||
let expected_host = host.clone();
|
||||
if let Ok(stream) = acceptor.accept(stream).await {
|
||||
if let Err(e) = server::handle_connection(stream, &dir, &expected_host).await {
|
||||
tracing::error!("Error handling connection: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue