InboxService is split the way the roadmap lays out Federation/Inbox:
- InboxReceiver reads and verifies the request exactly as before, runs
the checks that need no fetch (the activity id's origin, a Follow of a
missing or local-only actor, an Undo of someone else's activity, an
embedded object attributed to someone else), queues a ProcessInbox job
and answers 202. The job's dedupe key is the activity id, so a peer that
delivers the same activity twice is processed once.
- InboxProcessor (two at a time, eight attempts) loads the verified actor
and hands the activity to the handler for its type.
- Handlers/{Follow,Undo,Create,Delete,Update}Handler are the old methods,
unchanged except that they no longer produce status codes; the JSON
helpers live in Objects/ActivityJson and the group membership helpers in
Inbox/ForeignMembers.
A slow fetch of an object or a remote actor now delays the job, not the
sender's HTTP request.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
38 lines
1.4 KiB
C#
38 lines
1.4 KiB
C#
using MongoDB.Entities;
|
|
|
|
using PrivaPub.Federation.Actors;
|
|
using PrivaPub.Models.Federation;
|
|
using PrivaPub.Models.Group;
|
|
|
|
using GroupEntity = PrivaPub.Models.Group.Group;
|
|
|
|
namespace PrivaPub.Federation.Inbox
|
|
{
|
|
public static class ForeignMembers
|
|
{
|
|
public static async Task<bool> IsAcceptedFollower(LocalActor group, string actorUri, CancellationToken token) =>
|
|
await DB.Default.Find<Follower>()
|
|
.Match(f => f.LocalActorId == group.Id && f.LocalActorKind == LocalActorKind.Group && f.ActorURI == actorUri && f.IsAccepted)
|
|
.ExecuteAnyAsync(token);
|
|
|
|
public static async Task AddForeignMember(string groupId, string actorUri, CancellationToken token)
|
|
{
|
|
var group = await DB.Default.Find<GroupEntity>().MatchID(groupId).ExecuteFirstAsync(token);
|
|
if (group == default || group.Members.Any(m => m.IsForeign && m.AvatarId == actorUri))
|
|
return;
|
|
group.Members.Add(new GroupMember { AvatarId = actorUri, IsForeign = true });
|
|
group.UpdatedAt = DateTime.UtcNow;
|
|
await DB.Default.SaveAsync(group, token);
|
|
}
|
|
|
|
public static async Task RemoveForeignMember(string groupId, string actorUri, CancellationToken token)
|
|
{
|
|
var group = await DB.Default.Find<GroupEntity>().MatchID(groupId).ExecuteFirstAsync(token);
|
|
if (group == default || group.Members.RemoveAll(m => m.IsForeign && m.AvatarId == actorUri) == 0)
|
|
return;
|
|
group.UpdatedAt = DateTime.UtcNow;
|
|
await DB.Default.SaveAsync<GroupEntity>(group, token);
|
|
}
|
|
}
|
|
}
|