setup.rs 3.50 KiB
use std::thread::available_parallelism;
use tokio::{net::TcpListener, signal::unix::{SignalKind, signal}, select};
use crate::{
handlers::handlers::handle_connection,
handling::routes::{Route, Uri},
};
#[derive(Clone)]
pub struct MountPoint<'a> {
pub mountpoint: Uri<'a>,
pub routes: Vec<Route<'a>>,
}
pub struct Config {
mountpoints: Option<Vec<MountPoint<'static>>>,
address: TcpListener,
}
impl<'a> Config {
fn check_mountpoint_taken(&self, to_insert: Uri) -> bool {
if let Some(to_check) = &self.mountpoints {
let len = to_check.len();
for i in 0..len {
if to_check[i].mountpoint == to_insert {
return true; // Found a duplicate &str
}
}
};
false
}
pub fn mount(mut self, mountpoint: Uri<'static>, mut routes: Vec<Route<'static>>) -> Self {
if self.check_mountpoint_taken(mountpoint) {
eprintln!("\x1b[31mTrying to reassign a mountpoint, mountpoint `{mountpoint}` already taken.\x1b[0m");
return self;
}
routes.sort_by(|a, b| a.rank.cmp(&b.rank));
let mut mount_message = format!(" >> \x1b[35m{}\x1b[0m\n", mountpoint);
for (index, route) in routes.iter().enumerate() {
let indent_sign;
match index {
i if i == routes.len() - 1 => indent_sign = "└─",
_ => indent_sign = "├─",
};
mount_message += &format!(
" \x1b[35m{indent_sign}\x1b[0m \x1b[36m(\x1b[0m{}\x1b[36m)\x1b[0m \x1b[32m{}\x1b[0m \x1b[34;4m{}\x1b[24m{}\x1b[0m\n",
route.name.unwrap_or(""),
route.method,
mountpoint,
route.uri
)
}
println!("{mount_message}");
let mut temp_mountpoints = None;
std::mem::swap(&mut self.mountpoints, &mut temp_mountpoints);
if let Some(mut mountpoints) = temp_mountpoints {
mountpoints.push(MountPoint { mountpoint, routes });
self.mountpoints = Some(mountpoints);
} else {
self.mountpoints = Some(vec![MountPoint { mountpoint, routes }]);
}
self
}
pub async fn launch(self) {
println!("Server launched from http://{}", self.address.local_addr().unwrap());
let mut sigint = signal(SignalKind::interrupt()).unwrap();
loop {
select! {
_ = sigint.recv() => {
println!("Shutting down...");
break;
}
Ok((socket, _)) = self.address.accept() => {
let mountpoints = self.mountpoints.clone().unwrap();
tokio::spawn(async move { handle_connection(socket, mountpoints).await; });
}
}
}
}
}
pub async fn build(ip: &str) -> Config {
let listener = if let Ok(listener) = TcpListener::bind(ip).await {
listener
} else {
panic!("\x1b[31mCould't bind Listener to address\x1b[0m");
};
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();
println!(
"\x1b[34m⚙ Configuration\x1b[0m
>> \x1b[34mIp\x1b[0m: {ip}
>> \x1b[34mPort\x1b[0m: {port}
>> \x1b[34mWorkers\x1b[0m: {workers}
\x1b[35m🛪 Mountpoints\x1b[0m"
);
Config {
mountpoints: None,
address: listener,
}
}