refactor(handlers): Use rendering actor for page renders
This currently breaks error handling in page render flows. To fix it properly, the database actor should return failable futures instead of `Result<T>` wrapped in a future.
This commit is contained in:
parent
fe7e5e48b5
commit
1cce37446b
2 changed files with 31 additions and 46 deletions
|
@ -5,7 +5,7 @@
|
|||
//! the tera templates stored in the `/templates` directory in the
|
||||
//! project root.
|
||||
|
||||
use actix::prelude::{Addr, Syn};
|
||||
use actix::prelude::*;
|
||||
use actix_web;
|
||||
use actix_web::*;
|
||||
use actix_web::middleware::{Started, Middleware, RequestSession};
|
||||
|
@ -15,9 +15,12 @@ use futures::Future;
|
|||
use models::*;
|
||||
use oidc::*;
|
||||
use tera;
|
||||
use render::*;
|
||||
|
||||
type ConverseResponse = Box<Future<Item=HttpResponse, Error=ConverseError>>;
|
||||
|
||||
const HTML: &'static str = "text/html";
|
||||
|
||||
/// Represents the state carried by the web server actors.
|
||||
pub struct AppState {
|
||||
/// Address of the database actor
|
||||
|
@ -26,68 +29,47 @@ pub struct AppState {
|
|||
/// Address of the OIDC actor
|
||||
pub oidc: Addr<Syn, OidcExecutor>,
|
||||
|
||||
/// Compiled templates
|
||||
pub tera: tera::Tera,
|
||||
/// Address of the rendering actor
|
||||
pub renderer: Addr<Syn, Renderer>,
|
||||
}
|
||||
|
||||
/// This function renders an overview of threads into the default
|
||||
/// thread list template.
|
||||
fn render_threads(tpl: &tera::Tera, threads: Vec<Thread>) -> Result<HttpResponse> {
|
||||
let mut ctx = tera::Context::new();
|
||||
ctx.add("threads", &threads);
|
||||
let body = tpl.render("index.html", &ctx)?;
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(body))
|
||||
}
|
||||
// impl AppState {
|
||||
// fn render_ok<M>(self, msg: M) -> ConverseResponse
|
||||
// where M: Send + Message, Renderer: Handler<M> {
|
||||
// self.renderer.send(msg);
|
||||
// unimplemented!()
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn forum_index(state: State<AppState>) -> ConverseResponse {
|
||||
state.db.send(ListThreads)
|
||||
.and_then(move |res| state.renderer.send(IndexPage { threads: res.unwrap() }))
|
||||
.from_err()
|
||||
.and_then(move |res| match res {
|
||||
Ok(threads) => Ok(render_threads(&state.tera, threads)?),
|
||||
Err(err) => {
|
||||
error!("Error loading threads: {}", err);
|
||||
Ok(HttpResponse::InternalServerError().into())
|
||||
}
|
||||
})
|
||||
.map(|res| HttpResponse::Ok().content_type(HTML).body(res.unwrap()))
|
||||
.responder()
|
||||
}
|
||||
|
||||
/// This function renders a single forum thread into the default
|
||||
/// thread view.
|
||||
fn render_thread(tpl: &tera::Tera, thread: Thread, posts: Vec<Post>)
|
||||
-> Result<HttpResponse> {
|
||||
let mut ctx = tera::Context::new();
|
||||
ctx.add("thread", &thread);
|
||||
ctx.add("posts", &posts);
|
||||
|
||||
let body = tpl.render("thread.html", &ctx)?;
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("text/html")
|
||||
.body(body))
|
||||
}
|
||||
|
||||
/// This handler retrieves and displays a single forum thread.
|
||||
pub fn forum_thread(state: State<AppState>, thread_id: Path<i32>) -> ConverseResponse {
|
||||
let id = thread_id.into_inner();
|
||||
state.db.send(GetThread(id))
|
||||
.from_err()
|
||||
.and_then(move |res| match res {
|
||||
Ok((thread, posts)) => Ok(render_thread(&state.tera, thread, posts)?),
|
||||
Err(err) => {
|
||||
error!("Error loading thread {}: {}", id, err);
|
||||
Ok(HttpResponse::InternalServerError().into())
|
||||
}
|
||||
.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()))
|
||||
.responder()
|
||||
}
|
||||
|
||||
/// This handler presents the user with the "New Thread" form.
|
||||
pub fn new_thread(state: State<AppState>) -> Result<HttpResponse> {
|
||||
let ctx = tera::Context::new();
|
||||
let body = state.tera.render("new-thread.html", &ctx)?;
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("text/html")
|
||||
.body(body))
|
||||
pub fn new_thread(state: State<AppState>) -> ConverseResponse {
|
||||
state.renderer.send(NewThreadPage).from_err()
|
||||
.map(|res| HttpResponse::Ok().content_type(HTML).body(res.unwrap()))
|
||||
.responder()
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
|
5
todo.org
5
todo.org
|
@ -1,4 +1,7 @@
|
|||
* DONE Pin *-versions in cargo.toml
|
||||
* TODO Configurable number of DB workers
|
||||
* TODO Pin *-versions in cargo.toml
|
||||
* TODO Match certain types of Diesel errors (esp. for "not found")
|
||||
* TODO Sketch out categories vs. tags system
|
||||
* TODO Markdown support
|
||||
* TODO Quote button
|
||||
* TODO Multiquote buttons
|
||||
|
|
Loading…
Reference in a new issue