Migrate to actix-web #8

Manually merged
tlater merged 14 commits from tlater/actix-web into master 2022-09-16 17:44:53 +01:00
6 changed files with 42 additions and 84 deletions
Showing only changes of commit a960bf4b27 - Show all commits

13
Cargo.lock generated
View file

@ -44,9 +44,9 @@ dependencies = [
[[package]] [[package]]
name = "actix-http" name = "actix-http"
version = "3.2.1" version = "3.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f9ffb6db08c1c3a1f4aef540f1a63193adc73c4fbd40b75a95fc8c5258f6e51" checksum = "0c83abf9903e1f0ad9973cc4f7b9767fd5a03a583f51a5b7a339e07987cd2724"
dependencies = [ dependencies = [
"actix-codec", "actix-codec",
"actix-rt", "actix-rt",
@ -154,9 +154,9 @@ dependencies = [
[[package]] [[package]]
name = "actix-web" name = "actix-web"
version = "4.1.0" version = "4.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a27e8fe9ba4ae613c21f677c2cfaf0696c3744030c6f485b34634e502d6bb379" checksum = "d48f7b6534e06c7bfc72ee91db7917d4af6afe23e7d223b51e68fffbb21e96b9"
dependencies = [ dependencies = [
"actix-codec", "actix-codec",
"actix-http", "actix-http",
@ -176,6 +176,7 @@ dependencies = [
"encoding_rs", "encoding_rs",
"futures-core", "futures-core",
"futures-util", "futures-util",
"http",
"itoa", "itoa",
"language-tags", "language-tags",
"log", "log",
@ -194,9 +195,9 @@ dependencies = [
[[package]] [[package]]
name = "actix-web-codegen" name = "actix-web-codegen"
version = "4.0.1" version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f270541caec49c15673b0af0e9a00143421ad4f118d2df7edcb68b627632f56" checksum = "1fa9362663c8643d67b2d5eafba49e4cb2c8a053a29ed00a0bea121f17c76b13"
dependencies = [ dependencies = [
"actix-router", "actix-router",
"proc-macro2", "proc-macro2",

View file

@ -5,7 +5,7 @@ edition = "2021"
[dependencies] [dependencies]
actix-files = "0.6.2" actix-files = "0.6.2"
actix-web = "4.1.0" actix-web = { version = "4.2.1", features = ["macros"] }
clap = { version = "3.2.17", features = ["derive"] } clap = { version = "3.2.17", features = ["derive"] }
derive_more = "0.99.17" derive_more = "0.99.17"
env_logger = "0.9.0" env_logger = "0.9.0"

View file

@ -7,7 +7,7 @@ use actix_web::{web, HttpResponse, ResponseError};
use derive_more::{Display, Error}; use derive_more::{Display, Error};
use super::SharedData; use super::SharedData;
use crate::template_utils::{ErrorMessage, TemplateArgs}; use crate::template_utils::{render_template, ErrorMessage, TemplateArgs};
#[derive(Debug, Display, Error)] #[derive(Debug, Display, Error)]
pub enum UserError { pub enum UserError {
@ -56,8 +56,7 @@ pub fn generic_error<B>(
.error_page(ErrorMessage::new(message, status_code.as_u16())) .error_page(ErrorMessage::new(message, status_code.as_u16()))
.build(); .build();
let body = handlebars let body = render_template(handlebars, "error", &args)
.render("error", &args)
.map_err(|_| UserError::InternalError)?; .map_err(|_| UserError::InternalError)?;
HttpResponse::build(res.status()) HttpResponse::build(res.status())

View file

@ -2,6 +2,7 @@
use std::net::SocketAddr; use std::net::SocketAddr;
use std::path::PathBuf; use std::path::PathBuf;
use actix_files::Files;
use actix_web::{ use actix_web::{
http::{Method, StatusCode}, http::{Method, StatusCode},
middleware::{self, ErrorHandlers}, middleware::{self, ErrorHandlers},
@ -15,7 +16,7 @@ mod main_pages;
mod template_utils; mod template_utils;
use errors::generic_error; use errors::generic_error;
use main_pages::{mail_post, static_file, template, template_index}; use main_pages::{mail_post, template};
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct Config { struct Config {
@ -66,9 +67,8 @@ async fn main() -> std::io::Result<()> {
) )
.app_data(shared_data.clone()) .app_data(shared_data.clone())
.service(template) .service(template)
.service(static_file)
.service(template_index)
.service(mail_post) .service(mail_post)
.service(Files::new("/", &config.template_directory))
.default_service(web::route().method(Method::GET)) .default_service(web::route().method(Method::GET))
}) })
.bind(config.address)? .bind(config.address)?

View file

@ -1,11 +1,8 @@
use actix_files::NamedFile; use actix_web::{post, routes, web, HttpRequest, HttpResponse, Responder};
use actix_web::{get, post, web, HttpRequest, HttpResponse, Responder};
use log::info; use log::info;
use serde::Deserialize; use serde::Deserialize;
use crate::errors::UserError; use crate::template_utils::{render_template, Flash, FlashType, TemplateArgs};
use crate::template_utils::TemplateArgs;
use crate::template_utils::{Flash, FlashType};
use crate::SharedData; use crate::SharedData;
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
@ -15,69 +12,22 @@ pub(crate) struct Mail {
message: String, message: String,
} }
#[routes]
#[get(r"/")] #[get(r"/")]
pub(crate) async fn template_index(
shared: web::Data<SharedData<'_>>,
) -> actix_web::Result<impl Responder> {
if shared.handlebars.has_template("index") {
let body = shared
.handlebars
.render("index", &())
.map_err(|_| UserError::InternalError)?;
Ok(HttpResponse::Ok().body(body))
} else {
Err(UserError::NotFound)?
}
}
#[get(r"/{filename:.*\.html}")] #[get(r"/{filename:.*\.html}")]
pub(crate) async fn template( pub(crate) async fn template(
shared: web::Data<SharedData<'_>>, shared: web::Data<SharedData<'_>>,
req: HttpRequest, req: HttpRequest,
) -> actix_web::Result<impl Responder> { ) -> actix_web::Result<impl Responder> {
let path = req let path = match req.match_info().query("filename") {
.match_info() "" => "index",
.query("filename") other => other
.strip_suffix(".html") .strip_suffix(".html")
.expect("only paths with this suffix should get here"); .expect("only paths with this suffix should get here"),
};
if shared.handlebars.has_template(path) { render_template(&shared.handlebars, path, &TemplateArgs::default())
let body = shared .map(|body| HttpResponse::Ok().body(body))
.handlebars
.render(path, &())
.map_err(|_| UserError::InternalError)?;
Ok(HttpResponse::Ok().body(body))
} else {
Err(UserError::NotFound)?
}
}
#[get("/{filename:.*[^/]+}")]
pub(crate) async fn static_file(
shared: web::Data<SharedData<'_>>,
req: HttpRequest,
) -> actix_web::Result<impl Responder> {
let requested = req.match_info().query("filename");
match shared
.config
.template_directory
.join(requested)
.canonicalize()
{
// We only want to serve paths that are both valid *and* in
// the template directory.
//
// i.e., don't serve up /etc/passwd
Ok(path) if path.starts_with(&shared.config.template_directory) => {
let file = NamedFile::open_async(path)
.await
.map_err(|_| UserError::NotFound)?;
Ok(file.use_last_modified(false).respond_to(&req))
}
// Any other cases should 404
_ => Err(UserError::NotFound)?,
}
} }
#[post("/mail.html")] #[post("/mail.html")]
@ -91,13 +41,5 @@ pub(crate) async fn mail_post(
.flash(Flash::new("Mail successfully sent!", FlashType::Success)) .flash(Flash::new("Mail successfully sent!", FlashType::Success))
.build(); .build();
if shared.handlebars.has_template("mail") { render_template(&shared.handlebars, "mail", &args).map(|body| HttpResponse::Ok().body(body))
let body = shared
.handlebars
.render("mail", &args)
.map_err(|_| UserError::InternalError)?;
Ok(HttpResponse::Ok().body(body))
} else {
Err(UserError::InternalError)?
}
} }

View file

@ -1,7 +1,23 @@
use serde::Serialize; use serde::Serialize;
use crate::errors::UserError;
pub fn render_template(
handlebars: &handlebars::Handlebars,
name: &str,
args: &TemplateArgs,
) -> actix_web::Result<String> {
if handlebars.has_template(name) {
Ok(handlebars
.render(name, args)
.map_err(|_| UserError::InternalError)?)
} else {
Err(UserError::NotFound)?
}
}
/** All arguments that can be given to a template. */ /** All arguments that can be given to a template. */
#[derive(Serialize)] #[derive(Default, Serialize)]
pub struct TemplateArgs { pub struct TemplateArgs {
flash: Option<Flash>, flash: Option<Flash>,
error: Option<ErrorMessage>, error: Option<ErrorMessage>,