From 0ec214423e0367ad3be21a7c9df5341da3c633c4 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Thu, 12 Apr 2018 00:04:37 +0200 Subject: [PATCH] fix(handlers): Fix chained error handling in actors This took me some time to figure out so it's useful to document in the commit message. When chaining messages from actors, the result type of a message (i.e. the actual `::Result`) is sometimes itself a `Result`. In many cases this leads to a situation where the return type of a message sending process is something like (simplified): Future, Error=actix::MailboxError> Due to the implementation of `From for ConverseError` it is possible to use `.from_err()` on these futures to convert the future's `Error` to `ConverseError`. The type `Result` apparently implements `IntoFuture`, which means that due to some trait magic that's been applied somewhere in the futures API a call to `flatten()` can "lift" the contained error if the error types match and give us a "simple" Future From that point on chaining becomes easy. --- src/handlers.rs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/handlers.rs b/src/handlers.rs index 71469deea..43e45d925 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -34,9 +34,12 @@ pub struct AppState { pub fn forum_index(state: State) -> ConverseResponse { state.db.send(ListThreads) - .and_then(move |res| state.renderer.send(IndexPage { threads: res.unwrap() })) - .from_err() - .map(|res| HttpResponse::Ok().content_type(HTML).body(res.unwrap())) + .flatten() + .and_then(move |res| state.renderer.send(IndexPage { + threads: res + }).from_err()) + .flatten() + .map(|res| HttpResponse::Ok().content_type(HTML).body(res)) .responder() } @@ -44,22 +47,20 @@ pub fn forum_index(state: State) -> ConverseResponse { pub fn forum_thread(state: State, thread_id: Path) -> ConverseResponse { let id = thread_id.into_inner(); state.db.send(GetThread(id)) - .and_then(move |res| { - let u = res.unwrap(); - state.renderer.send(ThreadPage { - thread: u.0, - posts: u.1, - }) - }) - .from_err() - .map(|res| HttpResponse::Ok().content_type(HTML).body(res.unwrap())) + .flatten() + .and_then(move |res| state.renderer.send(ThreadPage { + thread: res.0, + posts: res.1, + }).from_err()) + .flatten() + .map(|res| HttpResponse::Ok().content_type(HTML).body(res)) .responder() } /// This handler presents the user with the "New Thread" form. pub fn new_thread(state: State) -> ConverseResponse { - state.renderer.send(NewThreadPage).from_err() - .map(|res| HttpResponse::Ok().content_type(HTML).body(res.unwrap())) + state.renderer.send(NewThreadPage).flatten() + .map(|res| HttpResponse::Ok().content_type(HTML).body(res)) .responder() }