use std::{ net::TcpListener, sync::{ atomic::{self, AtomicBool}, Arc, }, thread::available_parallelism, }; use crate::{handlers::handle_connection, routing::Route, threading::ThreadPool}; pub struct PreMountConfig { address: TcpListener, workers: usize, threadpool: ThreadPool, } impl PreMountConfig { pub fn mount(self, mountpoint: &str, routes: Vec<Route>) -> Config { Config { mountpoint, address: self.address, workers: self.workers, threadpool: self.threadpool, routes, } } } pub struct Config<'a> { mountpoint: &'a str, address: TcpListener, workers: usize, threadpool: ThreadPool, routes: Vec<Route>, } impl Config<'_> { pub fn launch(self) { let running = Arc::new(AtomicBool::new(true)); // Clone a reference to `running` to pass to the signal handler closure let running_for_handler = running.clone(); // Set up a signal handler for SIGINT ctrlc::set_handler(move || { // When the user sends a SIGINT signal (e.g. by pressing CTRL+C), // set the `running` flag to false to initiate a graceful shutdown println!("SIGNIT received, shutting down gracefully"); running_for_handler.store(false, atomic::Ordering::SeqCst); }) .expect("Error setting Ctrl-C handler"); for stream in self.address.incoming() { if !running.load(atomic::Ordering::SeqCst) { break; } let stream = stream.unwrap(); self.threadpool.execute(|| handle_connection(stream)) } } } pub fn build(ip: &str) -> PreMountConfig { let listener = TcpListener::bind(ip).unwrap(); let ip = ip.splitn(2, ":").collect::<Vec<&str>>(); if ip.len() != 2 { panic!("Invalid IP Address"); } let port = ip[1]; let ip = ip[0]; let workers = available_parallelism().unwrap().get(); let threadpool = ThreadPool::new(workers); println!( "\x1b[34m⚙ Configuration\x1b[0m >> \x1b[34mIp\x1b[0m: {ip} >> \x1b[34mPort\x1b[0m: {port} >> \x1b[34mWorkers\x1b[0m: {workers} \n Server has launched from {ip}:{port}. " ); PreMountConfig { address: listener, workers, threadpool, } }