use crate::{
byte::{handle_bytes, send_stream},
cache::main::init_cache,
plugin::JuriPlugin,
routing::{conversion_router, match_route, MatchRouter, Router},
Config, Response, error::ResponseAndError,
};
use async_std::{
net::{TcpListener, TcpStream},
prelude::*,
sync::Arc,
};
use colored::*;
use std::net::SocketAddr;
pub struct Server {
addr: SocketAddr,
plugins: Vec<Box<dyn JuriPlugin>>,
config: Config,
}
impl Server {
pub fn bind(addr: SocketAddr) -> Self {
Server {
addr,
plugins: vec![],
config: Config::new(),
}
}
pub fn config(mut self, config: Config) -> Self {
self.config = config;
self
}
pub fn plugin(mut self, plugin: impl JuriPlugin) -> Self {
self.plugins.push(Box::new(plugin));
self
}
pub async fn server(
self,
router: Router,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
init_cache();
let listener = TcpListener::bind(self.addr).await?;
println!(
"{}: listener port http://{} start",
"Juri".green(),
self.addr
);
let mut incoming = listener.incoming();
let router = Arc::new(conversion_router(router));
let plugins = Arc::new(self.plugins);
let config = Arc::new(self.config);
while let Some(stream) = incoming.next().await {
let stream = stream?;
let router = Arc::clone(&router);
let plugins = Arc::clone(&plugins);
let config = Arc::clone(&config);
Server::handle_stream(stream, router, plugins, config).await;
}
Ok(())
}
async fn handle_stream(
mut stream: TcpStream,
router: Arc<MatchRouter>,
plugins: Arc<Vec<Box<dyn JuriPlugin>>>,
config: Arc<Config>,
) {
loop {
let router = Arc::clone(&router);
let plugins = Arc::clone(&plugins);
let config = Arc::clone(&config);
match handle_bytes(&mut stream, &config).await {
Ok(mut request) => {
let peer_addr = stream.peer_addr().unwrap().ip();
println!(
"{}: Request {} {} {}",
"INFO".green(),
request.method,
request.path,
peer_addr
);
let mut run_plugin_number: usize = 0;
let mut plugin = plugins.iter();
let plugin_response = loop {
match plugin.next() {
Some(plugin) => {
run_plugin_number += 1;
let response = plugin.request(&mut request);
if let Some(response) = response {
break Some(response);
}
}
None => break None,
}
};
let mut response = match plugin_response {
Some(response) => response,
None => match match_route(&mut request, router) {
Some(fun) => {
let response: crate::Result<Response> = fun(&request);
match response {
Ok(response) => response,
Err(err) => match err {
ResponseAndError::Error(_) => Response::new_500(),
ResponseAndError::Response(response) => response,
},
}
}
None => Response::new_404(),
},
};
for plugin in plugins.iter().rev() {
if run_plugin_number == 0 {
break;
}
run_plugin_number -= 1;
plugin.response(&request, &mut response);
}
println!(
"{}: Response {} {} {}",
"INFO".green(),
request.method,
request.path,
response.status_code
);
send_stream(&mut stream, &config, Some(&request), &response).await;
if !request.is_keep_alive() {
break;
}
}
Err(e) => {
match e.code {
405 => {
let response = Response::new_405();
send_stream(&mut stream, &config, None, &response).await;
}
500 => {
let response = Response::new_500();
send_stream(&mut stream, &config, None, &response).await;
}
_ => {
println!("{}: {:?}", "ERROR".red(), e);
}
}
break;
}
};
}
}
}