203 lines
7.9 KiB
Rust
203 lines
7.9 KiB
Rust
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<dyn ActivityRepository>,
|
|
pub follow: std::sync::Arc<dyn FollowRepository>,
|
|
pub actor: std::sync::Arc<dyn ActorRepository>,
|
|
pub blocklist: std::sync::Arc<dyn BlocklistRepository>,
|
|
pub admin_query: std::sync::Arc<dyn domain::ports::FederationAdminQuery>,
|
|
pub review_store: std::sync::Arc<dyn RemoteReviewRepository>,
|
|
pub remote_watchlist: std::sync::Arc<dyn domain::ports::RemoteWatchlistRepository>,
|
|
pub follow_command: std::sync::Arc<dyn domain::ports::FollowCommand>,
|
|
pub follow_query: std::sync::Arc<dyn domain::ports::FollowQuery>,
|
|
}
|
|
|
|
pub struct ActivityPubWire {
|
|
pub document: std::sync::Arc<dyn domain::ports::ApDocumentPort>,
|
|
pub blocklist: std::sync::Arc<dyn domain::ports::InstanceBlocklistPort>,
|
|
pub backfill: std::sync::Arc<dyn domain::ports::ApBackfillPort>,
|
|
pub service: std::sync::Arc<ActivityPubService>,
|
|
pub router: axum::Router,
|
|
pub event_handler: std::sync::Arc<dyn domain::ports::EventHandler>,
|
|
pub deletion_notifier: std::sync::Arc<dyn domain::ports::FederationDeletionNotifier>,
|
|
}
|
|
|
|
pub struct ActivityPubDeps {
|
|
pub activity_repo: std::sync::Arc<dyn ActivityRepository>,
|
|
pub follow_repo: std::sync::Arc<dyn FollowRepository>,
|
|
pub actor_repo: std::sync::Arc<dyn ActorRepository>,
|
|
pub blocklist_repo: std::sync::Arc<dyn BlocklistRepository>,
|
|
pub review_store: std::sync::Arc<dyn RemoteReviewRepository>,
|
|
pub remote_watchlist_repo: std::sync::Arc<dyn domain::ports::RemoteWatchlistRepository>,
|
|
pub remote_goal_repo: std::sync::Arc<dyn domain::ports::RemoteGoalRepository>,
|
|
pub local_ap_content: std::sync::Arc<dyn domain::ports::LocalApContentQuery>,
|
|
pub movie_repo: std::sync::Arc<dyn domain::ports::MovieQuery>,
|
|
pub review_repo: std::sync::Arc<dyn domain::ports::ReviewRepository>,
|
|
pub diary_repo: std::sync::Arc<dyn domain::ports::DiaryQuery>,
|
|
pub goal_repo: std::sync::Arc<dyn domain::ports::GoalQuery>,
|
|
pub stats_repo: std::sync::Arc<dyn domain::ports::StatsRepository>,
|
|
pub user_repo: std::sync::Arc<dyn domain::ports::UserRepository>,
|
|
pub federation_settings: std::sync::Arc<dyn domain::ports::UserFederationSettingsQuery>,
|
|
pub follow_command: std::sync::Arc<dyn domain::ports::FollowCommand>,
|
|
pub follow_query: std::sync::Arc<dyn domain::ports::FollowQuery>,
|
|
pub instance: domain::value_objects::InstanceIdentity,
|
|
pub allow_registration: bool,
|
|
pub federation: config::FederationConfig,
|
|
pub event_publisher: std::sync::Arc<dyn domain::ports::EventPublisher>,
|
|
}
|
|
|
|
pub async fn wire(deps: ActivityPubDeps) -> anyhow::Result<ActivityPubWire> {
|
|
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<dyn ApContentReader>)
|
|
.object_handler(composite as std::sync::Arc<dyn ApObjectHandler>)
|
|
.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<dyn domain::ports::FederationDeletionNotifier>;
|
|
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<dyn domain::ports::EventHandler>;
|
|
|
|
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<dyn domain::ports::ApDocumentPort>,
|
|
blocklist: std::sync::Arc::clone(&ports)
|
|
as std::sync::Arc<dyn domain::ports::InstanceBlocklistPort>,
|
|
backfill: ports as std::sync::Arc<dyn domain::ports::ApBackfillPort>,
|
|
service: concrete,
|
|
router,
|
|
event_handler,
|
|
deletion_notifier,
|
|
})
|
|
}
|