nats adapter

This commit is contained in:
2026-05-10 13:42:28 +02:00
parent 05b44e17a1
commit 8678bbf391
20 changed files with 1078 additions and 37 deletions

View File

@@ -9,8 +9,18 @@ sqlite = ["dep:sqlite"]
postgres = ["dep:postgres"]
# Meta-feature: true when any federation adapter is active — keeps all #[cfg(feature = "federation")] gates working
federation = []
sqlite-federation = ["sqlite", "dep:sqlite-federation", "dep:activitypub", "federation"]
postgres-federation = ["postgres", "dep:postgres-federation", "dep:activitypub", "federation"]
sqlite-federation = [
"sqlite",
"dep:sqlite-federation",
"dep:activitypub",
"federation",
]
postgres-federation = [
"postgres",
"dep:postgres-federation",
"dep:activitypub",
"federation",
]
[dependencies]
tower-http = { version = "0.6.8", features = ["fs", "trace", "tracing"] }
@@ -39,6 +49,7 @@ poster-fetcher = { workspace = true }
poster-storage = { workspace = true }
template-askama = { workspace = true }
event-publisher = { workspace = true }
nats = { workspace = true }
rss = { workspace = true }
export = { workspace = true }
doc = { workspace = true }
@@ -46,12 +57,12 @@ sqlx = { workspace = true }
utoipa = { version = "5.5.0", features = ["axum_extras", "uuid"] }
# Optional — database backends
sqlite = { workspace = true, optional = true }
postgres = { workspace = true, optional = true }
sqlite = { workspace = true, optional = true }
postgres = { workspace = true, optional = true }
# Optional — federation
activitypub = { workspace = true, optional = true }
sqlite-federation = { workspace = true, optional = true }
activitypub = { workspace = true, optional = true }
sqlite-federation = { workspace = true, optional = true }
postgres-federation = { workspace = true, optional = true }
[dev-dependencies]

View File

@@ -38,9 +38,9 @@ use presentation::{openapi::ApiDoc, routes, state::AppState};
use utoipa::OpenApi as _;
use domain::ports::{
AuthService, DiaryExporter, DiaryRepository, MetadataClient, MovieRepository,
PasswordHasher, PosterFetcherClient, PosterStorage, ReviewRepository, StatsRepository,
UserRepository,
AuthService, DiaryExporter, DiaryRepository, EventHandler, EventPublisher, MetadataClient,
MovieRepository, PasswordHasher, PosterFetcherClient, PosterStorage, ReviewRepository,
StatsRepository, UserRepository,
};
#[cfg(not(any(feature = "sqlite", feature = "postgres")))]
@@ -184,26 +184,18 @@ async fn wire_dependencies() -> anyhow::Result<(AppState, axum::Router)> {
);
let ap_service_arc: Arc<dyn ActivityPubPort> = concrete_ap_service;
let poster_handler = Arc::new(PosterSyncHandler::new(handler_ctx, 3));
let (event_publisher, consumer) = create_event_channel(EventPublisherConfig::from_env());
let worker = WorkerService::new(
Arc::new(consumer),
vec![poster_handler, Arc::new(ap_event_handler)],
);
tokio::spawn(worker.run());
let ep: Arc<dyn domain::ports::EventPublisher> = Arc::new(event_publisher);
let ep = build_event_publisher(
handler_ctx,
vec![Arc::new(ap_event_handler) as Arc<dyn EventHandler>],
).await?;
(ep, ap_router, ap_service_arc, social_query_arc)
};
#[cfg(not(feature = "federation"))]
let (event_publisher_arc, ap_router): (Arc<dyn domain::ports::EventPublisher>, axum::Router) = {
let poster_handler = Arc::new(PosterSyncHandler::new(handler_ctx, 3));
let (event_publisher, consumer) = create_event_channel(EventPublisherConfig::from_env());
let worker = WorkerService::new(Arc::new(consumer), vec![poster_handler]);
tokio::spawn(worker.run());
(Arc::new(event_publisher), axum::Router::new())
};
let (event_publisher_arc, ap_router): (Arc<dyn EventPublisher>, axum::Router) = (
build_event_publisher(handler_ctx, vec![]).await?,
axum::Router::new(),
);
let app_ctx = AppContext {
movie_repository,
@@ -302,6 +294,23 @@ async fn wire_postgres(database_url: &str) -> anyhow::Result<(
Ok((pool, movie_repository, review_repository, diary_repository, stats_repository, user_repository))
}
async fn build_event_publisher(
handler_ctx: AppContext,
extra_handlers: Vec<Arc<dyn EventHandler>>,
) -> anyhow::Result<Arc<dyn EventPublisher>> {
if let Ok(cfg) = nats::NatsConfig::from_env() {
tracing::info!("event bus: NATS ({})", cfg.url);
return nats::create_publisher(cfg).await;
}
tracing::info!("event bus: in-memory");
let poster_handler = Arc::new(PosterSyncHandler::new(handler_ctx, 3));
let mut handlers: Vec<Arc<dyn EventHandler>> = vec![poster_handler];
handlers.extend(extra_handlers);
let (publisher, consumer) = create_event_channel(EventPublisherConfig::from_env());
tokio::spawn(WorkerService::new(Arc::new(consumer), handlers).run());
Ok(Arc::new(publisher))
}
fn init_tracing() {
tracing_subscriber::registry()
.with(tracing_subscriber::EnvFilter::new(