Hello everyone, I am new to Rust and I've been following the Rust Book practicing for a while now.
After that I've decided that as training I would create a small HTTP web server inspired on Middleware approach same as Express.js (I am mostly a Node.js developer).
So in the same book there is a little tutorial on creating a Multithreaded Web Server, so I have been following that, and started to implement the middleware functionality, for this, I have this struct for my handlers:
pub struct Handler {
method: RequestMethods,
path: String,
handler: Box<dyn FnOnce()>,
}
RequestMethods
in this case is just an enum (GET, POST, PUT,...), and the handler is the closure that I want to execute when we are on a given path and with a given method
All of these handlers live inside a Vec which is inside a server struct:
pub struct Server {
pub host: String,
pub port: u16,
pool_size: usize,
handlers: Vec<Handler>,
}
Inside the Server struct I have a listen function which basically creates threads for every request, to a maximum amount of N threads:
pub fn listen<F>(&self, f: F) where F: FnOnce(&String) {
let addr = &format!("{}{}{}", self.host, ":", self.port);
let listener = TcpListener::bind(addr).unwrap();
let pool = ThreadPool::new(self.pool_size);
f(&addr);
let handlers = Arc::new(Mutex::new(self.handlers));
for stream in listener.incoming() {
let clone = handlers.clone();
pool.execute(|| { // (dyn std::ops::FnOnce() + 'static) cannot be sent between threads safely
handler(stream.unwrap());
println!("{:?}", handlers.lock().unwrap().len());
});
}
}
Problem is that inside of the pool.execute closure I need to have access to the handlers, so I can call them depending on the condition (my handler
function is not part of the server class), how can I do that? I tried to create an Arc<Mutex<self.handlers>> but It wont compile giving me the error
(dyn std::ops::FnOnce() + 'static) cannot be sent between threads safely
This is the pool.execute function:
pub fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {
let job = Box::new(f);
self.sender.send(Message::NewJob(job)).unwrap();
}
I have tried with other datatypes like simple numbers or booleans and I can pass them to the closure, but I cannot do it if it is a Vec. How can I do this?
Thanks