refactor(domain): remove FetchRemoteActorPosts/FetchActorConnections from DomainEvent; add FederationSchedulerPort
This commit is contained in:
@@ -1592,6 +1592,39 @@ impl domain::ports::OutboundFederationPort for ActivityPubService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl domain::ports::FederationSchedulerPort for ActivityPubService {
|
||||||
|
async fn schedule_actor_posts_fetch(
|
||||||
|
&self,
|
||||||
|
actor_ap_url: &str,
|
||||||
|
outbox_url: &str,
|
||||||
|
) -> Result<(), domain::errors::DomainError> {
|
||||||
|
tracing::debug!(
|
||||||
|
actor = actor_ap_url,
|
||||||
|
outbox = outbox_url,
|
||||||
|
"schedule_actor_posts_fetch: deferred"
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn schedule_connections_fetch(
|
||||||
|
&self,
|
||||||
|
actor_ap_url: &str,
|
||||||
|
collection_url: &str,
|
||||||
|
connection_type: &str,
|
||||||
|
page: u32,
|
||||||
|
) -> Result<(), domain::errors::DomainError> {
|
||||||
|
tracing::debug!(
|
||||||
|
actor = actor_ap_url,
|
||||||
|
collection = collection_url,
|
||||||
|
connection_type,
|
||||||
|
page,
|
||||||
|
"schedule_connections_fetch: deferred"
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl domain::ports::FederationActionPort for ActivityPubService {
|
impl domain::ports::FederationActionPort for ActivityPubService {
|
||||||
async fn lookup_actor(
|
async fn lookup_actor(
|
||||||
|
|||||||
@@ -71,16 +71,6 @@ pub enum EventPayload {
|
|||||||
ProfileUpdated {
|
ProfileUpdated {
|
||||||
user_id: String,
|
user_id: String,
|
||||||
},
|
},
|
||||||
FetchRemoteActorPosts {
|
|
||||||
actor_ap_url: String,
|
|
||||||
outbox_url: String,
|
|
||||||
},
|
|
||||||
FetchActorConnections {
|
|
||||||
actor_ap_url: String,
|
|
||||||
collection_url: String,
|
|
||||||
connection_type: String,
|
|
||||||
page: u32,
|
|
||||||
},
|
|
||||||
MentionReceived {
|
MentionReceived {
|
||||||
thought_id: String,
|
thought_id: String,
|
||||||
mentioned_user_id: String,
|
mentioned_user_id: String,
|
||||||
@@ -107,8 +97,6 @@ impl EventPayload {
|
|||||||
Self::UserUnblocked { .. } => "users.unblocked",
|
Self::UserUnblocked { .. } => "users.unblocked",
|
||||||
Self::UserRegistered { .. } => "users.registered",
|
Self::UserRegistered { .. } => "users.registered",
|
||||||
Self::ProfileUpdated { .. } => "users.profile_updated",
|
Self::ProfileUpdated { .. } => "users.profile_updated",
|
||||||
Self::FetchRemoteActorPosts { .. } => "federation.fetch_outbox",
|
|
||||||
Self::FetchActorConnections { .. } => "federation.fetch_connections",
|
|
||||||
Self::MentionReceived { .. } => "mentions.received",
|
Self::MentionReceived { .. } => "mentions.received",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,24 +210,6 @@ impl From<&DomainEvent> for EventPayload {
|
|||||||
DomainEvent::ProfileUpdated { user_id } => Self::ProfileUpdated {
|
DomainEvent::ProfileUpdated { user_id } => Self::ProfileUpdated {
|
||||||
user_id: user_id.to_string(),
|
user_id: user_id.to_string(),
|
||||||
},
|
},
|
||||||
DomainEvent::FetchRemoteActorPosts {
|
|
||||||
actor_ap_url,
|
|
||||||
outbox_url,
|
|
||||||
} => Self::FetchRemoteActorPosts {
|
|
||||||
actor_ap_url: actor_ap_url.clone(),
|
|
||||||
outbox_url: outbox_url.clone(),
|
|
||||||
},
|
|
||||||
DomainEvent::FetchActorConnections {
|
|
||||||
actor_ap_url,
|
|
||||||
collection_url,
|
|
||||||
connection_type,
|
|
||||||
page,
|
|
||||||
} => Self::FetchActorConnections {
|
|
||||||
actor_ap_url: actor_ap_url.clone(),
|
|
||||||
collection_url: collection_url.clone(),
|
|
||||||
connection_type: connection_type.clone(),
|
|
||||||
page: *page,
|
|
||||||
},
|
|
||||||
DomainEvent::MentionReceived {
|
DomainEvent::MentionReceived {
|
||||||
thought_id,
|
thought_id,
|
||||||
mentioned_user_id,
|
mentioned_user_id,
|
||||||
@@ -370,24 +340,6 @@ impl TryFrom<EventPayload> for DomainEvent {
|
|||||||
EventPayload::ProfileUpdated { user_id } => DomainEvent::ProfileUpdated {
|
EventPayload::ProfileUpdated { user_id } => DomainEvent::ProfileUpdated {
|
||||||
user_id: UserId::from_uuid(parse_uuid(&user_id, "user_id")?),
|
user_id: UserId::from_uuid(parse_uuid(&user_id, "user_id")?),
|
||||||
},
|
},
|
||||||
EventPayload::FetchRemoteActorPosts {
|
|
||||||
actor_ap_url,
|
|
||||||
outbox_url,
|
|
||||||
} => DomainEvent::FetchRemoteActorPosts {
|
|
||||||
actor_ap_url,
|
|
||||||
outbox_url,
|
|
||||||
},
|
|
||||||
EventPayload::FetchActorConnections {
|
|
||||||
actor_ap_url,
|
|
||||||
collection_url,
|
|
||||||
connection_type,
|
|
||||||
page,
|
|
||||||
} => DomainEvent::FetchActorConnections {
|
|
||||||
actor_ap_url,
|
|
||||||
collection_url,
|
|
||||||
connection_type,
|
|
||||||
page,
|
|
||||||
},
|
|
||||||
EventPayload::MentionReceived {
|
EventPayload::MentionReceived {
|
||||||
thought_id,
|
thought_id,
|
||||||
mentioned_user_id,
|
mentioned_user_id,
|
||||||
@@ -481,16 +433,6 @@ mod tests {
|
|||||||
EventPayload::UserRegistered {
|
EventPayload::UserRegistered {
|
||||||
user_id: "a".into(),
|
user_id: "a".into(),
|
||||||
},
|
},
|
||||||
EventPayload::FetchRemoteActorPosts {
|
|
||||||
actor_ap_url: "https://mastodon.social/users/alice".into(),
|
|
||||||
outbox_url: "https://mastodon.social/users/alice/outbox".into(),
|
|
||||||
},
|
|
||||||
EventPayload::FetchActorConnections {
|
|
||||||
actor_ap_url: "https://mastodon.social/users/alice".into(),
|
|
||||||
collection_url: "https://mastodon.social/users/alice/followers".into(),
|
|
||||||
connection_type: "followers".into(),
|
|
||||||
page: 1,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
let mut subjects: Vec<&str> = samples.iter().map(|p| p.subject()).collect();
|
let mut subjects: Vec<&str> = samples.iter().map(|p| p.subject()).collect();
|
||||||
subjects.sort();
|
subjects.sort();
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ pub struct FederationEventService {
|
|||||||
pub users: Arc<dyn UserRepository>,
|
pub users: Arc<dyn UserRepository>,
|
||||||
pub ap: Arc<dyn OutboundFederationPort>,
|
pub ap: Arc<dyn OutboundFederationPort>,
|
||||||
pub base_url: String,
|
pub base_url: String,
|
||||||
pub federation_action: Arc<dyn domain::ports::FederationActionPort>,
|
|
||||||
pub ap_repo: Arc<dyn ActivityPubRepository>,
|
pub ap_repo: Arc<dyn ActivityPubRepository>,
|
||||||
pub remote_actor_connections: Arc<dyn domain::ports::RemoteActorConnectionRepository>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FederationEventService {
|
impl FederationEventService {
|
||||||
@@ -148,112 +146,6 @@ impl FederationEventService {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
DomainEvent::FetchRemoteActorPosts {
|
|
||||||
actor_ap_url,
|
|
||||||
outbox_url,
|
|
||||||
} => {
|
|
||||||
let notes = match self
|
|
||||||
.federation_action
|
|
||||||
.fetch_outbox_page(outbox_url, 1)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(n) => n,
|
|
||||||
Err(e) => {
|
|
||||||
tracing::warn!(outbox_url, error = %e, "failed to fetch remote outbox");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let actor_url = url::Url::parse(actor_ap_url)
|
|
||||||
.map_err(|e| DomainError::ExternalService(e.to_string()))?;
|
|
||||||
|
|
||||||
let author_id = self.ap_repo.intern_remote_actor(&actor_url).await?;
|
|
||||||
|
|
||||||
// Resolve and cache display info so thought cards show proper names.
|
|
||||||
let profiles = self
|
|
||||||
.federation_action
|
|
||||||
.resolve_actor_profiles(vec![actor_ap_url.clone()])
|
|
||||||
.await;
|
|
||||||
if let Some(profile) = profiles.into_iter().next() {
|
|
||||||
let _ = self
|
|
||||||
.ap_repo
|
|
||||||
.update_remote_actor_display(
|
|
||||||
&author_id,
|
|
||||||
profile.display_name.as_deref(),
|
|
||||||
profile.avatar_url.as_deref(),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
for note in notes {
|
|
||||||
let ap_id = match url::Url::parse(¬e.ap_id) {
|
|
||||||
Ok(u) => u,
|
|
||||||
Err(_) => continue,
|
|
||||||
};
|
|
||||||
let _ = self
|
|
||||||
.ap_repo
|
|
||||||
.accept_note(
|
|
||||||
&ap_id,
|
|
||||||
&author_id,
|
|
||||||
¬e.content,
|
|
||||||
note.published,
|
|
||||||
note.sensitive,
|
|
||||||
note.content_warning,
|
|
||||||
"public",
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
DomainEvent::FetchActorConnections {
|
|
||||||
actor_ap_url,
|
|
||||||
collection_url,
|
|
||||||
connection_type,
|
|
||||||
page,
|
|
||||||
} => {
|
|
||||||
let urls = match self
|
|
||||||
.federation_action
|
|
||||||
.fetch_actor_urls_from_collection(collection_url)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(u) => u,
|
|
||||||
Err(e) => {
|
|
||||||
tracing::warn!(
|
|
||||||
collection_url,
|
|
||||||
error = %e,
|
|
||||||
"failed to fetch actor connections collection"
|
|
||||||
);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if urls.is_empty() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let summaries = self.federation_action.resolve_actor_profiles(urls).await;
|
|
||||||
|
|
||||||
if summaries.is_empty() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
tracing::info!(
|
|
||||||
count = summaries.len(),
|
|
||||||
connection_type,
|
|
||||||
actor = actor_ap_url,
|
|
||||||
"caching actor connections"
|
|
||||||
);
|
|
||||||
|
|
||||||
self.remote_actor_connections
|
|
||||||
.upsert_connections(actor_ap_url, connection_type, *page, &summaries)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
DomainEvent::LikeAdded {
|
DomainEvent::LikeAdded {
|
||||||
like_id: _,
|
like_id: _,
|
||||||
user_id,
|
user_id,
|
||||||
@@ -438,9 +330,7 @@ mod tests {
|
|||||||
users: Arc::new(store.clone()),
|
users: Arc::new(store.clone()),
|
||||||
ap: spy,
|
ap: spy,
|
||||||
base_url: "https://example.com".to_string(),
|
base_url: "https://example.com".to_string(),
|
||||||
federation_action: Arc::new(store.clone()),
|
|
||||||
ap_repo: Arc::new(store.clone()),
|
ap_repo: Arc::new(store.clone()),
|
||||||
remote_actor_connections: Arc::new(store.clone()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -772,35 +662,6 @@ mod tests {
|
|||||||
assert!(spy.updated.lock().unwrap().is_empty());
|
assert!(spy.updated.lock().unwrap().is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn fetch_remote_actor_posts_is_noop_when_outbox_empty() {
|
|
||||||
let store = TestStore::default();
|
|
||||||
let spy = Arc::new(SpyPort::default());
|
|
||||||
svc(&store, spy.clone())
|
|
||||||
.process(&DomainEvent::FetchRemoteActorPosts {
|
|
||||||
actor_ap_url: "https://mastodon.social/users/alice".into(),
|
|
||||||
outbox_url: "https://mastodon.social/users/alice/outbox".into(),
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
// TestStore.fetch_outbox_page returns Ok(vec![]) — no notes, no error
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn fetch_actor_connections_is_noop_when_collection_empty() {
|
|
||||||
let store = TestStore::default();
|
|
||||||
let spy = Arc::new(SpyPort::default());
|
|
||||||
svc(&store, spy.clone())
|
|
||||||
.process(&DomainEvent::FetchActorConnections {
|
|
||||||
actor_ap_url: "https://mastodon.social/users/alice".into(),
|
|
||||||
collection_url: "https://mastodon.social/users/alice/followers".into(),
|
|
||||||
connection_type: "followers".into(),
|
|
||||||
page: 1,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn like_added_local_user_remote_thought_broadcasts_like() {
|
async fn like_added_local_user_remote_thought_broadcasts_like() {
|
||||||
let store = TestStore::default();
|
let store = TestStore::default();
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
use domain::{
|
use domain::{
|
||||||
errors::DomainError,
|
errors::DomainError,
|
||||||
events::DomainEvent,
|
|
||||||
models::{
|
models::{
|
||||||
actor_connection_summary::ActorConnectionSummary,
|
actor_connection_summary::ActorConnectionSummary,
|
||||||
feed::{FeedEntry, PageParams, Paginated},
|
feed::{FeedEntry, PageParams, Paginated},
|
||||||
remote_actor::RemoteActor,
|
remote_actor::RemoteActor,
|
||||||
},
|
},
|
||||||
ports::{
|
ports::{
|
||||||
ActivityPubRepository, EventPublisher, FederationActionPort, FeedRepository,
|
ActivityPubRepository, EventPublisher, FederationActionPort, FederationSchedulerPort,
|
||||||
FollowRepository, RemoteActorConnectionRepository, UserRepository,
|
FeedRepository, FollowRepository, RemoteActorConnectionRepository, UserRepository,
|
||||||
},
|
},
|
||||||
value_objects::UserId,
|
value_objects::UserId,
|
||||||
};
|
};
|
||||||
@@ -75,7 +74,7 @@ pub async fn get_remote_actor_posts(
|
|||||||
federation: &dyn FederationActionPort,
|
federation: &dyn FederationActionPort,
|
||||||
ap_repo: &dyn ActivityPubRepository,
|
ap_repo: &dyn ActivityPubRepository,
|
||||||
feed: &dyn FeedRepository,
|
feed: &dyn FeedRepository,
|
||||||
events: &dyn EventPublisher,
|
scheduler: &dyn FederationSchedulerPort,
|
||||||
handle: &str,
|
handle: &str,
|
||||||
page: PageParams,
|
page: PageParams,
|
||||||
viewer_id: Option<&UserId>,
|
viewer_id: Option<&UserId>,
|
||||||
@@ -88,11 +87,8 @@ pub async fn get_remote_actor_posts(
|
|||||||
};
|
};
|
||||||
let result = feed.user_feed(&author_id, &page, viewer_id).await?;
|
let result = feed.user_feed(&author_id, &page, viewer_id).await?;
|
||||||
if let Some(outbox_url) = actor.outbox_url {
|
if let Some(outbox_url) = actor.outbox_url {
|
||||||
let _ = events
|
let _ = scheduler
|
||||||
.publish(&DomainEvent::FetchRemoteActorPosts {
|
.schedule_actor_posts_fetch(&actor.url, &outbox_url)
|
||||||
actor_ap_url: actor.url,
|
|
||||||
outbox_url,
|
|
||||||
})
|
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
@@ -103,7 +99,7 @@ const ACTOR_CONNECTIONS_CACHE_TTL_SECS: i64 = 3600;
|
|||||||
pub async fn get_actor_connections_page(
|
pub async fn get_actor_connections_page(
|
||||||
federation: &dyn FederationActionPort,
|
federation: &dyn FederationActionPort,
|
||||||
connections: &dyn RemoteActorConnectionRepository,
|
connections: &dyn RemoteActorConnectionRepository,
|
||||||
events: &dyn EventPublisher,
|
scheduler: &dyn FederationSchedulerPort,
|
||||||
handle: &str,
|
handle: &str,
|
||||||
connection_type: &str,
|
connection_type: &str,
|
||||||
page: u32,
|
page: u32,
|
||||||
@@ -128,13 +124,8 @@ pub async fn get_actor_connections_page(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if stale {
|
if stale {
|
||||||
let _ = events
|
let _ = scheduler
|
||||||
.publish(&DomainEvent::FetchActorConnections {
|
.schedule_connections_fetch(&actor.url, &collection_url, connection_type, page)
|
||||||
actor_ap_url: actor.url,
|
|
||||||
collection_url,
|
|
||||||
connection_type: connection_type.to_string(),
|
|
||||||
page,
|
|
||||||
})
|
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
let has_more = items.len() >= PAGE_SIZE;
|
let has_more = items.len() >= PAGE_SIZE;
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ pub async fn build(cfg: &Config) -> Infrastructure {
|
|||||||
federation: ap_service.clone() as Arc<dyn domain::ports::FederationActionPort>,
|
federation: ap_service.clone() as Arc<dyn domain::ports::FederationActionPort>,
|
||||||
ap_repo: Arc::new(PgActivityPubRepository::new(pool.clone())),
|
ap_repo: Arc::new(PgActivityPubRepository::new(pool.clone())),
|
||||||
remote_actor_connections: Arc::new(PgRemoteActorConnectionRepository::new(pool.clone())),
|
remote_actor_connections: Arc::new(PgRemoteActorConnectionRepository::new(pool.clone())),
|
||||||
|
federation_scheduler: ap_service.clone() as Arc<dyn domain::ports::FederationSchedulerPort>,
|
||||||
};
|
};
|
||||||
|
|
||||||
Infrastructure { state, ap_service }
|
Infrastructure { state, ap_service }
|
||||||
|
|||||||
@@ -63,16 +63,6 @@ pub enum DomainEvent {
|
|||||||
ProfileUpdated {
|
ProfileUpdated {
|
||||||
user_id: UserId,
|
user_id: UserId,
|
||||||
},
|
},
|
||||||
FetchRemoteActorPosts {
|
|
||||||
actor_ap_url: String,
|
|
||||||
outbox_url: String,
|
|
||||||
},
|
|
||||||
FetchActorConnections {
|
|
||||||
actor_ap_url: String,
|
|
||||||
collection_url: String,
|
|
||||||
connection_type: String,
|
|
||||||
page: u32,
|
|
||||||
},
|
|
||||||
MentionReceived {
|
MentionReceived {
|
||||||
thought_id: ThoughtId,
|
thought_id: ThoughtId,
|
||||||
mentioned_user_id: UserId,
|
mentioned_user_id: UserId,
|
||||||
|
|||||||
@@ -497,3 +497,20 @@ pub trait OutboundFederationPort: Send + Sync {
|
|||||||
/// Fan out an Update(Actor) to all accepted followers after a profile change.
|
/// Fan out an Update(Actor) to all accepted followers after a profile change.
|
||||||
async fn broadcast_actor_update(&self, user_id: &UserId) -> Result<(), DomainError>;
|
async fn broadcast_actor_update(&self, user_id: &UserId) -> Result<(), DomainError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait FederationSchedulerPort: Send + Sync {
|
||||||
|
async fn schedule_actor_posts_fetch(
|
||||||
|
&self,
|
||||||
|
actor_ap_url: &str,
|
||||||
|
outbox_url: &str,
|
||||||
|
) -> Result<(), DomainError>;
|
||||||
|
|
||||||
|
async fn schedule_connections_fetch(
|
||||||
|
&self,
|
||||||
|
actor_ap_url: &str,
|
||||||
|
collection_url: &str,
|
||||||
|
connection_type: &str,
|
||||||
|
page: u32,
|
||||||
|
) -> Result<(), DomainError>;
|
||||||
|
}
|
||||||
|
|||||||
@@ -903,6 +903,22 @@ impl ActivityPubRepository for TestStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl FederationSchedulerPort for TestStore {
|
||||||
|
async fn schedule_actor_posts_fetch(&self, _: &str, _: &str) -> Result<(), DomainError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
async fn schedule_connections_fetch(
|
||||||
|
&self,
|
||||||
|
_: &str,
|
||||||
|
_: &str,
|
||||||
|
_: &str,
|
||||||
|
_: u32,
|
||||||
|
) -> Result<(), DomainError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl EventPublisher for TestStore {
|
impl EventPublisher for TestStore {
|
||||||
async fn publish(&self, event: &DomainEvent) -> Result<(), DomainError> {
|
async fn publish(&self, event: &DomainEvent) -> Result<(), DomainError> {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ pub async fn remote_actor_posts_handler(
|
|||||||
&*s.federation,
|
&*s.federation,
|
||||||
&*s.ap_repo,
|
&*s.ap_repo,
|
||||||
&*s.feed,
|
&*s.feed,
|
||||||
&*s.events,
|
&*s.federation_scheduler,
|
||||||
&handle,
|
&handle,
|
||||||
page,
|
page,
|
||||||
viewer.as_ref(),
|
viewer.as_ref(),
|
||||||
@@ -68,7 +68,7 @@ async fn actor_connections_handler(
|
|||||||
let (items, has_more) = get_actor_connections_page(
|
let (items, has_more) = get_actor_connections_page(
|
||||||
&*s.federation,
|
&*s.federation,
|
||||||
&*s.remote_actor_connections,
|
&*s.remote_actor_connections,
|
||||||
&*s.events,
|
&*s.federation_scheduler,
|
||||||
&handle,
|
&handle,
|
||||||
connection_type,
|
connection_type,
|
||||||
page,
|
page,
|
||||||
|
|||||||
@@ -22,4 +22,5 @@ pub struct AppState {
|
|||||||
pub federation: Arc<dyn FederationActionPort>,
|
pub federation: Arc<dyn FederationActionPort>,
|
||||||
pub ap_repo: Arc<dyn ActivityPubRepository>,
|
pub ap_repo: Arc<dyn ActivityPubRepository>,
|
||||||
pub remote_actor_connections: Arc<dyn RemoteActorConnectionRepository>,
|
pub remote_actor_connections: Arc<dyn RemoteActorConnectionRepository>,
|
||||||
|
pub federation_scheduler: Arc<dyn FederationSchedulerPort>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,5 +51,6 @@ pub fn make_state() -> AppState {
|
|||||||
federation: store.clone(),
|
federation: store.clone(),
|
||||||
ap_repo: store.clone(),
|
ap_repo: store.clone(),
|
||||||
remote_actor_connections: store.clone(),
|
remote_actor_connections: store.clone(),
|
||||||
|
federation_scheduler: store.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,8 @@ use std::sync::Arc;
|
|||||||
use activitypub::ThoughtsObjectHandler;
|
use activitypub::ThoughtsObjectHandler;
|
||||||
use activitypub_base::ActivityPubService;
|
use activitypub_base::ActivityPubService;
|
||||||
use application::services::{FederationEventService, NotificationEventService};
|
use application::services::{FederationEventService, NotificationEventService};
|
||||||
use domain::ports::{ActivityPubRepository, FederationActionPort, OutboundFederationPort};
|
use domain::ports::{ActivityPubRepository, OutboundFederationPort};
|
||||||
use postgres::activitypub::PgActivityPubRepository;
|
use postgres::activitypub::PgActivityPubRepository;
|
||||||
use postgres::remote_actor_connections::PgRemoteActorConnectionRepository;
|
|
||||||
use postgres_federation::{PostgresApUserRepository, PostgresFederationRepository};
|
use postgres_federation::{PostgresApUserRepository, PostgresFederationRepository};
|
||||||
|
|
||||||
use crate::handlers::{FederationHandler, NotificationHandler};
|
use crate::handlers::{FederationHandler, NotificationHandler};
|
||||||
@@ -58,11 +57,8 @@ pub async fn build(
|
|||||||
.expect("ActivityPubService build failed"),
|
.expect("ActivityPubService build failed"),
|
||||||
);
|
);
|
||||||
let ap_outbound = ap_service.clone() as Arc<dyn OutboundFederationPort>;
|
let ap_outbound = ap_service.clone() as Arc<dyn OutboundFederationPort>;
|
||||||
let ap_federation = ap_service.clone() as Arc<dyn FederationActionPort>;
|
|
||||||
let ap_repo_worker =
|
let ap_repo_worker =
|
||||||
Arc::new(PgActivityPubRepository::new(pool.clone())) as Arc<dyn ActivityPubRepository>;
|
Arc::new(PgActivityPubRepository::new(pool.clone())) as Arc<dyn ActivityPubRepository>;
|
||||||
let actor_connections = Arc::new(PgRemoteActorConnectionRepository::new(pool.clone()))
|
|
||||||
as Arc<dyn domain::ports::RemoteActorConnectionRepository>;
|
|
||||||
|
|
||||||
// Application services
|
// Application services
|
||||||
let notification_svc = Arc::new(NotificationEventService {
|
let notification_svc = Arc::new(NotificationEventService {
|
||||||
@@ -74,9 +70,7 @@ pub async fn build(
|
|||||||
users,
|
users,
|
||||||
ap: ap_outbound,
|
ap: ap_outbound,
|
||||||
base_url: base_url.to_string(),
|
base_url: base_url.to_string(),
|
||||||
federation_action: ap_federation,
|
|
||||||
ap_repo: ap_repo_worker,
|
ap_repo: ap_repo_worker,
|
||||||
remote_actor_connections: actor_connections,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Thin handlers
|
// Thin handlers
|
||||||
|
|||||||
1230
docs/superpowers/plans/2026-05-15-domain-application-refactor.md
Normal file
1230
docs/superpowers/plans/2026-05-15-domain-application-refactor.md
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user