Skip to content

Commit

Permalink
Fix fetching of community posts (fixes #4283)
Browse files Browse the repository at this point in the history
Also use spawn_try_task to fetch community outbox, mods etc to avoid
delay/timeout when fetching new community.
  • Loading branch information
Nutomic committed Dec 18, 2023
1 parent aab3ca4 commit 3dcd2db
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 22 deletions.
22 changes: 22 additions & 0 deletions api_tests/src/community.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,3 +480,25 @@ test("Dont receive community activities after unsubscribe", async () => {
let postResBeta = searchPostLocal(beta, postRes.post_view.post);
expect((await postResBeta).posts.length).toBe(0);
});

test("Fetch community, includes posts", async () => {
let communityRes = await createCommunity(alpha);
expect(communityRes.community_view.community.name).toBeDefined();
expect(communityRes.community_view.counts.subscribers).toBe(1);

let postRes = await createPost(alpha, communityRes.community_view.community.id);
expect(postRes.post_view.post).toBeDefined();

let resolvedCommunity = await waitUntil(
() => resolveCommunity(beta, communityRes.community_view.community.actor_id),
c => c.community?.community.id != undefined,
);
let betaCommunity = resolvedCommunity.community;
expect(betaCommunity?.community.actor_id).toBe(communityRes.community_view.community.actor_id);

await longDelay();

let post_listing = await getPosts(beta, 'All');
expect(post_listing.posts.length).toBe(1);
expect(post_listing.posts[0].post.ap_id).toBe(postRes.post_view.post.ap_id);
});
20 changes: 15 additions & 5 deletions crates/apub/src/collections/community_outbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,21 @@ impl Collection for ApubCommunityOutbox {
// process items in parallel, to avoid long delay from fetch_site_metadata() and other processing
join_all(outbox_activities.into_iter().map(|activity| {
async {
// use separate request counter for each item, otherwise there will be problems with
// parallel processing
let verify = activity.verify(data).await;
if verify.is_ok() {
activity.receive(data).await.ok();
// Receiving announce requires at least one local community follower for anti spam purposes.
// This won't be the case for newly fetched communities, so we extract the inner activity
// and handle it directly to bypass this check.
let inner: Option<AnnouncableActivities> = activity
.object
.object(data)
.await
.ok()
.map(|o| o.try_into().ok())
.flatten();
if let Some(AnnouncableActivities::CreateOrUpdatePost(inner)) = inner {
let verify = inner.verify(data).await;
if verify.is_ok() {
inner.receive(data).await.ok();
}
}
}
}))
Expand Down
28 changes: 11 additions & 17 deletions crates/apub/src/objects/community.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,8 @@ use lemmy_db_schema::{
traits::{ApubActor, Crud},
};
use lemmy_db_views_actor::structs::CommunityFollowerView;
use lemmy_utils::{error::LemmyError, utils::markdown::markdown_to_html};
use lemmy_utils::{error::LemmyError, spawn_try_task, utils::markdown::markdown_to_html};
use std::ops::Deref;
use tracing::debug;
use url::Url;

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -142,21 +141,16 @@ impl Object for ApubCommunity {

// Fetching mods and outbox is not necessary for Lemmy to work, so ignore errors. Besides,
// we need to ignore these errors so that tests can work entirely offline.
let fetch_outbox = group.outbox.dereference(&community, context);
let fetch_followers = group.followers.dereference(&community, context);

if let Some(moderators) = group.attributed_to {
let fetch_moderators = moderators.dereference(&community, context);
// Fetch mods, outbox and followers in parallel
let res = tokio::join!(fetch_outbox, fetch_moderators, fetch_followers);
res.0.map_err(|e| debug!("{}", e)).ok();
res.1.map_err(|e| debug!("{}", e)).ok();
res.2.map_err(|e| debug!("{}", e)).ok();
} else {
let res = tokio::join!(fetch_outbox, fetch_followers);
res.0.map_err(|e| debug!("{}", e)).ok();
res.1.map_err(|e| debug!("{}", e)).ok();
}
let community_ = community.clone();
let context_ = context.reset_request_count();
spawn_try_task(async move {
group.outbox.dereference(&community_, &context_).await?;
group.followers.dereference(&community_, &context_).await?;
if let Some(moderators) = group.attributed_to {
moderators.dereference(&community_, &context_).await?;
}
Ok(())
});

Ok(community)
}
Expand Down

0 comments on commit 3dcd2db

Please sign in to comment.