use std::fmt; use std::marker::PhantomData; use actix_codec::{AsyncRead, AsyncWrite}; use actix_http::{http::Method, Error}; use actix_service::{NewService, Service}; use futures::future::{ok, FutureResult}; use futures::{Async, Future, IntoFuture, Poll}; use log::error; use crate::app::HttpServiceFactory; use crate::request::FramedRequest; /// Resource route definition /// /// Route uses builder-like pattern for configuration. /// If handler is not explicitly set, default *404 Not Found* handler is used. pub struct FramedRoute { handler: F, pattern: String, methods: Vec, state: PhantomData<(Io, S, R)>, } impl FramedRoute { pub fn build(path: &str) -> FramedRouteBuilder { FramedRouteBuilder::new(path) } pub fn get(path: &str) -> FramedRouteBuilder { FramedRouteBuilder::new(path).method(Method::GET) } pub fn post(path: &str) -> FramedRouteBuilder { FramedRouteBuilder::new(path).method(Method::POST) } pub fn put(path: &str) -> FramedRouteBuilder { FramedRouteBuilder::new(path).method(Method::PUT) } pub fn delete(path: &str) -> FramedRouteBuilder { FramedRouteBuilder::new(path).method(Method::DELETE) } } impl FramedRoute where F: FnMut(FramedRequest) -> R + Clone, R: IntoFuture, R::Future: 'static, R::Error: fmt::Display, { pub fn new(pattern: &str, handler: F) -> Self { FramedRoute { handler, pattern: pattern.to_string(), methods: Vec::new(), state: PhantomData, } } pub fn method(mut self, method: Method) -> Self { self.methods.push(method); self } } impl HttpServiceFactory for FramedRoute where Io: AsyncRead + AsyncWrite + 'static, F: FnMut(FramedRequest) -> R + Clone, R: IntoFuture, R::Future: 'static, R::Error: fmt::Display, { type Factory = FramedRouteFactory; fn path(&self) -> &str { &self.pattern } fn create(self) -> Self::Factory { FramedRouteFactory { handler: self.handler, methods: self.methods, _t: PhantomData, } } } pub struct FramedRouteFactory { handler: F, methods: Vec, _t: PhantomData<(Io, S, R)>, } impl NewService for FramedRouteFactory where Io: AsyncRead + AsyncWrite + 'static, F: FnMut(FramedRequest) -> R + Clone, R: IntoFuture, R::Future: 'static, R::Error: fmt::Display, { type Request = FramedRequest; type Response = (); type Error = Error; type InitError = (); type Service = FramedRouteService; type Future = FutureResult; fn new_service(&self, _: &()) -> Self::Future { ok(FramedRouteService { handler: self.handler.clone(), methods: self.methods.clone(), _t: PhantomData, }) } } pub struct FramedRouteService { handler: F, methods: Vec, _t: PhantomData<(Io, S, R)>, } impl Service for FramedRouteService where Io: AsyncRead + AsyncWrite + 'static, F: FnMut(FramedRequest) -> R + Clone, R: IntoFuture, R::Future: 'static, R::Error: fmt::Display, { type Request = FramedRequest; type Response = (); type Error = Error; type Future = Box>; fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } fn call(&mut self, req: FramedRequest) -> Self::Future { Box::new((self.handler)(req).into_future().then(|res| { if let Err(e) = res { error!("Error in request handler: {}", e); } Ok(()) })) } } pub struct FramedRouteBuilder { pattern: String, methods: Vec, state: PhantomData<(Io, S)>, } impl FramedRouteBuilder { fn new(path: &str) -> FramedRouteBuilder { FramedRouteBuilder { pattern: path.to_string(), methods: Vec::new(), state: PhantomData, } } pub fn method(mut self, method: Method) -> Self { self.methods.push(method); self } pub fn to(self, handler: F) -> FramedRoute where F: FnMut(FramedRequest) -> R, R: IntoFuture, R::Future: 'static, R::Error: fmt::Debug, { FramedRoute { handler, pattern: self.pattern, methods: self.methods, state: PhantomData, } } }