add simple error response rendering
we don't really need anything pretty here since 99% of the time, the error's that would be generated during a request will be something to do with tera template rendering and thus, are probably only going to be experienced while fiddling with the site. so we just want to display the error details and move on. the vast majority (if not all) of other errors will occuring during startup and content reloading, and thus we only really need to worry about them being logged to the console (which they are already)
This commit is contained in:
parent
c7665fdc79
commit
3427b954ed
11
src/main.rs
11
src/main.rs
|
@ -41,12 +41,15 @@ async fn rss_feed(data: web::Data<site::SiteService>) -> impl Responder {
|
||||||
data.serve_rss_feed()
|
data.serve_rss_feed()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn site_content(req: HttpRequest, data: web::Data<site::SiteService>) -> Either<HttpResponse, Redirect> {
|
async fn site_content(
|
||||||
|
req: HttpRequest,
|
||||||
|
data: web::Data<site::SiteService>,
|
||||||
|
) -> Result<Either<HttpResponse, Redirect>, site::SiteError> {
|
||||||
log::debug!("GET {} -> fallback to site_content()", req.path());
|
log::debug!("GET {} -> fallback to site_content()", req.path());
|
||||||
if let Some(response) = data.serve_content_by_url(&req) {
|
if let Some(response) = data.serve_content_by_url(&req)? {
|
||||||
response
|
Ok(response)
|
||||||
} else {
|
} else {
|
||||||
Either::Left(not_found())
|
Ok(Either::Left(not_found()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
41
src/site.rs
41
src/site.rs
|
@ -3,6 +3,8 @@ use std::ops::Deref;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
|
|
||||||
|
use actix_web::body::BoxBody;
|
||||||
|
use actix_web::http::header::ContentType;
|
||||||
use actix_web::http::StatusCode;
|
use actix_web::http::StatusCode;
|
||||||
use actix_web::web::Redirect;
|
use actix_web::web::Redirect;
|
||||||
use actix_web::{Either, HttpRequest, HttpResponse};
|
use actix_web::{Either, HttpRequest, HttpResponse};
|
||||||
|
@ -63,6 +65,15 @@ pub enum SiteError {
|
||||||
TeraError(#[from] tera::Error),
|
TeraError(#[from] tera::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl actix_web::error::ResponseError for SiteError {
|
||||||
|
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||||
|
let status_code = self.status_code();
|
||||||
|
HttpResponse::build(status_code) //
|
||||||
|
.insert_header(ContentType::plaintext())
|
||||||
|
.body(format!("{status_code}\n\n{:#?}", self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct AlternateUrlMappings {
|
pub struct AlternateUrlMappings {
|
||||||
mapping: HashMap<UriPath, UriPath>,
|
mapping: HashMap<UriPath, UriPath>,
|
||||||
}
|
}
|
||||||
|
@ -354,34 +365,34 @@ impl SiteService {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serve_latest_post(&self) -> HttpResponse {
|
pub fn serve_latest_post(&self) -> Result<HttpResponse, SiteError> {
|
||||||
let content = self.content.read().expect("SiteContent read lock failed"); // TODO: better error handling
|
let content = self.content.read().expect("SiteContent read lock failed"); // TODO: better error handling
|
||||||
let post = content.get_latest_post();
|
let post = content.get_latest_post();
|
||||||
let mut context = tera::Context::new();
|
let mut context = tera::Context::new();
|
||||||
if let Some(post) = post {
|
if let Some(post) = post {
|
||||||
context.insert("post", post);
|
context.insert("post", post);
|
||||||
}
|
}
|
||||||
HttpResponse::Ok().body(content.template_renderer.render("latest_post.html", &context).unwrap())
|
Ok(HttpResponse::Ok().body(content.template_renderer.render("latest_post.html", &context)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serve_posts_by_tag(&self, tag: &Tag) -> HttpResponse {
|
pub fn serve_posts_by_tag(&self, tag: &Tag) -> Result<HttpResponse, SiteError> {
|
||||||
let content = self.content.read().expect("SiteContent read lock failed"); // TODO: better error handling
|
let content = self.content.read().expect("SiteContent read lock failed"); // TODO: better error handling
|
||||||
let posts = content.get_posts_with_tag_ordered_by_date(tag);
|
let posts = content.get_posts_with_tag_ordered_by_date(tag);
|
||||||
let mut context = tera::Context::new();
|
let mut context = tera::Context::new();
|
||||||
context.insert("tag", tag);
|
context.insert("tag", tag);
|
||||||
context.insert("posts", &posts);
|
context.insert("posts", &posts);
|
||||||
HttpResponse::Ok().body(content.template_renderer.render("tag.html", &context).unwrap())
|
Ok(HttpResponse::Ok().body(content.template_renderer.render("tag.html", &context)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serve_posts_archive(&self) -> HttpResponse {
|
pub fn serve_posts_archive(&self) -> Result<HttpResponse, SiteError> {
|
||||||
let content = self.content.read().expect("SiteContent read lock failed"); // TODO: better error handling
|
let content = self.content.read().expect("SiteContent read lock failed"); // TODO: better error handling
|
||||||
let posts = content.get_posts_ordered_by_date();
|
let posts = content.get_posts_ordered_by_date();
|
||||||
let mut context = tera::Context::new();
|
let mut context = tera::Context::new();
|
||||||
context.insert("posts", &posts);
|
context.insert("posts", &posts);
|
||||||
HttpResponse::Ok().body(content.template_renderer.render("archive.html", &context).unwrap())
|
Ok(HttpResponse::Ok().body(content.template_renderer.render("archive.html", &context)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serve_rss_feed(&self) -> HttpResponse {
|
pub fn serve_rss_feed(&self) -> Result<HttpResponse, SiteError> {
|
||||||
let content = self.content.read().expect("SiteContent read lock failed"); // TODO: better error handling
|
let content = self.content.read().expect("SiteContent read lock failed"); // TODO: better error handling
|
||||||
let base_url = url::Url::parse(&content.rss.url).unwrap();
|
let base_url = url::Url::parse(&content.rss.url).unwrap();
|
||||||
let posts = content.get_posts_ordered_by_date();
|
let posts = content.get_posts_ordered_by_date();
|
||||||
|
@ -404,10 +415,10 @@ impl SiteService {
|
||||||
})
|
})
|
||||||
.collect::<Vec<rss::Item>>(),
|
.collect::<Vec<rss::Item>>(),
|
||||||
);
|
);
|
||||||
HttpResponse::Ok().content_type("application/rss+xml").body(channel.to_string())
|
Ok(HttpResponse::Ok().content_type("application/rss+xml").body(channel.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serve_content_by_url(&self, req: &HttpRequest) -> Option<Either<HttpResponse, Redirect>> {
|
pub fn serve_content_by_url(&self, req: &HttpRequest) -> Result<Option<Either<HttpResponse, Redirect>>, SiteError> {
|
||||||
let content = self.content.read().expect("SiteContent read lock failed"); // TODO: better error handling
|
let content = self.content.read().expect("SiteContent read lock failed"); // TODO: better error handling
|
||||||
let url = String::from(req.path());
|
let url = String::from(req.path());
|
||||||
match content.get_content_at(&url) {
|
match content.get_content_at(&url) {
|
||||||
|
@ -415,23 +426,23 @@ impl SiteService {
|
||||||
log::debug!("Found page content at {}", req.path());
|
log::debug!("Found page content at {}", req.path());
|
||||||
let mut context = tera::Context::new();
|
let mut context = tera::Context::new();
|
||||||
context.insert("page", page);
|
context.insert("page", page);
|
||||||
let rendered = content.template_renderer.render("page.html", &context).unwrap();
|
let rendered = content.template_renderer.render("page.html", &context)?;
|
||||||
Some(Either::Left(HttpResponse::Ok().body(rendered)))
|
Ok(Some(Either::Left(HttpResponse::Ok().body(rendered))))
|
||||||
}
|
}
|
||||||
Some(Content::Post(post)) => {
|
Some(Content::Post(post)) => {
|
||||||
log::debug!("Found post content at {}", req.path());
|
log::debug!("Found post content at {}", req.path());
|
||||||
let mut context = tera::Context::new();
|
let mut context = tera::Context::new();
|
||||||
context.insert("post", post);
|
context.insert("post", post);
|
||||||
let rendered = content.template_renderer.render("post.html", &context).unwrap();
|
let rendered = content.template_renderer.render("post.html", &context)?;
|
||||||
Some(Either::Left(HttpResponse::Ok().body(rendered)))
|
Ok(Some(Either::Left(HttpResponse::Ok().body(rendered))))
|
||||||
}
|
}
|
||||||
Some(Content::Redirect(url)) => {
|
Some(Content::Redirect(url)) => {
|
||||||
log::debug!("Found redirect at {}", req.path());
|
log::debug!("Found redirect at {}", req.path());
|
||||||
Some(Either::Right(Redirect::to(url).using_status_code(StatusCode::MOVED_PERMANENTLY)))
|
Ok(Some(Either::Right(Redirect::to(url).using_status_code(StatusCode::MOVED_PERMANENTLY))))
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
log::debug!("No matching content at {}", req.path());
|
log::debug!("No matching content at {}", req.path());
|
||||||
None
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue