BLOG-85 refactor: enhance configuration management with database, server, session, and storage modules
All checks were successful
Frontend CI / build (push) Successful in 1m8s
All checks were successful
Frontend CI / build (push) Successful in 1m8s
This commit is contained in:
parent
8bacf74c9e
commit
62803debee
@ -1,18 +1,33 @@
|
||||
use openidconnect::reqwest;
|
||||
|
||||
use crate::configuration::oidc::OidcConfiguration;
|
||||
use crate::configuration::{
|
||||
db::DbConfiguration, oidc::OidcConfiguration, server::ServerConfiguration,
|
||||
session::SessionConfiguration, storage::StorageConfiguration,
|
||||
};
|
||||
|
||||
pub mod db;
|
||||
pub mod oidc;
|
||||
pub mod server;
|
||||
pub mod session;
|
||||
pub mod storage;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Configuration {
|
||||
pub oidc_configuration: OidcConfiguration,
|
||||
pub db: DbConfiguration,
|
||||
pub oidc: OidcConfiguration,
|
||||
pub server: ServerConfiguration,
|
||||
pub session: SessionConfiguration,
|
||||
pub storage: StorageConfiguration,
|
||||
}
|
||||
|
||||
impl Configuration {
|
||||
pub async fn new(http_client: reqwest::Client) -> Self {
|
||||
Self {
|
||||
oidc_configuration: OidcConfiguration::new(http_client).await,
|
||||
db: DbConfiguration::new(),
|
||||
oidc: OidcConfiguration::new(http_client).await,
|
||||
server: ServerConfiguration::new(),
|
||||
session: SessionConfiguration::new(),
|
||||
storage: StorageConfiguration::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
44
backend/server/src/configuration/db.rs
Normal file
44
backend/server/src/configuration/db.rs
Normal file
@ -0,0 +1,44 @@
|
||||
use std::env;
|
||||
|
||||
use sqlx::{Pool, Postgres, postgres::PgPoolOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DbConfiguration {
|
||||
pub database_url: String,
|
||||
}
|
||||
|
||||
impl DbConfiguration {
|
||||
pub fn new() -> Self {
|
||||
let host = env::var("DATABASE_HOST").unwrap_or_else(|_| "127.0.0.1".to_string());
|
||||
let port = env::var("DATABASE_PORT").unwrap_or_else(|_| "5432".to_string());
|
||||
let user = env::var("DATABASE_USER").unwrap_or_else(|_| "postgres".to_string());
|
||||
let password = env::var("DATABASE_PASSWORD").unwrap_or_else(|_| "".to_string());
|
||||
let dbname = env::var("DATABASE_NAME").unwrap_or_else(|_| "postgres".to_string());
|
||||
|
||||
let encoded_password =
|
||||
percent_encoding::utf8_percent_encode(&password, percent_encoding::NON_ALPHANUMERIC)
|
||||
.to_string();
|
||||
|
||||
let database_url = format!(
|
||||
"postgres://{}:{}@{}:{}/{}",
|
||||
user, encoded_password, host, port, dbname
|
||||
);
|
||||
|
||||
Self { database_url }
|
||||
}
|
||||
|
||||
pub async fn create_connection(&self) -> Pool<Postgres> {
|
||||
let db_pool = PgPoolOptions::new()
|
||||
.max_connections(5)
|
||||
.connect(&self.database_url)
|
||||
.await
|
||||
.expect("Failed to create database connection pool");
|
||||
|
||||
sqlx::migrate!("../migrations")
|
||||
.run(&db_pool)
|
||||
.await
|
||||
.expect("Failed to run database migrations");
|
||||
|
||||
db_pool
|
||||
}
|
||||
}
|
17
backend/server/src/configuration/server.rs
Normal file
17
backend/server/src/configuration/server.rs
Normal file
@ -0,0 +1,17 @@
|
||||
#[derive(Clone)]
|
||||
pub struct ServerConfiguration {
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
impl ServerConfiguration {
|
||||
pub fn new() -> Self {
|
||||
let host = std::env::var("HOST").unwrap_or_else(|_| "127.0.0.1".to_string());
|
||||
let port = std::env::var("PORT")
|
||||
.unwrap_or_else(|_| "8080".to_string())
|
||||
.parse::<u16>()
|
||||
.unwrap();
|
||||
|
||||
Self { host, port }
|
||||
}
|
||||
}
|
36
backend/server/src/configuration/session.rs
Normal file
36
backend/server/src/configuration/session.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use actix_session::storage::RedisSessionStore;
|
||||
use actix_web::cookie::Key;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SessionConfiguration {
|
||||
pub session_key: Key,
|
||||
pub redis_url: String,
|
||||
}
|
||||
|
||||
impl SessionConfiguration {
|
||||
pub fn new() -> Self {
|
||||
let session_key_hex = std::env::var("SESSION_KEY").expect("SESSION_KEY must be set");
|
||||
let session_key_bytes =
|
||||
hex::decode(session_key_hex).expect("Invalid SESSION_KEY format, must be hex encoded");
|
||||
|
||||
if session_key_bytes.len() != 64 {
|
||||
panic!("SESSION_KEY must be 64 bytes long");
|
||||
}
|
||||
|
||||
let session_key = Key::from(&session_key_bytes);
|
||||
|
||||
let redis_url =
|
||||
std::env::var("REDIS_URL").unwrap_or_else(|_| "redis://127.0.1:6379".to_string());
|
||||
|
||||
Self {
|
||||
session_key,
|
||||
redis_url,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create_session_store(&self) -> RedisSessionStore {
|
||||
RedisSessionStore::new(self.redis_url.clone())
|
||||
.await
|
||||
.expect("Failed to create Redis session store")
|
||||
}
|
||||
}
|
13
backend/server/src/configuration/storage.rs
Normal file
13
backend/server/src/configuration/storage.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use std::env;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StorageConfiguration {
|
||||
pub storage_path: String,
|
||||
}
|
||||
|
||||
impl StorageConfiguration {
|
||||
pub fn new() -> Self {
|
||||
let storage_path = env::var("STORAGE_PATH").unwrap_or_else(|_| "static".to_string());
|
||||
Self { storage_path }
|
||||
}
|
||||
}
|
@ -49,11 +49,10 @@ pub struct Container {
|
||||
impl Container {
|
||||
pub fn new(
|
||||
db_pool: Pool<Postgres>,
|
||||
storage_path: &str,
|
||||
http_client: reqwest::Client,
|
||||
configuration: Configuration,
|
||||
) -> Self {
|
||||
let oidc_configuration = &configuration.oidc_configuration;
|
||||
let oidc_configuration = &configuration.oidc;
|
||||
let auth_oidc_service = Arc::new(AuthOidcServiceImpl::new(
|
||||
oidc_configuration.provider_metadata.clone(),
|
||||
&oidc_configuration.client_id,
|
||||
@ -81,7 +80,7 @@ impl Container {
|
||||
));
|
||||
|
||||
let image_db_service = Arc::new(ImageDbServiceImpl::new(db_pool.clone()));
|
||||
let image_storage = Arc::new(ImageStorageImpl::new(storage_path.into()));
|
||||
let image_storage = Arc::new(ImageStorageImpl::new(&configuration.storage.storage_path));
|
||||
let image_repository = Arc::new(ImageRepositoryImpl::new(
|
||||
image_db_service.clone(),
|
||||
image_storage.clone(),
|
||||
|
@ -4,7 +4,6 @@ use actix_session::{
|
||||
use actix_web::{
|
||||
App, Error, HttpServer,
|
||||
body::MessageBody,
|
||||
cookie,
|
||||
dev::{ServiceFactory, ServiceRequest, ServiceResponse},
|
||||
web,
|
||||
};
|
||||
@ -13,36 +12,30 @@ use image::framework::web::image_web_routes::configure_image_routes;
|
||||
use openidconnect::reqwest;
|
||||
use post::framework::web::post_web_routes::configure_post_routes;
|
||||
use server::{configuration::Configuration, container::Container};
|
||||
use sqlx::{Pool, Postgres, postgres::PgPoolOptions};
|
||||
use std::env;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
dotenv::dotenv().ok();
|
||||
env_logger::init();
|
||||
|
||||
let db_pool = init_database().await;
|
||||
let storage_path = env::var("STORAGE_PATH").unwrap_or_else(|_| "static".to_string());
|
||||
let http_client = reqwest::ClientBuilder::new()
|
||||
.redirect(reqwest::redirect::Policy::none())
|
||||
.build()
|
||||
.expect("Failed to create HTTP client");
|
||||
|
||||
let session_store = init_session_store().await;
|
||||
let session_key = init_session_key().await;
|
||||
|
||||
let host = env::var("HOST").unwrap_or_else(|_| "0.0.0.0".to_string());
|
||||
let port = env::var("PORT")
|
||||
.unwrap_or_else(|_| "8080".to_string())
|
||||
.parse::<u16>()
|
||||
.unwrap();
|
||||
|
||||
let configuration = Configuration::new(http_client.clone()).await;
|
||||
|
||||
let host = configuration.server.host.clone();
|
||||
let port = configuration.server.port;
|
||||
|
||||
let db_pool = configuration.db.create_connection().await;
|
||||
let session_key = configuration.session.session_key.clone();
|
||||
let session_store = configuration.session.create_session_store().await;
|
||||
|
||||
HttpServer::new(move || {
|
||||
create_app(
|
||||
db_pool.clone(),
|
||||
storage_path.clone(),
|
||||
http_client.clone(),
|
||||
SessionMiddleware::builder(session_store.clone(), session_key.clone()),
|
||||
configuration.clone(),
|
||||
@ -53,55 +46,8 @@ async fn main() -> std::io::Result<()> {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn init_database() -> Pool<Postgres> {
|
||||
let host = env::var("DATABASE_HOST").unwrap_or_else(|_| "127.0.0.1".to_string());
|
||||
let port = env::var("DATABASE_PORT").unwrap_or_else(|_| "5432".to_string());
|
||||
let user = env::var("DATABASE_USER").unwrap_or_else(|_| "postgres".to_string());
|
||||
let password = env::var("DATABASE_PASSWORD").unwrap_or_else(|_| "".to_string());
|
||||
let dbname = env::var("DATABASE_NAME").unwrap_or_else(|_| "postgres".to_string());
|
||||
|
||||
let encoded_password =
|
||||
percent_encoding::utf8_percent_encode(&password, percent_encoding::NON_ALPHANUMERIC)
|
||||
.to_string();
|
||||
let database_url = format!(
|
||||
"postgres://{}:{}@{}:{}/{}",
|
||||
user, encoded_password, host, port, dbname
|
||||
);
|
||||
|
||||
let db_pool = PgPoolOptions::new()
|
||||
.max_connections(5)
|
||||
.connect(&database_url)
|
||||
.await
|
||||
.expect("Failed to create database connection pool");
|
||||
|
||||
sqlx::migrate!("../migrations")
|
||||
.run(&db_pool)
|
||||
.await
|
||||
.expect("Failed to run database migrations");
|
||||
|
||||
db_pool
|
||||
}
|
||||
|
||||
async fn init_session_store() -> RedisSessionStore {
|
||||
let redis_url = env::var("REDIS_URL").unwrap_or_else(|_| "redis://127.0.1:6379".to_string());
|
||||
RedisSessionStore::new(redis_url)
|
||||
.await
|
||||
.expect("Failed to create Redis session store")
|
||||
}
|
||||
|
||||
async fn init_session_key() -> cookie::Key {
|
||||
let session_key_hex = env::var("SESSION_KEY").expect("SESSION_KEY must be set");
|
||||
let session_key_bytes =
|
||||
hex::decode(session_key_hex).expect("Invalid SESSION_KEY format, must be hex encoded");
|
||||
if session_key_bytes.len() != 64 {
|
||||
panic!("SESSION_KEY must be 64 bytes long");
|
||||
}
|
||||
cookie::Key::from(&session_key_bytes)
|
||||
}
|
||||
|
||||
fn create_app(
|
||||
db_pool: Pool<Postgres>,
|
||||
storage_path: String,
|
||||
http_client: reqwest::Client,
|
||||
session_middleware_builder: SessionMiddlewareBuilder<RedisSessionStore>,
|
||||
configuration: Configuration,
|
||||
@ -114,7 +60,7 @@ fn create_app(
|
||||
Error = Error,
|
||||
>,
|
||||
> {
|
||||
let container = Container::new(db_pool, &storage_path, http_client, configuration);
|
||||
let container = Container::new(db_pool, http_client, configuration);
|
||||
|
||||
App::new()
|
||||
.wrap(session_middleware_builder.build())
|
||||
|
Loading…
x
Reference in New Issue
Block a user