From 813b56ebe59224012210f560dd1a8b4cf592d04a Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 20 Dec 2017 12:51:39 -0800 Subject: [PATCH] make async handler future more generic --- guide/src/qs_4.md | 10 ++++++++-- src/handler.rs | 47 ++++++++++++++++++++++++++++++++--------------- src/route.rs | 10 +++++----- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/guide/src/qs_4.md b/guide/src/qs_4.md index 25528c45..dda86e27 100644 --- a/guide/src/qs_4.md +++ b/guide/src/qs_4.md @@ -95,8 +95,9 @@ fn main() { There are two different types of async handlers. -Response object could be generated asynchronously. In this case handle must -return `Future` object that resolves to `HttpResponse`, i.e: +Response object could be generated asynchronously or more precisely, any type +that implements [*Responder*](../actix_web/trait.Responder.html) trait. In this case handle must +return `Future` object that resolves to *Responder* type, i.e: ```rust # extern crate actix_web; @@ -114,9 +115,14 @@ fn index(req: HttpRequest) -> FutureResult { .map_err(|e| e.into())) } +fn index2(req: HttpRequest) -> FutureResult<&'static str, Error> { + result(Ok("Welcome!")) +} + fn main() { Application::new() .resource("/async", |r| r.route().a(index)) + .resource("/", |r| r.route().a(index2)) .finish(); } ``` diff --git a/src/handler.rs b/src/handler.rs index f0fbb1ea..2293d909 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; use actix::Actor; -use futures::Future; +use futures::future::{Future, ok, err}; use serde_json; use serde::Serialize; use regex::Regex; @@ -221,36 +221,53 @@ impl RouteHandler for WrapHandler /// Async route handler pub(crate) -struct AsyncHandler - where F: Fn(HttpRequest) -> R + 'static, - R: Future + 'static, +struct AsyncHandler + where H: Fn(HttpRequest) -> F + 'static, + F: Future + 'static, + R: Responder + 'static, + E: Into + 'static, S: 'static, { - f: Box, + h: Box, s: PhantomData, } -impl AsyncHandler - where F: Fn(HttpRequest) -> R + 'static, - R: Future + 'static, +impl AsyncHandler + where H: Fn(HttpRequest) -> F + 'static, + F: Future + 'static, + R: Responder + 'static, + E: Into + 'static, S: 'static, { - pub fn new(f: F) -> Self { - AsyncHandler{f: Box::new(f), s: PhantomData} + pub fn new(h: H) -> Self { + AsyncHandler{h: Box::new(h), s: PhantomData} } } -impl RouteHandler for AsyncHandler - where F: Fn(HttpRequest) -> R + 'static, - R: Future + 'static, +impl RouteHandler for AsyncHandler + where H: Fn(HttpRequest) -> F + 'static, + F: Future + 'static, + R: Responder + 'static, + E: Into + 'static, S: 'static, { fn handle(&self, req: HttpRequest) -> Reply { - Reply::async((self.f)(req)) + let req2 = req.clone_without_state(); + let fut = (self.h)(req) + .map_err(|e| e.into()) + .then(move |r| { + match r.respond_to(req2) { + Ok(reply) => match reply.into().0 { + ReplyItem::Message(resp) => ok(resp), + _ => panic!("Nested async replies are not supported"), + } + Err(e) => err(e), + } + }); + Reply::async(fut) } } - /// Json response helper /// /// The `Json` type allows you to respond with well-formed JSON data: simply return a value of diff --git a/src/route.rs b/src/route.rs index 284daaf6..194a1c06 100644 --- a/src/route.rs +++ b/src/route.rs @@ -5,8 +5,6 @@ use pred::Predicate; use handler::{Reply, Handler, Responder, RouteHandler, AsyncHandler, WrapHandler}; use httpcodes::HTTPNotFound; use httprequest::HttpRequest; -use httpresponse::HttpResponse; - /// Resource route definition /// @@ -80,9 +78,11 @@ impl Route { } /// Set async handler function. - pub fn a(&mut self, handler: F) - where F: Fn(HttpRequest) -> R + 'static, - R: Future + 'static, + pub fn a(&mut self, handler: H) + where H: Fn(HttpRequest) -> F + 'static, + F: Future + 'static, + R: Responder + 'static, + E: Into + 'static { self.handler = Box::new(AsyncHandler::new(handler)); }