httpageboy/
server_base.rs

1use std::collections::HashMap;
2use std::io::prelude::Write;
3use std::net::{TcpListener, TcpStream};
4use std::sync::{Arc, Mutex};
5
6pub use crate::threadpool::ThreadPool;
7pub use crate::request_type::Rt;
8pub use crate::request_handler::Rh;
9use crate::request::{ Request, stream_to_request, handle_request};
10use crate::response::Response;
11use crate::utils::absolutize_path;
12
13
14pub struct ServerBase {
15	listener: TcpListener,
16	pool: Arc<Mutex<ThreadPool>>,
17	routes: HashMap<String, Rh>,
18	files_sources: Vec<String>
19}
20
21impl ServerBase {
22	pub fn new(
23			serving_url: &str,
24			pool_size: u8,
25			routes_list: Option<HashMap<String, Rh>>)
26			-> Result<ServerBase, std::io::Error>{
27  	let listener = TcpListener::bind(serving_url)?;
28		let pool = Arc::new(Mutex::new(ThreadPool::new(pool_size as usize)));
29		let routes: HashMap<String, Rh>;
30
31		if let Some(routes_list) = routes_list {
32			routes = routes_list;
33		}
34		else {
35			routes = HashMap::new();
36		}
37
38		return Ok(ServerBase {
39			listener,
40			routes,
41			pool,
42			files_sources: Vec::new()
43		});
44	}
45
46	pub fn add_route(&mut self, path: &str, rt: Rt, rh: fn(&Request) -> Response) {
47		let key = format!("{}|{}", path, rt.to_string());
48		let handler = Rh { handler: rh};
49		self.routes.insert(key, handler);
50	}
51
52	pub fn add_files_source(&mut self, path: String) {
53		let local_path = absolutize_path(&path);
54		self.files_sources.push(local_path);
55	}
56
57	pub fn run (&self) {
58		for stream in self.listener.incoming(){
59			match stream {
60				Ok(stream) => {
61					let routes_local = self.routes.clone();
62					let sources_local = self.files_sources.clone();
63					let pool = Arc::clone(&self.pool);
64					pool.lock().unwrap().run(move || {
65						let request: Request = stream_to_request(&stream);
66						let answer: Option<Response> = handle_request(&request, &routes_local, &sources_local);
67						match answer {
68							Some(response) => {
69								send_response(stream, &response);
70							}
71							None => {
72								send_response(stream, &Response::new());
73							}
74						}
75					});
76				}
77				Err(err) => {
78					println!("Error: {}", err);
79				}
80			}
81		}
82	}
83
84	pub fn stop(&self) {
85		let mut pool = self.pool.lock().unwrap();
86		println!("server_base stop");
87		pool.stop();
88	}
89}
90
91fn send_response(mut stream: TcpStream, response: &Response) {
92	let header = format!(
93		"HTTP/1.1 {}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n",
94		response.status,
95		response.content_type,
96		response.content.len()
97	);
98	stream.write(header.as_bytes()).unwrap();
99	if response.content_type.starts_with("image/") {
100		stream.write(&response.content).unwrap();
101	}
102	else {
103		stream.write(String::from_utf8_lossy(&response.content).as_bytes()).unwrap();
104	}
105	stream.flush().unwrap();
106}