simple-auth/src/main.rs

100 lines
2.8 KiB
Rust

mod config;
mod jwt;
mod router;
mod stores;
use clap::Parser;
use configparser::ini::Ini;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::{TcpListener, TcpStream},
time::{timeout, Duration},
};
use crate::router::ROUTER;
use config::Config;
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
struct Cli {
/// config filepath (.ini)
config: String,
}
#[tokio::main]
async fn main() {
simple_logger::init_with_level(log::Level::Info).unwrap();
let args = Cli::parse();
let mut config = Ini::new();
match config.load(args.config) {
Ok(c) => c,
Err(e) => {
log::error!("error while loading the config file details={}", e);
std::process::exit(1);
}
};
let server_url = config.get("server", "url").unwrap_or("".to_string());
let listener = {
match TcpListener::bind(&server_url).await {
Ok(t) => {
log::info!("server is listening on '{}'", server_url);
t
}
Err(e) => {
log::error!("while initializing tcp listener details={}", e);
std::process::exit(1);
}
}
};
let router_config: Config = {
match Config::try_from(config) {
Ok(c) => c,
Err(e) => {
log::error!("unable to load the configuration details={}", e);
std::process::exit(1);
}
}
};
loop {
let (stream, addr) = listener.accept().await.unwrap();
let conf = router_config.clone();
tokio::spawn(handle_connection(stream, addr.to_string(), conf.clone()));
}
}
/// parses the incoming request (partial spec implementation) and build an HTTP response
async fn handle_connection(mut stream: TcpStream, addr: String, config: Config) {
log::info!("client connected: {}", addr);
let mut message = vec![];
let mut buffer: [u8; 1024] = [0; 1024];
let duration = Duration::from_millis(5);
// loop until the message is read
// the stream can be fragmented so, using a timeout (5ms should be far enough) for the future for completion
// after the timeout, the message is "considered" as entirely read
loop {
match timeout(duration, stream.read(&mut buffer)).await {
Ok(v) => {
let n = v.unwrap();
message.extend_from_slice(&buffer[0..n]);
}
Err(_e) => break,
}
}
let request_string = std::str::from_utf8(&message).unwrap();
let response = ROUTER.route(request_string, config).await;
let response_str: String = response.into();
stream.write(response_str.as_bytes()).await.unwrap();
stream.flush().await.unwrap();
log::info!("connection closed: {}", addr);
}