fix: wire DeliveryRequested federation events — outbound AP delivery was broken
FederationEventBridge silently dropped DeliveryRequested events from k-ap, so no Create/Delete/Accept activities were pushed to follower inboxes. Reviews only reached remote instances via outbox backfill (pull), and deletes never propagated. Bridge now publishes FederationDeliveryRequested domain events through the event bus; worker calls ap_service.deliver_to_inbox() to send them.
This commit is contained in:
@@ -80,6 +80,23 @@ impl EventHandler for ActivityPubEventHandler {
|
|||||||
.on_watchlist_removed(user_id, movie_id)
|
.on_watchlist_removed(user_id, movie_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| DomainError::InfrastructureError(e.to_string())),
|
.map_err(|e| DomainError::InfrastructureError(e.to_string())),
|
||||||
|
DomainEvent::FederationDeliveryRequested {
|
||||||
|
inbox_url,
|
||||||
|
activity_json,
|
||||||
|
signing_actor_id,
|
||||||
|
} => {
|
||||||
|
let inbox: url::Url = inbox_url
|
||||||
|
.parse()
|
||||||
|
.map_err(|e| DomainError::InfrastructureError(format!("bad inbox URL: {e}")))?;
|
||||||
|
let activity: serde_json::Value =
|
||||||
|
serde_json::from_str(activity_json).map_err(|e| {
|
||||||
|
DomainError::InfrastructureError(format!("bad activity JSON: {e}"))
|
||||||
|
})?;
|
||||||
|
self.ap_service
|
||||||
|
.deliver_to_inbox(inbox, activity, *signing_actor_id)
|
||||||
|
.await
|
||||||
|
.map_err(|e| DomainError::InfrastructureError(e.to_string()))
|
||||||
|
}
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,24 @@ impl k_ap::EventPublisher for FederationEventBridge {
|
|||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.map_err(|e| anyhow::anyhow!(e.to_string())),
|
.map_err(|e| anyhow::anyhow!(e.to_string())),
|
||||||
_ => {
|
FederationEvent::DeliveryRequested {
|
||||||
tracing::debug!("ignoring federation event: {:?}", event);
|
inbox,
|
||||||
|
activity,
|
||||||
|
signing_actor_id,
|
||||||
|
} => {
|
||||||
|
let json = serde_json::to_string(&activity)
|
||||||
|
.map_err(|e| anyhow::anyhow!("serialize activity: {e}"))?;
|
||||||
|
self.domain_publisher
|
||||||
|
.publish(&DomainEvent::FederationDeliveryRequested {
|
||||||
|
inbox_url: inbox.to_string(),
|
||||||
|
activity_json: json,
|
||||||
|
signing_actor_id,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map_err(|e| anyhow::anyhow!(e.to_string()))
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
tracing::debug!("ignoring federation event: {:?}", other);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,11 @@ pub enum EventPayload {
|
|||||||
owner_user_id: String,
|
owner_user_id: String,
|
||||||
follower_inbox_url: String,
|
follower_inbox_url: String,
|
||||||
},
|
},
|
||||||
|
FederationDeliveryRequested {
|
||||||
|
inbox_url: String,
|
||||||
|
activity_json: String,
|
||||||
|
signing_actor_id: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventPayload {
|
impl EventPayload {
|
||||||
@@ -84,6 +89,7 @@ impl EventPayload {
|
|||||||
EventPayload::WatchlistEntryRemoved { .. } => "WatchlistEntryRemoved",
|
EventPayload::WatchlistEntryRemoved { .. } => "WatchlistEntryRemoved",
|
||||||
EventPayload::FollowAccepted { .. } => "FollowAccepted",
|
EventPayload::FollowAccepted { .. } => "FollowAccepted",
|
||||||
EventPayload::BackfillFollower { .. } => "BackfillFollower",
|
EventPayload::BackfillFollower { .. } => "BackfillFollower",
|
||||||
|
EventPayload::FederationDeliveryRequested { .. } => "FederationDeliveryRequested",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,6 +199,15 @@ impl From<&DomainEvent> for EventPayload {
|
|||||||
owner_user_id: owner_user_id.value().to_string(),
|
owner_user_id: owner_user_id.value().to_string(),
|
||||||
follower_inbox_url: follower_inbox_url.clone(),
|
follower_inbox_url: follower_inbox_url.clone(),
|
||||||
},
|
},
|
||||||
|
DomainEvent::FederationDeliveryRequested {
|
||||||
|
inbox_url,
|
||||||
|
activity_json,
|
||||||
|
signing_actor_id,
|
||||||
|
} => EventPayload::FederationDeliveryRequested {
|
||||||
|
inbox_url: inbox_url.clone(),
|
||||||
|
activity_json: activity_json.clone(),
|
||||||
|
signing_actor_id: signing_actor_id.to_string(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,6 +315,15 @@ impl TryFrom<EventPayload> for DomainEvent {
|
|||||||
owner_user_id: UserId::from_uuid(parse_uuid(&owner_user_id, "owner_user_id")?),
|
owner_user_id: UserId::from_uuid(parse_uuid(&owner_user_id, "owner_user_id")?),
|
||||||
follower_inbox_url,
|
follower_inbox_url,
|
||||||
}),
|
}),
|
||||||
|
EventPayload::FederationDeliveryRequested {
|
||||||
|
inbox_url,
|
||||||
|
activity_json,
|
||||||
|
signing_actor_id,
|
||||||
|
} => Ok(DomainEvent::FederationDeliveryRequested {
|
||||||
|
inbox_url,
|
||||||
|
activity_json,
|
||||||
|
signing_actor_id: parse_uuid(&signing_actor_id, "signing_actor_id")?,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ pub fn event_to_subject(prefix: &str, event: &DomainEvent) -> String {
|
|||||||
DomainEvent::WatchlistEntryRemoved { .. } => "watchlist.entry.removed",
|
DomainEvent::WatchlistEntryRemoved { .. } => "watchlist.entry.removed",
|
||||||
DomainEvent::FollowAccepted { .. } => "follow.accepted",
|
DomainEvent::FollowAccepted { .. } => "follow.accepted",
|
||||||
DomainEvent::BackfillFollower { .. } => "backfill.follower",
|
DomainEvent::BackfillFollower { .. } => "backfill.follower",
|
||||||
|
DomainEvent::FederationDeliveryRequested { .. } => "federation.delivery.requested",
|
||||||
};
|
};
|
||||||
format!("{prefix}.{suffix}")
|
format!("{prefix}.{suffix}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ impl EventHandler for RecordingHandler {
|
|||||||
}
|
}
|
||||||
DomainEvent::FollowAccepted { .. } => "follow_accepted",
|
DomainEvent::FollowAccepted { .. } => "follow_accepted",
|
||||||
DomainEvent::BackfillFollower { .. } => "backfill_follower",
|
DomainEvent::BackfillFollower { .. } => "backfill_follower",
|
||||||
|
DomainEvent::FederationDeliveryRequested { .. } => "federation_delivery",
|
||||||
};
|
};
|
||||||
self.calls.lock().unwrap().push(label);
|
self.calls.lock().unwrap().push(label);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -65,6 +65,11 @@ pub enum DomainEvent {
|
|||||||
owner_user_id: UserId,
|
owner_user_id: UserId,
|
||||||
follower_inbox_url: String,
|
follower_inbox_url: String,
|
||||||
},
|
},
|
||||||
|
FederationDeliveryRequested {
|
||||||
|
inbox_url: String,
|
||||||
|
activity_json: String,
|
||||||
|
signing_actor_id: uuid::Uuid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|||||||
Reference in New Issue
Block a user