+ if needs_update(existing_record) do
+ Logger.info("Updating metadata for #{host}")
+ favicon = scrape_favicon(uri)
+ nodeinfo = scrape_nodeinfo(uri)
+
+ existing_record
+ |> changeset(%{
+ host: host,
+ favicon: favicon,
+ nodeinfo: nodeinfo,
+ metadata_updated_at: NaiveDateTime.utc_now()
+ })
+ |> Repo.update()
+ else
+ {:discard, "Does not require update"}
+ end
+ else
+ favicon = scrape_favicon(uri)
+ nodeinfo = scrape_nodeinfo(uri)
+
+ Logger.info("Creating metadata for #{host}")
+
+ %Instance{}
+ |> changeset(%{
+ host: host,
+ favicon: favicon,
+ nodeinfo: nodeinfo,
+ metadata_updated_at: NaiveDateTime.utc_now()
+ })
+ |> Repo.insert()
+ end
+ end
+
+ def get_favicon(%URI{host: host}) do
+ existing_record = Repo.get_by(Instance, %{host: host})
+
+ if existing_record do
+ existing_record.favicon
+ else
+ nil
+ end
+ end
+
+ defp scrape_nodeinfo(%URI{} = instance_uri) do
+ with true <- Pleroma.Config.get([:instances_nodeinfo, :enabled]),
+ {_, true} <- {:reachable, reachable?(instance_uri.host)},
+ {:ok, %Tesla.Env{status: 200, body: body}} <-
+ Tesla.get(
+ "https://#{instance_uri.host}/.well-known/nodeinfo",
+ headers: [{"Accept", "application/json"}]
+ ),
+ {:ok, json} <- Jason.decode(body),
+ {:ok, %{"links" => links}} <- {:ok, json},
+ {:ok, %{"href" => href}} <-
+ {:ok,
+ Enum.find(links, &(&1["rel"] == "http://nodeinfo.diaspora.software/ns/schema/2.0"))},
+ {:ok, %Tesla.Env{body: data}} <-
+ Pleroma.HTTP.get(href, [{"accept", "application/json"}], []),
+ {:length, true} <- {:length, String.length(data) < 50_000},
+ {:ok, nodeinfo} <- Jason.decode(data) do
+ nodeinfo
+ else
+ {:reachable, false} ->
+ Logger.debug(
+ "Instance.scrape_nodeinfo(\"#{to_string(instance_uri)}\") ignored unreachable host"
+ )
+
+ nil
+
+ {:length, false} ->
+ Logger.debug(
+ "Instance.scrape_nodeinfo(\"#{to_string(instance_uri)}\") ignored too long body"
+ )