2021-02-14 16:27:04 +00:00
|
|
|
use crate::configuration::{DatabaseSettings, Settings};
|
2021-01-11 10:01:48 +00:00
|
|
|
use crate::email_client::EmailClient;
|
2021-04-02 10:51:39 +00:00
|
|
|
use crate::routes::{confirm, health_check, subscribe};
|
2020-09-27 16:09:42 +00:00
|
|
|
use actix_web::dev::Server;
|
|
|
|
use actix_web::web::Data;
|
|
|
|
use actix_web::{web, App, HttpServer};
|
2021-02-14 16:27:04 +00:00
|
|
|
use sqlx::postgres::PgPoolOptions;
|
2020-09-27 16:09:42 +00:00
|
|
|
use sqlx::PgPool;
|
|
|
|
use std::net::TcpListener;
|
|
|
|
use tracing_actix_web::TracingLogger;
|
|
|
|
|
2021-02-14 16:41:45 +00:00
|
|
|
pub struct Application {
|
2021-02-15 21:26:43 +00:00
|
|
|
port: u16,
|
2021-02-14 16:41:45 +00:00
|
|
|
server: Server,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Application {
|
|
|
|
pub async fn build(configuration: Settings) -> Result<Self, std::io::Error> {
|
|
|
|
let connection_pool = get_connection_pool(&configuration.database)
|
|
|
|
.await
|
|
|
|
.expect("Failed to connect to Postgres.");
|
|
|
|
|
|
|
|
let sender_email = configuration
|
|
|
|
.email_client
|
|
|
|
.sender()
|
|
|
|
.expect("Invalid sender email address.");
|
|
|
|
let email_client = EmailClient::new(
|
|
|
|
configuration.email_client.base_url,
|
|
|
|
sender_email,
|
|
|
|
configuration.email_client.authorization_token,
|
|
|
|
);
|
|
|
|
|
|
|
|
let address = format!(
|
|
|
|
"{}:{}",
|
|
|
|
configuration.application.host, configuration.application.port
|
|
|
|
);
|
|
|
|
let listener = TcpListener::bind(&address)?;
|
2021-02-15 21:26:43 +00:00
|
|
|
let port = listener.local_addr().unwrap().port();
|
2021-03-09 22:40:14 +00:00
|
|
|
let server = run(
|
|
|
|
listener,
|
|
|
|
connection_pool,
|
|
|
|
email_client,
|
2021-03-11 09:24:57 +00:00
|
|
|
configuration.application.base_url,
|
2021-03-09 22:40:14 +00:00
|
|
|
)?;
|
2021-02-14 16:41:45 +00:00
|
|
|
|
2021-02-15 21:26:43 +00:00
|
|
|
Ok(Self { port, server })
|
2021-02-14 16:41:45 +00:00
|
|
|
}
|
|
|
|
|
2021-02-15 21:26:43 +00:00
|
|
|
pub fn port(&self) -> u16 {
|
|
|
|
self.port
|
2021-02-14 16:41:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn run_until_stopped(self) -> Result<(), std::io::Error> {
|
|
|
|
self.server.await
|
|
|
|
}
|
2021-02-14 16:27:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn get_connection_pool(configuration: &DatabaseSettings) -> Result<PgPool, sqlx::Error> {
|
|
|
|
PgPoolOptions::new()
|
|
|
|
.connect_timeout(std::time::Duration::from_secs(2))
|
|
|
|
.connect_with(configuration.with_db())
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
2021-03-11 09:24:57 +00:00
|
|
|
pub struct ApplicationBaseUrl(pub String);
|
2021-03-09 22:40:14 +00:00
|
|
|
|
2021-02-14 16:41:45 +00:00
|
|
|
fn run(
|
2021-01-11 10:01:48 +00:00
|
|
|
listener: TcpListener,
|
|
|
|
db_pool: PgPool,
|
|
|
|
email_client: EmailClient,
|
2021-03-11 09:24:57 +00:00
|
|
|
base_url: String,
|
2021-01-11 10:01:48 +00:00
|
|
|
) -> Result<Server, std::io::Error> {
|
2020-09-27 16:09:42 +00:00
|
|
|
let db_pool = Data::new(db_pool);
|
2021-01-11 10:01:48 +00:00
|
|
|
let email_client = Data::new(email_client);
|
2021-07-09 07:37:14 +00:00
|
|
|
let base_url = Data::new(ApplicationBaseUrl(base_url));
|
2020-09-27 16:09:42 +00:00
|
|
|
let server = HttpServer::new(move || {
|
|
|
|
App::new()
|
2021-05-01 15:11:16 +00:00
|
|
|
.wrap(TracingLogger::default())
|
2020-09-27 16:09:42 +00:00
|
|
|
.route("/health_check", web::get().to(health_check))
|
|
|
|
.route("/subscriptions", web::post().to(subscribe))
|
2021-03-11 09:24:57 +00:00
|
|
|
.route("/subscriptions/confirm", web::get().to(confirm))
|
2020-09-27 16:09:42 +00:00
|
|
|
.app_data(db_pool.clone())
|
2021-01-11 10:01:48 +00:00
|
|
|
.app_data(email_client.clone())
|
2021-07-09 07:37:14 +00:00
|
|
|
.app_data(base_url.clone())
|
2020-09-27 16:09:42 +00:00
|
|
|
})
|
|
|
|
.listen(listener)?
|
|
|
|
.run();
|
|
|
|
Ok(server)
|
|
|
|
}
|