forked from potsda.mn/mobilizon
c3aa145148
And use it to log refreshing instance errors Signed-off-by: Thomas Citharel <tcit@tcit.fr>
109 lines
3.3 KiB
Elixir
109 lines
3.3 KiB
Elixir
defmodule Mobilizon.Service.Workers.RefreshInstances do
|
|
@moduledoc """
|
|
Worker to refresh the instances materialized view and the relay actors
|
|
"""
|
|
|
|
use Oban.Worker
|
|
|
|
alias Mobilizon.Actors.Actor
|
|
alias Mobilizon.Federation.ActivityPub.Actor, as: ActivityPubActor
|
|
alias Mobilizon.Federation.ActivityPub.Relay
|
|
alias Mobilizon.Federation.NodeInfo
|
|
alias Mobilizon.Instances
|
|
alias Mobilizon.Instances.{Instance, InstanceActor}
|
|
alias Oban.Job
|
|
require Logger
|
|
import Mobilizon.Storage.Ecto, only: [convert_ecto_errors: 1]
|
|
|
|
@impl Oban.Worker
|
|
@spec perform(Oban.Job.t()) :: :ok
|
|
def perform(%Job{}) do
|
|
Instances.refresh()
|
|
|
|
Instances.all_domains()
|
|
|> Enum.each(fn %Instance{domain: domain} -> refresh_instance_actor(domain) end)
|
|
end
|
|
|
|
@spec refresh_instance_actor(String.t() | nil) ::
|
|
{:ok, Mobilizon.Actors.Actor.t()} | {:error, Ecto.Changeset.t()} | {:error, atom}
|
|
def refresh_instance_actor(nil) do
|
|
{:error, :not_remote_instance}
|
|
end
|
|
|
|
def refresh_instance_actor(domain) do
|
|
%Actor{url: url} = Relay.get_actor()
|
|
%URI{host: host} = URI.new!(url)
|
|
|
|
if host == domain do
|
|
{:error, :not_remote_instance}
|
|
else
|
|
actor_id =
|
|
case fetch_actor(domain) do
|
|
{:ok, %Actor{id: actor_id}} -> actor_id
|
|
_ -> nil
|
|
end
|
|
|
|
with instance_metadata <- fetch_instance_metadata(domain),
|
|
args <- %{
|
|
domain: domain,
|
|
actor_id: actor_id,
|
|
instance_name: get_in(instance_metadata, ["metadata", "nodeName"]),
|
|
instance_description: get_in(instance_metadata, ["metadata", "nodeDescription"]),
|
|
software: get_in(instance_metadata, ["software", "name"]),
|
|
software_version: get_in(instance_metadata, ["software", "version"])
|
|
},
|
|
:ok <- Logger.debug("Ready to save instance actor details #{inspect(args)}"),
|
|
{:ok, %InstanceActor{}} <-
|
|
Instances.create_instance_actor(args) do
|
|
Logger.info("Saved instance actor details for domain #{host}")
|
|
else
|
|
{:error, %Ecto.Changeset{} = changeset} ->
|
|
Logger.error("Unable to save instance \"#{domain}\" metadata")
|
|
Logger.debug(convert_ecto_errors(changeset))
|
|
|
|
err ->
|
|
Logger.error(inspect(err))
|
|
end
|
|
end
|
|
end
|
|
|
|
defp mobilizon(domain), do: "relay@#{domain}"
|
|
defp peertube(domain), do: "peertube@#{domain}"
|
|
defp mastodon(domain), do: "#{domain}@#{domain}"
|
|
|
|
defp fetch_actor(domain) do
|
|
case NodeInfo.application_actor(domain) do
|
|
nil -> guess_application_actor(domain)
|
|
url -> ActivityPubActor.get_or_fetch_actor_by_url(url)
|
|
end
|
|
end
|
|
|
|
defp fetch_instance_metadata(domain) do
|
|
case NodeInfo.nodeinfo(domain) do
|
|
{:error, _} ->
|
|
%{}
|
|
|
|
{:ok, metadata} ->
|
|
metadata
|
|
end
|
|
end
|
|
|
|
defp guess_application_actor(domain) do
|
|
Enum.find_value(
|
|
[
|
|
&mobilizon/1,
|
|
&peertube/1,
|
|
&mastodon/1
|
|
],
|
|
{:error, :no_application_actor_found},
|
|
fn username_pattern ->
|
|
case ActivityPubActor.find_or_make_actor_from_nickname(username_pattern.(domain)) do
|
|
{:ok, %Actor{type: :Application} = actor} -> {:ok, actor}
|
|
{:error, _err} -> false
|
|
{:ok, _actor} -> false
|
|
end
|
|
end
|
|
)
|
|
end
|
|
end
|