use log::info; use std::io::{Read, Write}; use std::net::{TcpListener, TcpStream}; use std::sync::{Arc, Mutex, mpsc}; use std::{sync, thread}; static GET: &'static [u8] = b"GET / HTTP/1.1\r\n"; struct Worker { id: usize, thread: thread::JoinHandle<()>, } impl Worker { fn new(id: usize, receiver: Arc>>) -> Worker { let thread = thread::spawn(move || { loop { let job = receiver.lock().unwrap().recv().unwrap(); job(); } }); Worker { id, thread } } } pub struct ThreadPool { workers: Vec, sender: mpsc::Sender, } impl ThreadPool { /// Create a new ThreadPool /// /// # Panics /// /// The `new` function panics if the size is zero pub fn new(size: usize) -> Self { assert!(size > 0); let mut workers = Vec::with_capacity(size); let (sender, receiver) = mpsc::channel(); let receiver = Arc::new(Mutex::new(receiver)); for id in 0..size { workers.push(Worker::new(id, Arc::clone(&receiver))) } Self { workers, sender } } pub fn execute(&self, f: F) where F: FnOnce() + Send + 'static, { let job = Box::new(f); self.sender.send(job).unwrap(); } } type Job = Box; fn main() -> std::io::Result<()> { env_logger::init(); let listener = TcpListener::bind("127.0.0.1:7878")?; let pool = ThreadPool::new(4); for stream in listener.incoming() { let stream = stream?; pool.execute(|| handle_connection(stream).unwrap()); } Ok(()) } fn handle_connection(mut stream: TcpStream) -> std::io::Result<()> { let mut buffer = [0; 1024]; stream.read(&mut buffer)?; info!("Request: {}", String::from_utf8_lossy(&buffer[..])); let response = if buffer.starts_with(GET) { let contents = include_str!("hello.html"); format!( "HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}", contents.len(), contents ) } else { "HTTP/1.1 405 Method not allowed\r\n\r\n".to_string() }; stream.write(response.as_bytes())?; stream.flush()?; Ok(()) }