use hero_websocket_server::{ServerBuilder, TlsConfigError}; use clap::Parser; use dotenv::dotenv; use log::info; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] struct Args { #[clap(short = 'H', long, value_parser, default_value = "127.0.0.1")] host: String, #[clap(short, long, value_parser, default_value_t = 8443)] port: u16, #[clap(long, value_parser, default_value = "redis://127.0.0.1/")] redis_url: String, #[clap(long, help = "Enable authentication")] auth: bool, #[clap(long, help = "Enable TLS/WSS")] tls: bool, #[clap(long, value_parser, help = "Path to TLS certificate file")] cert: Option, #[clap(long, value_parser, help = "Path to TLS private key file")] key: Option, #[clap(long, value_parser, help = "Separate port for TLS connections")] tls_port: Option, #[clap(short, long, action = clap::ArgAction::Count, help = "Increase verbosity (-v for debug, -vv for trace)")] verbose: u8, #[clap(long, help = "Remove timestamps from log output")] no_timestamp: bool, #[clap(long, help = "Enable webhook handling")] webhooks: bool, #[clap(long, value_parser, help = "Worker ID for the server")] worker_id: String, } #[actix_web::main] async fn main() -> std::io::Result<()> { let args = Args::parse(); // Configure logging based on verbosity level let log_config = match args.verbose { 0 => { // Default: suppress actix server logs, show only hero_websocket_server info and above "warn,hero_websocket_server=info" } 1 => { // -v: show debug for hero_websocket_server, info for actix "info,hero_websocket_server=debug,actix_server=info" } 2 => { // -vv: show debug for everything "debug" } _ => { // -vvv and above: show trace for everything "trace" } }; std::env::set_var("RUST_LOG", log_config); // Configure env_logger with or without timestamps if args.no_timestamp { env_logger::Builder::from_default_env() .format_timestamp(None) .init(); } else { env_logger::init(); } // Validate TLS configuration if args.tls && (args.cert.is_none() || args.key.is_none()) { eprintln!("Error: TLS is enabled but certificate or key path is missing"); eprintln!("Use --cert and --key to specify certificate and key files"); std::process::exit(1); } let mut builder = ServerBuilder::new() .host(args.host.clone()) .port(args.port) .redis_url(args.redis_url.clone()) .worker_id(args.worker_id.clone()); if args.auth { builder = builder.with_auth(); } if args.tls { if let (Some(cert), Some(key)) = (args.cert.clone(), args.key.clone()) { builder = builder.with_tls(cert, key); } else { eprintln!("Error: TLS is enabled but --cert or --key is missing."); std::process::exit(1); } } if let Some(tls_port) = args.tls_port { builder = builder.with_tls_port(tls_port); } if args.webhooks { builder = builder.with_webhooks(); } let server = match builder.build() { Ok(server) => server, Err(e) => { eprintln!("Error building server: {}", e); std::process::exit(1); } }; println!("🚀 Starting Circles WebSocket Server"); println!("📋 Configuration:"); println!(" Host: {}", args.host); println!(" Port: {}", args.port); if let Some(tls_port) = args.tls_port { println!(" TLS Port: {}", tls_port); } println!(" Authentication: {}", if args.auth { "ENABLED" } else { "DISABLED" }); println!(" TLS/WSS: {}", if args.tls { "ENABLED" } else { "DISABLED" }); println!(" Webhooks: {}", if args.webhooks { "ENABLED" } else { "DISABLED" }); if args.tls { if let (Some(cert), Some(key)) = (&args.cert, &args.key) { println!(" Certificate: {}", cert); println!(" Private Key: {}", key); } } if args.webhooks { println!(" Webhook secrets loaded from environment variables:"); println!(" - STRIPE_WEBHOOK_SECRET"); println!(" - IDENFY_WEBHOOK_SECRET"); } println!(); let (server_task, _server_handle) = server.spawn_circle_server()?; server_task.await? }