One delivery a server; BookWyrm 0.9.3 in the pasture
An activity now goes once to each server, to its shared inbox when it has one, for the accounts a post names, answers or quotes as for its followers, as Mastodon delivers (a circle post excepted: each member's copy names that member). BookWyrm took the same post twice when one copy reached its shared inbox and another the named account's inbox at once. SharedInboxTests checks a reply to a follower's post goes once. BookWyrm joins the pasture (peers/bookwyrm.sh: its image on the shared Postgres and Redis, gunicorn and a Celery worker, its user, book and statuses made in its Django shell). scenarios/bookwyrm.sh: follows both ways, a review, a comment and a quotation reaching alice as BookWyrm's pure posts, her like, boost and reply landing there, her post naming bwuser and bwuser's like and reply, a deletion, the unfollow and statistics: 20 checks. GoToSocial (64), Mastodon (57) and Misskey (35) still pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
12b51a211a
commit
53158b4cf4
9 files changed
+243
-21
No files matched your search
@@ -58,15 +58,15 @@ namespace PrivaPub.Federation.Outbox
|
||||
foreach (var uri in addressed)
|
||||
{
|
||||
var actor = await _dbEntities.ForeignAvatars.Match(a => a.ActorURI == uri).ExecuteFirstAsync(token);
|
||||
if (actor != default && !string.IsNullOrEmpty(actor.InboxURL))
|
||||
inboxes.Add(actor.InboxURL);
|
||||
if (Preferred(actor) is { } inbox)
|
||||
inboxes.Add(inbox);
|
||||
}
|
||||
|
||||
if (post.Visibility != PostVisibility.Direct && !string.IsNullOrEmpty(post.InReplyToAccountId))
|
||||
{
|
||||
var parentAuthor = await _dbEntities.ForeignAvatars.MatchID(post.InReplyToAccountId).ExecuteFirstAsync(token);
|
||||
if (parentAuthor != default && !string.IsNullOrEmpty(parentAuthor.InboxURL) && !blockers.Contains(parentAuthor.ActorURI))
|
||||
inboxes.Add(parentAuthor.InboxURL);
|
||||
if (Preferred(parentAuthor) is { } inbox && !blockers.Contains(parentAuthor.ActorURI))
|
||||
inboxes.Add(inbox);
|
||||
}
|
||||
|
||||
if (post.Visibility is PostVisibility.Public or PostVisibility.Unlisted && !string.IsNullOrEmpty(post.QuotedPostId))
|
||||
@@ -75,13 +75,19 @@ namespace PrivaPub.Federation.Outbox
|
||||
var quotedAuthor = quoted is { IsFederatedCopy: true }
|
||||
? await _dbEntities.ForeignAvatars.Match(a => a.ActorURI == quoted.ActorURI).ExecuteFirstAsync(token)
|
||||
: default;
|
||||
if (!string.IsNullOrEmpty(quotedAuthor?.InboxURL))
|
||||
inboxes.Add(quotedAuthor.InboxURL);
|
||||
if (Preferred(quotedAuthor) is { } inbox)
|
||||
inboxes.Add(inbox);
|
||||
}
|
||||
|
||||
return inboxes.Where(i => !string.IsNullOrEmpty(i)).Distinct(StringComparer.Ordinal).ToList();
|
||||
}
|
||||
|
||||
// a server's shared inbox when it has one, as Mastodon delivers: one delivery a server, whoever on it is named, and
|
||||
// none of the races a server runs into when the same activity reaches two of its inboxes at once (BookWyrm kept
|
||||
// two copies of a post that named a follower)
|
||||
static string Preferred(ForeignAvatar actor) =>
|
||||
actor == default ? default : !string.IsNullOrEmpty(actor.SharedInboxURL) ? actor.SharedInboxURL : actor.InboxURL is { Length: > 0 } inbox ? inbox : default;
|
||||
|
||||
async Task<IReadOnlyList<string>> CircleMembers(string groupId, CancellationToken token) =>
|
||||
(await CircleRecipients(groupId, token)).Select(r => r.InboxURL).Distinct(StringComparer.Ordinal).ToList();
|
||||
|
||||
|
||||
Reference in new issue
Block a user