perf(federation): always prefer the shared inbox
Followers-only posts and DMs went to each recipient's personal inbox, so a followers-only post was sent once per follower on the same server. Mastodon, GoToSocial and Iceshrimp.NET always use the shared inbox. Only activities with bcc or bto still go to personal inboxes. Based on Akkoma a80444041. Co-authored-by: Oneric <oneric@oneric.stub>
This commit is contained in:
parent
d54ff52691
commit
5a5f4794d3
3 changed files with 52 additions and 29 deletions
1
changelog.d/shared-inbox.change
Normal file
1
changelog.d/shared-inbox.change
Normal file
|
|
@ -0,0 +1 @@
|
|||
Deliver to shared inboxes whenever possible, including followers-only posts and DMs, so each server gets one copy
|
||||
|
|
@ -281,36 +281,18 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
defp maybe_use_sharedinbox(%User{shared_inbox: shared_inbox}), do: shared_inbox
|
||||
|
||||
@doc """
|
||||
Determine a user inbox to use based on heuristics. These heuristics
|
||||
are based on an approximation of the ``sharedInbox`` rules in the
|
||||
[ActivityPub specification][ap-sharedinbox].
|
||||
Determines the inbox to deliver an activity to.
|
||||
|
||||
Please do not edit this function (or its children) without reading
|
||||
the spec, as editing the code is likely to introduce some breakage
|
||||
without some familiarity.
|
||||
|
||||
[ap-sharedinbox]: https://www.w3.org/TR/activitypub/#shared-inbox-delivery
|
||||
Like Mastodon, GoToSocial and Akkoma, this always prefers the shared inbox,
|
||||
which saves duplicate deliveries to the same server. Only activities with
|
||||
`bcc` or `bto` go to personal inboxes, because the receiver rebuilds that
|
||||
addressing from the inbox the activity arrived at.
|
||||
"""
|
||||
def determine_inbox(
|
||||
%Activity{data: activity_data},
|
||||
%User{inbox: inbox} = user
|
||||
) do
|
||||
to = activity_data["to"] || []
|
||||
cc = activity_data["cc"] || []
|
||||
type = activity_data["type"]
|
||||
|
||||
cond do
|
||||
type == "Delete" ->
|
||||
maybe_use_sharedinbox(user)
|
||||
|
||||
Pleroma.Constants.as_public() in to || Pleroma.Constants.as_public() in cc ->
|
||||
maybe_use_sharedinbox(user)
|
||||
|
||||
length(to) + length(cc) > 1 ->
|
||||
maybe_use_sharedinbox(user)
|
||||
|
||||
true ->
|
||||
inbox
|
||||
def determine_inbox(%Activity{data: activity_data}, %User{inbox: inbox} = user) do
|
||||
if Enum.empty?(activity_data["bcc"] || []) and Enum.empty?(activity_data["bto"] || []) do
|
||||
maybe_use_sharedinbox(user)
|
||||
else
|
||||
inbox
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
|
|||
assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
|
||||
end
|
||||
|
||||
test "it returns inbox for messages involving single recipients in total" do
|
||||
test "it returns sharedInbox for messages to a single recipient" do
|
||||
user =
|
||||
insert(:user, %{
|
||||
shared_inbox: "http://example.com/inbox",
|
||||
|
|
@ -148,6 +148,46 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
|
|||
data: %{"to" => [user.ap_id], "cc" => []}
|
||||
}
|
||||
|
||||
assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
|
||||
end
|
||||
|
||||
test "it returns sharedInbox for followers-only messages" do
|
||||
user =
|
||||
insert(:user, %{
|
||||
shared_inbox: "http://example.com/inbox",
|
||||
inbox: "http://example.com/personal-inbox"
|
||||
})
|
||||
|
||||
author = insert(:user)
|
||||
|
||||
activity = %Activity{
|
||||
data: %{"to" => [author.follower_address], "cc" => []}
|
||||
}
|
||||
|
||||
assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
|
||||
end
|
||||
|
||||
test "it returns inbox for messages with bcc or bto, which needs personal inboxes" do
|
||||
user =
|
||||
insert(:user, %{
|
||||
shared_inbox: "http://example.com/inbox",
|
||||
inbox: "http://example.com/personal-inbox"
|
||||
})
|
||||
|
||||
for field <- ["bcc", "bto"] do
|
||||
activity = %Activity{
|
||||
data: %{"to" => [@as_public], "cc" => [], field => [user.ap_id]}
|
||||
}
|
||||
|
||||
assert Publisher.determine_inbox(activity, user) == "http://example.com/personal-inbox"
|
||||
end
|
||||
end
|
||||
|
||||
test "it returns inbox when the user has no sharedInbox" do
|
||||
user = insert(:user, %{shared_inbox: nil, inbox: "http://example.com/personal-inbox"})
|
||||
|
||||
activity = %Activity{data: %{"to" => [@as_public], "cc" => []}}
|
||||
|
||||
assert Publisher.determine_inbox(activity, user) == "http://example.com/personal-inbox"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue