pub mod composite_handler; pub mod deletion_notifier; pub mod event_handler; pub mod federation_event_bridge; pub mod federation_ports; pub mod goal_handler; pub mod objects; pub mod remote_review_repository; pub mod review_handler; pub mod social_adapter; pub mod tombstone_gate; pub(crate) mod urls; pub mod user_adapter; pub mod watchlist_handler; pub const INSTANCE_ACTOR_ID: uuid::Uuid = uuid::Uuid::from_bytes([0, 0, 0, 0, 0, 0, 0x40, 0, 0x80, 0, 0, 0, 0, 0, 0, 0]); pub use k_ap::{ ActivityPubService, ActivityRepository, ActorRepository, ApContentReader, ApFederationConfig, ApObjectHandler, ApUser, ApUserRepository, BlocklistRepository, FederationData, FollowRepository, Follower, FollowerStatus, FollowingStatus, LocalObject, RemoteActor, }; pub use deletion_notifier::ApDeletionNotifier; pub use event_handler::ActivityPubEventHandler; pub use federation_ports::ApServiceAdapter; pub use remote_review_repository::{NewRemoteReview, RemoteReviewRepository, RemoteReviewUpdate}; pub use review_handler::ReviewObjectHandler; pub use social_adapter::CompositeSocialAdapter; pub use user_adapter::DomainUserRepoAdapter; pub struct FederationRepos { pub activity: std::sync::Arc, pub follow: std::sync::Arc, pub actor: std::sync::Arc, pub blocklist: std::sync::Arc, pub admin_query: std::sync::Arc, pub review_store: std::sync::Arc, pub remote_watchlist: std::sync::Arc, pub follow_command: std::sync::Arc, pub follow_query: std::sync::Arc, } pub struct ActivityPubWire { pub document: std::sync::Arc, pub blocklist: std::sync::Arc, pub backfill: std::sync::Arc, pub service: std::sync::Arc, pub router: axum::Router, pub event_handler: std::sync::Arc, pub deletion_notifier: std::sync::Arc, } pub struct ActivityPubDeps { pub activity_repo: std::sync::Arc, pub follow_repo: std::sync::Arc, pub actor_repo: std::sync::Arc, pub blocklist_repo: std::sync::Arc, pub review_store: std::sync::Arc, pub remote_watchlist_repo: std::sync::Arc, pub remote_goal_repo: std::sync::Arc, pub local_ap_content: std::sync::Arc, pub movie_repo: std::sync::Arc, pub review_repo: std::sync::Arc, pub diary_repo: std::sync::Arc, pub goal_repo: std::sync::Arc, pub stats_repo: std::sync::Arc, pub user_repo: std::sync::Arc, pub federation_settings: std::sync::Arc, pub follow_command: std::sync::Arc, pub follow_query: std::sync::Arc, pub instance: domain::value_objects::InstanceIdentity, pub allow_registration: bool, pub federation: config::FederationConfig, pub event_publisher: std::sync::Arc, } pub async fn wire(deps: ActivityPubDeps) -> anyhow::Result { let ActivityPubDeps { activity_repo, follow_repo, actor_repo, blocklist_repo, review_store, remote_watchlist_repo, remote_goal_repo, local_ap_content, movie_repo, review_repo, diary_repo, goal_repo, stats_repo, user_repo, federation_settings, follow_command: _, follow_query: _, instance, allow_registration, federation, event_publisher, } = deps; let review_handler = std::sync::Arc::new(ReviewObjectHandler { content_query: std::sync::Arc::clone(&local_ap_content), movie_repo: std::sync::Arc::clone(&movie_repo), diary_repo, review_store, instance: instance.clone(), }); let watchlist_handler = std::sync::Arc::new(watchlist_handler::WatchlistObjectHandler { remote_watchlist_repo, content_query: std::sync::Arc::clone(&local_ap_content), instance: instance.clone(), }); let goal_handler = std::sync::Arc::new(goal_handler::GoalObjectHandler { remote_goal_repo, goal_repo: std::sync::Arc::clone(&goal_repo), instance: instance.clone(), }); let composite = std::sync::Arc::new(composite_handler::CompositeObjectHandler { review: review_handler, watchlist: watchlist_handler, goal: goal_handler, }); let federation_debug = federation.debug; if federation_debug { tracing::warn!( "federation running in DEBUG mode — PermissiveVerifier active, \ no URL/signature validation. Do NOT use in production." ); } let fed_event_bridge = std::sync::Arc::new( federation_event_bridge::FederationEventBridge::new(event_publisher), ); let concrete = std::sync::Arc::new( ActivityPubService::builder(instance.base_url().to_string()) .activity_repo(activity_repo) .follow_repo(follow_repo) .actor_repo(actor_repo) .blocklist_repo(blocklist_repo) .user_repo(std::sync::Arc::new(DomainUserRepoAdapter::new( std::sync::Arc::clone(&user_repo), instance.clone(), ))) .signed_fetch_actor_id(INSTANCE_ACTOR_ID) .content_reader(composite.clone() as std::sync::Arc) .object_handler(composite as std::sync::Arc) .event_publisher(fed_event_bridge) .allow_registration(allow_registration) .software_name("movies-diary") .nodeinfo_metadata(serde_json::json!({ "nodeName": "movies-diary", "nodeDescription": "A federated movie diary" })) .debug(federation_debug) .build() .await?, ); let router = concrete .router() .layer(axum::middleware::from_fn_with_state( std::sync::Arc::clone(&user_repo), tombstone_gate::tombstone_gate, )); let deletion_notifier = std::sync::Arc::new(ApDeletionNotifier::new( std::sync::Arc::clone(&concrete), instance.clone(), )) as std::sync::Arc; let event_handler = std::sync::Arc::new(ActivityPubEventHandler::new( std::sync::Arc::clone(&concrete), local_ap_content, review_repo, movie_repo, goal_repo, stats_repo, federation_settings, std::sync::Arc::clone(&user_repo), instance, )) as std::sync::Arc; let ports = std::sync::Arc::new(federation_ports::ApServiceAdapter::new( std::sync::Arc::clone(&concrete), std::sync::Arc::clone(&user_repo), )); Ok(ActivityPubWire { document: std::sync::Arc::clone(&ports) as std::sync::Arc, blocklist: std::sync::Arc::clone(&ports) as std::sync::Arc, backfill: ports as std::sync::Arc, service: concrete, router, event_handler, deletion_notifier, }) }