feat(nodeinfo): extract and save NodeInfo information from instances to display it on instances list
We also try to detect the application actor if it's not given by NodeInfo metadata (FEP-2677) (guessing for Mobilizon, PeerTube & Mastodon). Closes #1392 Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -3,14 +3,16 @@ defmodule Mobilizon.Service.Workers.RefreshInstances do
|
||||
Worker to refresh the instances materialized view and the relay actors
|
||||
"""
|
||||
|
||||
use Oban.Worker, unique: [period: :infinity, keys: [:event_uuid, :action]]
|
||||
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
|
||||
alias Mobilizon.Instances.{Instance, InstanceActor}
|
||||
alias Oban.Job
|
||||
require Logger
|
||||
|
||||
@impl Oban.Worker
|
||||
@spec perform(Oban.Job.t()) :: :ok
|
||||
@@ -30,6 +32,8 @@ defmodule Mobilizon.Service.Workers.RefreshInstances do
|
||||
{:error, :not_remote_instance}
|
||||
end
|
||||
|
||||
@spec refresh_instance_actor(Instance.t()) ::
|
||||
{:ok, InstanceActor.t()} | {:error, Ecto.Changeset.t()} | {:error, atom}
|
||||
def refresh_instance_actor(%Instance{domain: domain}) do
|
||||
%Actor{url: url} = Relay.get_actor()
|
||||
%URI{host: host} = URI.new!(url)
|
||||
@@ -37,7 +41,67 @@ defmodule Mobilizon.Service.Workers.RefreshInstances do
|
||||
if host == domain do
|
||||
{:error, :not_remote_instance}
|
||||
else
|
||||
ActivityPubActor.find_or_make_actor_from_nickname("relay@#{domain}")
|
||||
actor_id =
|
||||
case fetch_actor(domain) do
|
||||
{:ok, %Actor{id: actor_id}} -> actor_id
|
||||
_ -> nil
|
||||
end
|
||||
|
||||
with instance_metadata <- fetch_instance_metadata(domain),
|
||||
:ok <- Logger.debug("Ready to save instance actor details"),
|
||||
{:ok, %InstanceActor{}} <-
|
||||
Instances.create_instance_actor(%{
|
||||
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"])
|
||||
}) do
|
||||
Logger.info("Saved instance actor details for domain #{host}")
|
||||
else
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user