use std::fmt;
use std::sync::Arc;
use std::collections::HashMap;
use std::time::Duration;
use hyper::Server as HyperServer;
use futures_cpupool::CpuPool;
use crate::{Context, Handler, Protocol, Catcher};
use crate::http::{self, StatusCode, Request, Response, Mime};
use crate::http::headers::SET_COOKIE;
use crate::catcher;
use std::net::{SocketAddr, ToSocketAddrs};
use futures::{future, Future};
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Timeouts {
pub keep_alive: Option<Duration>,
}
impl Default for Timeouts {
fn default() -> Self {
Timeouts {
keep_alive: Some(Duration::from_secs(5)),
}
}
}
pub struct Server<H: Handler> {
pub handler: Arc<H>,
pub config: Arc<ServerConfig>
}
pub struct ServerConfig{
pub timeouts: Timeouts,
pub pool: CpuPool,
pub protocol: Protocol,
pub local_addr: Option<SocketAddr>,
pub catchers: Arc<Vec<Box<dyn Catcher>>>,
pub media_types: Arc<HashMap<String, Mime>>,
}
impl ServerConfig {
pub fn new()->ServerConfig{
ServerConfig{
protocol: Protocol::http(),
local_addr: None,
timeouts: Timeouts::default(),
pool: CpuPool::new_num_cpus(),
catchers: Arc::new(catcher::defaults::get()),
media_types: Arc::new(http::media_type::defaults::get()),
}
}
}
impl Default for ServerConfig {
fn default() -> Self {
ServerConfig::new()
}
}
impl<H: Handler> Server<H> {
pub fn new(handler: H)->Server<H>{
let config = ServerConfig::default();
Server{
handler: Arc::new(handler),
config: Arc::new(config),
}
}
pub fn with_config(handler: H, config: ServerConfig)->Server<H> {
Server{
handler: Arc::new(handler),
config: Arc::new(config),
}
}
pub fn serve<A>(mut self, addr: A) where A: ToSocketAddrs{
let addr: SocketAddr = addr.to_socket_addrs().unwrap().next().unwrap();
Arc::get_mut(&mut self.config).unwrap().local_addr = Some(addr);
let server = HyperServer::bind(&addr)
.tcp_keepalive(self.config.timeouts.keep_alive)
.serve(self).map_err(|e| eprintln!("server error: {}", e));
println!("Server running: {}", addr);
hyper::rt::run(server);
}
}
impl<H: Handler> hyper::service::NewService for Server<H> {
type ReqBody = hyper::body::Body;
type ResBody = hyper::body::Body;
type Error = hyper::Error;
type Service = HyperHandler<H>;
type InitError = hyper::Error;
type Future = future::FutureResult<Self::Service, Self::InitError>;
fn new_service(&self) -> Self::Future {
future::ok(HyperHandler {
handler: self.handler.clone(),
server_config: self.config.clone(),
})
}
}
pub struct HyperHandler<H: Handler> {
handler: Arc<H>,
server_config: Arc<ServerConfig>,
}
impl<H: Handler> hyper::service::Service for HyperHandler<H>{
type ReqBody = hyper::body::Body;
type ResBody = hyper::body::Body;
type Error = hyper::Error;
type Future = Box<dyn Future<Item = hyper::Response<Self::ResBody>, Error = Self::Error> + Send>;
fn call(&mut self, req: hyper::Request<Self::ReqBody>) -> Self::Future {
let handler = self.handler.clone();
let sconfig = self.server_config.clone();
let pool = sconfig.pool.clone();
let local_addr = sconfig.local_addr.clone();
let protocol = sconfig.protocol.clone();
let catchers = sconfig.catchers.clone();
Box::new(pool.spawn_fn(move || {
let mut ctx = Context::new(sconfig, Request::from_hyper(req, local_addr, &protocol).unwrap(), Response::new());
handler.handle(&mut ctx);
if !ctx.is_commited() {
ctx.commit();
}
let mut response = hyper::Response::<hyper::Body>::new(hyper::Body::empty());
if let None = ctx.response.status{
if ctx.response.body_writers.len() == 0 {
ctx.response.status = Some(StatusCode::NOT_FOUND);
}else {
ctx.response.status = Some(StatusCode::OK);
}
}
let status = ctx.response.status.unwrap();
if ctx.response.body_writers.len() == 0 && (status.as_str().starts_with('4') || status.as_str().starts_with('5')) {
for catcher in &*catchers {
if catcher.catch(&ctx.request, &mut ctx.response){
break;
}
}
}
for cookie in ctx.cookies.delta() {
if let Ok(hv) = cookie.encoded().to_string().parse(){
response.headers_mut().append(SET_COOKIE, hv);
}
}
ctx.response.write_back(&mut response, ctx.request.method().clone());
future::ok(response)
}))
}
}