http-server-rs 0.1.17

HTTP server implementation in Rust without any dependencies, design inspired by Java's com.sun.net.httpserver.HttpServer
Documentation
use std::{collections::BTreeMap, io::Error, net::{TcpListener, TcpStream, ToSocketAddrs}, sync::{Arc, Mutex}};

use crate::{executor::Executor, httpreader::HttpReader};


pub struct HttpServer<T : Executor>
{
    listener : Option<TcpListener>,
    handler : BTreeMap<String, HttpHandlerWrap>,
    started : bool,
    executor : T,
    max_client_timeout_ms : u64,
}

impl<T : Executor> HttpServer<T>

{
    
    pub fn new(max_client_timeout_ms : u64, executor : T) -> Self {
        let server : HttpServer<T> = HttpServer {
            listener : Option::None,
            handler : BTreeMap::new(),
            started : false,
            executor,
            max_client_timeout_ms,
        };
        return server;
    }
    
    pub fn add_endpoint<F>(&mut self, path : &str, handler : F) 
    where F : Sized + FnMut(HttpReader) + Send + Sync + 'static {
        let value = Arc::new(Mutex::new(handler));
        self.handler.insert(String::from(path), value);
    }
    
    pub fn init_listener<SA : ToSocketAddrs>(&mut self, socket_address : SA) -> Result<TcpListener, Error> {
        let listener = TcpListener::bind(socket_address);
        if listener.is_err() {
            return Result::Err(listener.unwrap_err());
        } else {
            let l = listener.unwrap();
            let result : Result<TcpListener, Error> = Result::Ok(l.try_clone().unwrap());
            self.listener = Option::Some(l);
            return result;
        }
    }
    
    pub fn start<SA : ToSocketAddrs>(&mut self, socket_address : SA) -> Result<bool, Error> {
        if self.listener.is_none() {
            let init = self.init_listener(socket_address);
            if init.is_err() {
                return Result::Err(init.unwrap_err());
            }
        }
        
        if !self.started {        
            self.started = true;
            let listener_copy : &TcpListener = self.listener.as_ref().unwrap();
            let max_client_timeout_ms = self.max_client_timeout_ms;
            let map_copy = self.handler.clone();
            for tcpstream in listener_copy.incoming() {
                let map_copy_copy = map_copy.clone();
                self.executor.execute_mut(move || {
                    if tcpstream.is_ok() {
                        HttpServer::<T>::handle_connection(tcpstream.unwrap(), map_copy_copy, max_client_timeout_ms);
                    }
                });
            }
        }
        
        return Result::Ok(true);
    }
    
    fn handle_connection(tcpstream : TcpStream, mut handler_map : BTreeMap<String, HttpHandlerWrap>, max_client_timeout_ms : u64) {
        let pre_check_http_reader = HttpReader::new(tcpstream, max_client_timeout_ms);
        if pre_check_http_reader.is_ok() {
            let http_reader = pre_check_http_reader.unwrap();
            let handler = handler_map.get_mut(&http_reader.get_request_path());
            if handler.is_none() {
                let fallback_key = &String::from("*");
                let fallback = handler_map.get_mut(fallback_key);
                if fallback.is_some() {
                    let mut unwrapped = fallback.unwrap().lock().unwrap();
                    (unwrapped)(http_reader);
                } else {
                    http_reader.respond_404();
                }
            } else {
                let mut unwrapped = handler.unwrap().lock().unwrap();
                (unwrapped)(http_reader);
            }
        }
    }
    
}

type HttpHandler = dyn FnMut(HttpReader) + Send + Sync;
type HttpHandlerWrap = Arc<Mutex<HttpHandler>>;