use std::{sync::OnceLock, time::Duration}; use redis::{aio::MultiplexedConnection as RedisConnection, Client as RedisClient, RedisResult}; use sqlx::{postgres::PgPoolOptions, Pool, Postgres}; use crate::error::SirenResult; static POOL: OnceLock> = OnceLock::new(); static REDIS: OnceLock = OnceLock::new(); pub async fn initialize() -> SirenResult<()> { log::info!("Initializing database..."); let db_user = std::env::var("DATABASE_USER").unwrap_or("siren".to_string()); let db_password = std::env::var("DATABASE_PASSWORD").expect("DATABASE_PASSWORD must be set"); let db_host: String = std::env::var("DATABASE_HOST").expect("DATABASE_HOST must be set"); let db_port = std::env::var("DATABASE_PORT").unwrap_or("5432".to_string()); let db_name = std::env::var("DATABASE_NAME").unwrap_or("siren".to_string()); // Setup Postgres pool connection let pool = PgPoolOptions::new() .max_connections(5) .acquire_timeout(Duration::from_secs(30)) .connect(&format!( "postgres://{}:{}@{}:{}/{}", db_user, db_password, db_host, db_port, db_name )) .await?; match POOL.set(pool) { Ok(_) => {} Err(_) => { log::warn!("Database pool already initialized"); } } // Setup Redis connection let redis = { let host = std::env::var("REDIS_HOST").unwrap_or("localhost".to_string()); let port = std::env::var("REDIS_PORT").unwrap_or("6379".to_string()); let url = format!("redis://{}:{}", host, port); RedisClient::open(url).expect("Failed to create redis client") }; match REDIS.set(redis) { Ok(_) => {} Err(_) => { log::warn!("Redis client already initialized"); } } // Run migrations match run_migrations().await { Ok(_) => log::debug!("Successfully ran migrations"), Err(e) => log::error!("Failed to run migrations: {}", e), } log::info!("Database initialized"); Ok(()) } pub fn pool() -> &'static Pool { POOL.get().unwrap() } fn redis() -> &'static RedisClient { REDIS.get().unwrap() } pub fn redis_connection() -> RedisResult { let conn = redis().get_connection()?; Ok(conn) } pub async fn redis_async_connection() -> RedisResult { let conn = redis().get_multiplexed_async_connection().await?; Ok(conn) } async fn run_migrations() -> SirenResult<()> { log::debug!("Running migrations"); let pool = pool(); sqlx::migrate!().run(pool).await?; Ok(()) }