99 lines
3.0 KiB
Rust
99 lines
3.0 KiB
Rust
use crate::{configuration::Settings, email_client::EmailClient, routes::*};
|
|
use axum::{
|
|
Router,
|
|
extract::MatchedPath,
|
|
http::Request,
|
|
routing::{get, post},
|
|
};
|
|
use axum_messages::MessagesManagerLayer;
|
|
use secrecy::SecretString;
|
|
use sqlx::{PgPool, postgres::PgPoolOptions};
|
|
use std::sync::Arc;
|
|
use tokio::net::TcpListener;
|
|
use tower_http::trace::TraceLayer;
|
|
use tower_sessions::{MemoryStore, SessionManagerLayer};
|
|
use uuid::Uuid;
|
|
|
|
pub struct Application {
|
|
listener: TcpListener,
|
|
router: Router,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct AppState {
|
|
pub connection_pool: PgPool,
|
|
pub email_client: Arc<EmailClient>,
|
|
pub base_url: String,
|
|
pub hmac_secret: SecretString,
|
|
}
|
|
|
|
impl Application {
|
|
pub async fn build(configuration: Settings) -> Result<Self, std::io::Error> {
|
|
let address = format!(
|
|
"{}:{}",
|
|
configuration.application.host, configuration.application.port
|
|
);
|
|
let listener = TcpListener::bind(address).await?;
|
|
let connection_pool =
|
|
PgPoolOptions::new().connect_lazy_with(configuration.database.with_db());
|
|
let email_client = EmailClient::new(configuration.email_client);
|
|
let router = app(
|
|
connection_pool,
|
|
email_client,
|
|
configuration.application.base_url,
|
|
configuration.application.hmac_secret,
|
|
);
|
|
Ok(Self { listener, router })
|
|
}
|
|
|
|
pub async fn run_until_stopped(self) -> Result<(), std::io::Error> {
|
|
tracing::debug!("listening on {}", self.listener.local_addr().unwrap());
|
|
axum::serve(self.listener, self.router).await
|
|
}
|
|
|
|
pub fn local_addr(&self) -> String {
|
|
self.listener.local_addr().unwrap().to_string()
|
|
}
|
|
}
|
|
|
|
pub fn app(
|
|
connection_pool: PgPool,
|
|
email_client: EmailClient,
|
|
base_url: String,
|
|
hmac_secret: SecretString,
|
|
) -> Router {
|
|
let app_state = AppState {
|
|
connection_pool,
|
|
email_client: Arc::new(email_client),
|
|
base_url,
|
|
hmac_secret,
|
|
};
|
|
Router::new()
|
|
.route("/", get(home))
|
|
.route("/login", get(get_login).post(post_login))
|
|
.route("/health_check", get(health_check))
|
|
.route("/subscriptions", post(subscribe))
|
|
.route("/subscriptions/confirm", get(confirm))
|
|
.route("/newsletters", post(publish_newsletter))
|
|
.layer(
|
|
TraceLayer::new_for_http().make_span_with(|request: &Request<_>| {
|
|
let matched_path = request
|
|
.extensions()
|
|
.get::<MatchedPath>()
|
|
.map(MatchedPath::as_str);
|
|
let request_id = Uuid::new_v4().to_string();
|
|
|
|
tracing::info_span!(
|
|
"http_request",
|
|
method = ?request.method(),
|
|
matched_path,
|
|
request_id,
|
|
some_other_field = tracing::field::Empty,
|
|
)
|
|
}),
|
|
)
|
|
.layer(MessagesManagerLayer)
|
|
.layer(SessionManagerLayer::new(MemoryStore::default()))
|
|
.with_state(app_state)
|
|
}
|