netter 0.3.1

Netter is a CLI tool for fast and easy server startup!
use http_body_util::{combinators::BoxBody, BodyExt, Empty, Full};
use hyper::{body::{self, Bytes}, header::{HeaderName, HeaderValue}, server::conn::http1, service::service_fn, Request, Response, StatusCode};
use log::{debug, trace, error};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::str::FromStr;
use derive_more::Debug;
use crate::{core::{config_parser::load_config, language::{interpreter::Interpreter, lexer::AstNode}}, state};

#[derive(Debug)]
pub struct Routes {
    method: String,
    path: String,
    response: Resp,
}

#[derive(Debug)]
pub struct Resp {
    body: String,
    headers: Vec<(String, String)>,
    status: u16,
}

#[derive(Debug)]
pub struct Server {
    addr: Vec<u16>,
    port: u16,
    routes: Vec<Routes>,
    #[debug(skip)]
    interpreter: Option<Arc<Mutex<Interpreter>>>,
}

#[allow(dead_code)]
pub trait HTTP {
    fn new(addr: Vec<u16>, port: u16, routes: Routes) -> Self;
    async fn start(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
}

#[derive(Serialize, Deserialize)]
pub struct Config {
    host: String,
    port: u16,
    routes: Vec<RouteConfig>,
}

#[derive(Serialize, Deserialize)]
pub struct RouteConfig {
    method: String,
    path: String,
    response: RespConfig,
}

#[derive(Serialize, Deserialize)]
pub struct RespConfig {
    body: String,
    headers: Vec<(String, String)>,
    status: u16,
}

impl Server {
    pub fn configure(file_path: &str) -> Result<Self, Box<dyn std::error::Error>> {
        debug!("Read config data");

        let config = load_config(file_path)?;

        let routes = config.routes.into_iter().map(|route| Routes {
            method: route.method,
            path: route.path,
            response: Resp {
                body: route.response.body,
                headers: route.response.headers,
                status: route.response.status,
            },
        }).collect();

        Ok(Server {
            addr: config.host.split('.')
                .map(|s| s.parse::<u16>().unwrap_or(127))
                .collect(),
            port: config.port,
            routes,
            interpreter: None,
        })
    }

    pub fn from_interpreter(
        addr: Vec<u16>, 
        port: u16, 
        interpreter: Interpreter
    ) -> Self {
        Server {
            addr,
            port,
            routes: Vec::new(),
            interpreter: Some(Arc::new(Mutex::new(interpreter))),
        }
    }

    pub fn from_ast(
        addr: Vec<u16>, 
        port: u16, 
        ast: &AstNode
    ) -> Result<Self, String> {
        let mut interpreter = Interpreter::new();
        interpreter.interpret(ast)?;
        
        Ok(Server::from_interpreter(addr, port, interpreter))
    }
}

async fn handler(
    req: Request<body::Incoming>,
    server_state: Arc<Mutex<Server>>
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, hyper::Error> {
    let server = server_state.lock().unwrap();
    
    if let Some(interpreter) = &server.interpreter {
        let method = req.method().as_str().to_string();
        let path = req.uri().path().to_string();
        
        let params = HashMap::new();
        
        let response_obj = crate::core::language::interpreter::handle_request(
            &interpreter.lock().unwrap(),
            &method,
            &path,
            params
        );
        
        let mut response = Response::new(full(response_obj.body.unwrap_or_default()));
        *response.status_mut() = StatusCode::from_u16(response_obj.status).unwrap_or(StatusCode::OK);
        
        for (key, value) in &response_obj.headers {
            if let Ok(header_name) = HeaderName::from_str(key) {
                if let Ok(header_value) = HeaderValue::from_str(value) {
                    response.headers_mut().insert(header_name, header_value);
                }
            }
        }
        
        return Ok(response);
    }
    
    for route in &server.routes {
        if req.method().as_str() == route.method && req.uri().path() == route.path {
            let mut response = Response::new(full(route.response.body.clone()));
            *response.status_mut() = StatusCode::from_u16(route.response.status).unwrap_or(StatusCode::OK);
            for (key, value) in &route.response.headers {
                if let Ok(header_name) = HeaderName::from_str(key) {
                    if let Ok(header_value) = HeaderValue::from_str(value) {
                        response.headers_mut().insert(header_name, header_value);
                    }
                }
            }
            return Ok(response);
        }
    }

    let mut not_found = Response::new(empty());
    *not_found.status_mut() = StatusCode::NOT_FOUND;
    Ok(not_found)
}

impl HTTP for Server {
    fn new(addr: Vec<u16>, port: u16, routes: Routes) -> Self {
        Server {
            addr,
            port,
            routes: vec![routes],
            interpreter: None,
        }
    }

    async fn start(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
        let addr = format!(
            "{}:{}",
            self.addr.iter().map(|n| n.to_string()).collect::<Vec<_>>().join("."),
            self.port
        );
        let listener = tokio::net::TcpListener::bind(&addr).await?;
        trace!("Server started on {}", addr);

        state::save_state(String::from("HTTP"), 
            self.addr.clone().iter().map(|n| n.to_string()).collect::<Vec<_>>().join("."), 
            self.port)
            .map_err(|_| "Failed to save state")?;

        let server_state = Arc::new(Mutex::new(self.clone()));
        state::load_state();

        loop {
            let (socket, _) = listener.accept().await?;
            let io = hyper_util::rt::TokioIo::new(socket);
            
            let server_clone = server_state.clone();
            
            tokio::task::spawn(async move {
                if let Err(err) = http1::Builder::new()
                    .serve_connection(io, service_fn(move |req| {
                        let server_clone = server_clone.clone();
                        async move { handler(req, server_clone).await }
                    }))
                    .await
                {
                    error!("Error serving connection: {}", err);
                }
            });
        }
    }
}

impl Clone for Server {
    fn clone(&self) -> Self {
        Server {
            addr: self.addr.clone(),
            port: self.port,
            routes: self.routes.clone(),
            interpreter: self.interpreter.clone(),
        }
    }
}

impl Clone for Routes {
    fn clone(&self) -> Self {
        Routes {
            method: self.method.clone(),
            path: self.path.clone(),
            response: self.response.clone(),
        }
    }
}

impl Clone for Resp {
    fn clone(&self) -> Self {
        Resp {
            body: self.body.clone(),
            headers: self.headers.clone(),
            status: self.status,
        }
    }
}

fn empty() -> BoxBody<Bytes, hyper::Error> {
    Empty::<Bytes>::new()
        .map_err(|never| match never {})
        .boxed()
}

fn full<T: Into<Bytes>>(chunk: T) -> BoxBody<Bytes, hyper::Error> {
    Full::new(chunk.into())
        .map_err(|never| match never {})
        .boxed()
}