Add address from config, rate limiter and tracing

This commit is contained in:
Mo 2022-11-02 00:24:17 +01:00
parent 14c418dacc
commit ba01105058
5 changed files with 78 additions and 7 deletions

View file

@ -20,3 +20,8 @@ lettre = "0.10"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
tokio = { version = "1.21", features = ["full"] } tokio = { version = "1.21", features = ["full"] }
tower = { version = "0.4", features = ["limit", "buffer"] }
tower-http = { version = "0.3", features = ["trace"] }
tracing = "0.1"
tracing-appender = "0.2"
tracing-subscriber = "0.3"

View file

@ -4,6 +4,12 @@ use std::env;
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
#[derive(Deserialize)]
pub struct SocketAddress {
pub address: [u8; 4],
pub port: u16,
}
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct EmailServer { pub struct EmailServer {
pub server_name: String, pub server_name: String,
@ -18,12 +24,20 @@ pub struct Address {
pub domain: String, pub domain: String,
} }
#[derive(Deserialize)]
pub struct Logging {
pub directory: String,
pub filename_prefix: String,
}
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Config { pub struct Config {
pub path_prefix: String, pub path_prefix: String,
pub socket_address: SocketAddress,
pub email_server: EmailServer, pub email_server: EmailServer,
pub email_from: Address, pub email_from: Address,
pub email_to: Address, pub email_to: Address,
pub logging: Logging,
} }
impl Config { impl Config {

View file

@ -11,6 +11,6 @@ impl IntoResponse for AppError {
impl From<anyhow::Error> for AppError { impl From<anyhow::Error> for AppError {
fn from(err: anyhow::Error) -> Self { fn from(err: anyhow::Error) -> Self {
Self(err.into()) Self(err)
} }
} }

19
src/logging.rs Normal file
View file

@ -0,0 +1,19 @@
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::filter::LevelFilter;
use crate::config;
pub fn init_logger(logging_config: &config::Logging) -> WorkerGuard {
let file_appender = tracing_appender::rolling::hourly(
&logging_config.directory,
&logging_config.filename_prefix,
);
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
tracing_subscriber::fmt()
.with_max_level(LevelFilter::INFO)
.with_writer(non_blocking)
.init();
guard
}

View file

@ -2,6 +2,7 @@ mod captcha_solutions;
mod config; mod config;
mod errors; mod errors;
mod forms; mod forms;
mod logging;
mod mailer; mod mailer;
mod routes; mod routes;
mod templates; mod templates;
@ -9,14 +10,34 @@ mod templates;
use anyhow::Result; use anyhow::Result;
use axum::extract::Extension; use axum::extract::Extension;
use axum::routing::{get, post}; use axum::routing::{get, post};
use axum::{error_handling::HandleErrorLayer, http::StatusCode, BoxError};
use axum::{Router, Server}; use axum::{Router, Server};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::process; use std::process;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration;
use tower::buffer::BufferLayer;
use tower::limit::RateLimitLayer;
use tower::ServiceBuilder;
use tower_http::trace::{DefaultOnResponse, TraceLayer};
use tracing::Level;
use tracing_appender::non_blocking::WorkerGuard;
async fn init() -> Result<()> { async fn init() -> Result<WorkerGuard> {
let mut config = config::Config::new()?; let mut config = config::Config::new()?;
let path_prefix = config.path_prefix.clone(); let path_prefix = config.path_prefix.clone();
let mailer = Arc::new(mailer::Mailer::new(&mut config)?); let mailer = Arc::new(mailer::Mailer::new(&mut config)?);
let address = config.socket_address.address;
let socket_address = SocketAddr::new(
IpAddr::V4(Ipv4Addr::new(
address[0], address[1], address[2], address[3],
)),
config.socket_address.port,
);
let tracing_worker_gurad = logging::init_logger(&config.logging);
let config = Arc::new(config); let config = Arc::new(config);
let captcha_solutions = Arc::new(captcha_solutions::SharedCaptchaSolutions::new()); let captcha_solutions = Arc::new(captcha_solutions::SharedCaptchaSolutions::new());
@ -24,24 +45,36 @@ async fn init() -> Result<()> {
.route("/", get(routes::index)) .route("/", get(routes::index))
.route("/submit", post(routes::submit)) .route("/submit", post(routes::submit))
.route("/success", get(routes::success)) .route("/success", get(routes::success))
.layer(TraceLayer::new_for_http().on_response(DefaultOnResponse::new().level(Level::INFO)))
.layer(
ServiceBuilder::new()
.layer(HandleErrorLayer::new(|err: BoxError| async move {
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("Unhandled error: {}", err),
)
}))
.layer(BufferLayer::new(1024))
.layer(RateLimitLayer::new(2, Duration::from_secs(3))),
)
.layer(Extension(config)) .layer(Extension(config))
.layer(Extension(mailer)) .layer(Extension(mailer))
.layer(Extension(captcha_solutions)); .layer(Extension(captcha_solutions));
let app = Router::new().nest(&path_prefix, routes); let app = Router::new().nest(&path_prefix, routes);
Server::bind(&([127, 0, 0, 1], 8080).into()) Server::bind(&socket_address)
.serve(app.into_make_service()) .serve(app.into_make_service())
.await .await
.unwrap(); .unwrap();
Ok(()) Ok(tracing_worker_gurad)
} }
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
init().await.unwrap_or_else(|e| { let _tracing_worker_gurad = init().await.unwrap_or_else(|e| {
eprintln!("{e}"); eprintln!("{e:?}");
process::exit(1); process::exit(1);
}) });
} }