From 5689db0ad7db631ad36099e1fb943931c7365e27 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Mon, 4 May 2026 12:44:53 +0200 Subject: [PATCH] feat(wiring): wire PosterSyncHandler into event channel in main.rs --- crates/adapters/event-publisher/src/lib.rs | 9 ++++ crates/presentation/src/main.rs | 49 +++++++++++++++++----- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/crates/adapters/event-publisher/src/lib.rs b/crates/adapters/event-publisher/src/lib.rs index a4122f3..dc4ecb9 100644 --- a/crates/adapters/event-publisher/src/lib.rs +++ b/crates/adapters/event-publisher/src/lib.rs @@ -81,6 +81,15 @@ impl EventWorker { } } +pub struct NoopEventPublisher; + +#[async_trait] +impl EventPublisher for NoopEventPublisher { + async fn publish(&self, _event: &DomainEvent) -> Result<(), DomainError> { + Ok(()) + } +} + pub fn create_event_channel( config: EventPublisherConfig, handlers: Vec>, diff --git a/crates/presentation/src/main.rs b/crates/presentation/src/main.rs index e1cbed7..82a2481 100644 --- a/crates/presentation/src/main.rs +++ b/crates/presentation/src/main.rs @@ -1,7 +1,8 @@ use std::sync::Arc; use anyhow::Context; -use event_publisher::{EventPublisherConfig, create_event_channel}; +use event_publisher::{EventPublisherConfig, NoopEventPublisher, create_event_channel}; +use presentation::event_handlers::PosterSyncHandler; use sqlx::SqlitePool; use tokio::net::TcpListener; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; @@ -52,20 +53,48 @@ async fn wire_dependencies() -> anyhow::Result { .map_err(|e| anyhow::anyhow!("{}", e)) .context("Database migration failed")?; - let user_repo = SqliteUserRepository::new(pool); + use domain::ports::{ + AuthService, MetadataClient, MovieRepository, PasswordHasher, + PosterFetcherClient, PosterStorage, UserRepository, + }; + let repository: Arc = Arc::new(movie_repo); + let user_repository: Arc = Arc::new(SqliteUserRepository::new(pool)); + let metadata_client: Arc = Arc::new(MetadataClientImpl::new_omdb(omdb_api_key)); + let poster_fetcher: Arc = Arc::new(ReqwestPosterFetcher::new(PosterFetcherConfig::from_env())?); + let poster_storage: Arc = Arc::new(PosterStorageAdapter::from_config(storage_config)?); + let auth_service: Arc = Arc::new(JwtAuthService::new(auth_config)); + let password_hasher: Arc = Arc::new(Argon2PasswordHasher); - let (event_publisher, event_worker) = create_event_channel(EventPublisherConfig::from_env()); + // Build a context for the poster handler. sync_poster doesn't publish events, + // so a noop publisher here is safe and avoids a circular dependency. + let handler_ctx = AppContext { + repository: Arc::clone(&repository), + metadata_client: Arc::clone(&metadata_client), + poster_fetcher: Arc::clone(&poster_fetcher), + poster_storage: Arc::clone(&poster_storage), + event_publisher: Arc::new(NoopEventPublisher), + auth_service: Arc::clone(&auth_service), + password_hasher: Arc::clone(&password_hasher), + user_repository: Arc::clone(&user_repository), + config: app_config.clone(), + }; + + let poster_handler = PosterSyncHandler::new(handler_ctx, 3); + let (event_publisher, event_worker) = create_event_channel( + EventPublisherConfig::from_env(), + vec![Box::new(poster_handler)], + ); tokio::spawn(event_worker.run()); let app_ctx = AppContext { - repository: Arc::new(movie_repo), - metadata_client: Arc::new(MetadataClientImpl::new_omdb(omdb_api_key)), - poster_fetcher: Arc::new(ReqwestPosterFetcher::new(PosterFetcherConfig::from_env())?), - poster_storage: Arc::new(PosterStorageAdapter::from_config(storage_config)?), + repository, + metadata_client, + poster_fetcher, + poster_storage, event_publisher: Arc::new(event_publisher), - auth_service: Arc::new(JwtAuthService::new(auth_config)), - password_hasher: Arc::new(Argon2PasswordHasher), - user_repository: Arc::new(user_repo), + auth_service, + password_hasher, + user_repository, config: app_config, };