diff --git a/crates/presentation/Cargo.toml b/crates/presentation/Cargo.toml index fea57d7..dbfd03e 100644 --- a/crates/presentation/Cargo.toml +++ b/crates/presentation/Cargo.toml @@ -14,6 +14,8 @@ api-types = { workspace = true } postgres = { workspace = true } postgres-search = { workspace = true } auth = { workspace = true } +nats = { workspace = true } +async-nats = { workspace = true } axum = { workspace = true } sqlx = { workspace = true } tower-http = { workspace = true } diff --git a/crates/presentation/src/lib.rs b/crates/presentation/src/lib.rs index aa90e69..afe40c9 100644 --- a/crates/presentation/src/lib.rs +++ b/crates/presentation/src/lib.rs @@ -5,23 +5,36 @@ pub mod routes; pub mod state; use std::sync::Arc; -use sqlx::PgPool; -use state::AppState; -use postgres_search::PgSearchRepository; - use async_trait::async_trait; +use sqlx::PgPool; use domain::{errors::DomainError, events::DomainEvent, ports::EventPublisher}; +use postgres_search::PgSearchRepository; +use state::AppState; struct NoOpEventPublisher; - #[async_trait] impl EventPublisher for NoOpEventPublisher { - async fn publish(&self, _e: &DomainEvent) -> Result<(), DomainError> { - Ok(()) - } + async fn publish(&self, _e: &DomainEvent) -> Result<(), DomainError> { Ok(()) } } -pub fn build_state(pool: PgPool, jwt_secret: String) -> AppState { +pub async fn build_state(pool: PgPool, jwt_secret: String) -> AppState { + let event_publisher: Arc = match std::env::var("NATS_URL") { + Ok(url) => match async_nats::connect(&url).await { + Ok(client) => { + tracing::info!("Connected to NATS at {url}"); + Arc::new(nats::NatsEventPublisher::new(client)) + } + Err(e) => { + tracing::warn!("Failed to connect to NATS at {url}: {e} — using no-op publisher"); + Arc::new(NoOpEventPublisher) + } + }, + Err(_) => { + tracing::info!("NATS_URL not set — using no-op event publisher"); + Arc::new(NoOpEventPublisher) + } + }; + AppState { users: Arc::new(postgres::user::PgUserRepository::new(pool.clone())), thoughts: Arc::new(postgres::thought::PgThoughtRepository::new(pool.clone())), @@ -38,6 +51,6 @@ pub fn build_state(pool: PgPool, jwt_secret: String) -> AppState { search: Arc::new(PgSearchRepository::new(pool.clone())), auth: Arc::new(auth::JwtAuthService::new(jwt_secret, 86400 * 30)), hasher: Arc::new(auth::Argon2PasswordHasher), - events: Arc::new(NoOpEventPublisher), + events: event_publisher, } } diff --git a/crates/presentation/src/main.rs b/crates/presentation/src/main.rs index d29e32d..a80eff1 100644 --- a/crates/presentation/src/main.rs +++ b/crates/presentation/src/main.rs @@ -16,7 +16,7 @@ async fn main() { let pool = PgPool::connect(&database_url).await.expect("DB connect failed"); sqlx::migrate!("../adapters/postgres/migrations").run(&pool).await.expect("Migrations failed"); - let state = presentation::build_state(pool, jwt_secret); + let state = presentation::build_state(pool, jwt_secret).await; let app = presentation::routes::router() .with_state(state) .layer(CorsLayer::permissive());