use std::mem; use std::rc::Rc; use std::marker::PhantomData; use std::collections::HashMap; use actix::Actor; use bytes::Bytes; use http::Method; use task::Task; use route::{Route, Payload, RouteHandler}; use context::HttpContext; use httpcodes::HTTPMethodNotAllowed; use httpmessage::{HttpRequest, HttpMessage, IntoHttpMessage}; /// Resource pub struct HttpResource { state: PhantomData, routes: HashMap>>, default: Box>, } impl Default for HttpResource { fn default() -> Self { HttpResource { state: PhantomData, routes: HashMap::new(), default: Box::new(HTTPMethodNotAllowed)} } } impl HttpResource where S: 'static { pub fn handler(&mut self, method: Method, handler: H) -> &mut Self where H: RouteHandler { self.routes.insert(method, Box::new(handler)); self } pub fn default_handler(&mut self, handler: H) -> &mut Self where H: RouteHandler { self.default = Box::new(handler); self } pub fn get(&mut self) -> &mut Self where A: Route { self.handler(Method::GET, A::factory()) } pub fn post(&mut self) -> &mut Self where A: Route { self.handler(Method::POST, A::factory()) } pub fn put(&mut self) -> &mut Self where A: Route { self.handler(Method::PUT, A::factory()) } pub fn delete(&mut self) -> &mut Self where A: Route { self.handler(Method::DELETE, A::factory()) } } impl RouteHandler for HttpResource { fn handle(&self, req: HttpRequest, payload: Option, state: Rc) -> Task { if let Some(handler) = self.routes.get(req.method()) { handler.handle(req, payload, state) } else { self.default.handle(req, payload, state) } } } #[cfg_attr(feature="cargo-clippy", allow(large_enum_variant))] enum HttpResponseItem where A: Actor> + Route { Message(HttpMessage, Option), Actor(A), } pub struct HttpResponse> + Route> (HttpResponseItem); impl HttpResponse where A: Actor> + Route { /// Create async response #[allow(non_snake_case)] pub fn Stream(act: A) -> Self { HttpResponse(HttpResponseItem::Actor(act)) } #[allow(non_snake_case)] pub fn Reply(req: HttpRequest, msg: I) -> Self where I: IntoHttpMessage { HttpResponse(HttpResponseItem::Message(msg.into_response(req), None)) } #[allow(non_snake_case)] pub fn ReplyMessage(msg: HttpMessage, body: Option) -> Self { HttpResponse(HttpResponseItem::Message(msg, body)) } pub(crate) fn into(self, mut ctx: HttpContext) -> Task { match self.0 { HttpResponseItem::Message(msg, body) => Task::reply(msg, body), HttpResponseItem::Actor(act) => { let old = ctx.replace_actor(act); mem::forget(old); Task::with_stream(ctx) } } } }