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…
	
	Add table
		Add a link
		
	
		Reference in a new issue