Actor suspension refactoring

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2021-09-10 11:36:05 +02:00
parent e9fecc4d24
commit 75e254d8b4
23 changed files with 816 additions and 603 deletions

View File

@@ -14,65 +14,62 @@ defmodule Mobilizon.Federation.ActivityPub.Actor do
@doc """
Getting an actor from url, eventually creating it if we don't have it locally or if it needs an update
"""
@spec get_or_fetch_actor_by_url(String.t(), boolean) :: {:ok, Actor.t()} | {:error, String.t()}
@spec get_or_fetch_actor_by_url(url :: String.t(), preload :: boolean()) ::
{:ok, Actor.t()}
| {:error, make_actor_errors}
| {:error, :no_internal_relay_actor}
| {:error, :url_nil}
def get_or_fetch_actor_by_url(url, preload \\ false)
def get_or_fetch_actor_by_url(nil, _preload), do: {:error, "Can't fetch a nil url"}
def get_or_fetch_actor_by_url(nil, _preload), do: {:error, :url_nil}
def get_or_fetch_actor_by_url("https://www.w3.org/ns/activitystreams#Public", _preload) do
with %Actor{url: url} <- Relay.get_actor() do
get_or_fetch_actor_by_url(url)
case Relay.get_actor() do
%Actor{url: url} ->
get_or_fetch_actor_by_url(url)
{:error, %Ecto.Changeset{}} ->
{:error, :no_internal_relay_actor}
end
end
@spec get_or_fetch_actor_by_url(String.t(), boolean()) :: {:ok, Actor.t()} | {:error, any()}
def get_or_fetch_actor_by_url(url, preload) do
with {:ok, %Actor{} = cached_actor} <- Actors.get_actor_by_url(url, preload),
false <- Actors.needs_update?(cached_actor) do
{:ok, cached_actor}
else
_ ->
# For tests, see https://github.com/jjh42/mock#not-supported---mocking-internal-function-calls and Mobilizon.Federation.ActivityPubTest
case __MODULE__.make_actor_from_url(url, preload) do
{:ok, %Actor{} = actor} ->
{:ok, actor}
{:error, err} ->
Logger.debug("Could not fetch by AP id")
Logger.debug(inspect(err))
{:error, "Could not fetch by AP id"}
case Actors.get_actor_by_url(url, preload) do
{:ok, %Actor{} = cached_actor} ->
unless Actors.needs_update?(cached_actor) do
{:ok, cached_actor}
else
__MODULE__.make_actor_from_url(url, preload)
end
{:error, :actor_not_found} ->
# For tests, see https://github.com/jjh42/mock#not-supported---mocking-internal-function-calls and Mobilizon.Federation.ActivityPubTest
__MODULE__.make_actor_from_url(url, preload)
end
end
@type make_actor_errors :: Fetcher.fetch_actor_errors() | :actor_is_local
@doc """
Create an actor locally by its URL (AP ID)
"""
@spec make_actor_from_url(String.t(), boolean()) ::
{:ok, %Actor{}} | {:error, :actor_deleted} | {:error, :http_error} | {:error, any()}
@spec make_actor_from_url(url :: String.t(), preload :: boolean()) ::
{:ok, Actor.t()} | {:error, make_actor_errors}
def make_actor_from_url(url, preload \\ false) do
if are_same_origin?(url, Endpoint.url()) do
{:error, "Can't make a local actor from URL"}
{:error, :actor_is_local}
else
case Fetcher.fetch_and_prepare_actor_from_url(url) do
# Just in case
{:ok, {:error, _e}} ->
raise ArgumentError, message: "Failed to make actor from url #{url}"
{:ok, data} ->
{:ok, data} when is_map(data) ->
Actors.upsert_actor(data, preload)
# Request returned 410
{:error, :actor_deleted} ->
Logger.info("Actor was deleted")
Logger.info("Actor #{url} was deleted")
{:error, :actor_deleted}
{:error, :http_error} ->
{:error, :http_error}
{:error, e} ->
Logger.warn("Failed to make actor from url #{url}")
{:error, e}
{:error, err} when err in [:http_error, :json_decode_error] ->
{:error, err}
end
end
end
@@ -80,8 +77,8 @@ defmodule Mobilizon.Federation.ActivityPub.Actor do
@doc """
Find an actor in our local database or call WebFinger to find what's its AP ID is and then fetch it
"""
@spec find_or_make_actor_from_nickname(String.t(), atom() | nil) ::
{:ok, Actor.t()} | {:error, any()}
@spec find_or_make_actor_from_nickname(nickname :: String.t(), type :: atom() | nil) ::
{:ok, Actor.t()} | {:error, make_actor_errors | WebFinger.finger_errors()}
def find_or_make_actor_from_nickname(nickname, type \\ nil) do
case Actors.get_actor_by_name_with_preload(nickname, type) do
%Actor{url: actor_url} = actor ->
@@ -96,20 +93,22 @@ defmodule Mobilizon.Federation.ActivityPub.Actor do
end
end
@spec find_or_make_group_from_nickname(String.t()) :: tuple()
@spec find_or_make_group_from_nickname(nick :: String.t()) ::
{:error, make_actor_errors | WebFinger.finger_errors()}
def find_or_make_group_from_nickname(nick), do: find_or_make_actor_from_nickname(nick, :Group)
@doc """
Create an actor inside our database from username, using WebFinger to find out its AP ID and then fetch it
"""
@spec make_actor_from_nickname(String.t()) :: {:ok, %Actor{}} | {:error, any()}
@spec make_actor_from_nickname(nickname :: String.t(), preload :: boolean) ::
{:ok, Actor.t()} | {:error, make_actor_errors | WebFinger.finger_errors()}
def make_actor_from_nickname(nickname, preload \\ false) do
case WebFinger.finger(nickname) do
{:ok, url} when is_binary(url) ->
make_actor_from_url(url, preload)
{:error, _e} ->
{:error, "No ActivityPub URL found in WebFinger"}
{:error, e} ->
{:error, e}
end
end
end