defmodule Clacks.ActivityPub.Fetcher do require Logger @spec fetch_actor(id :: String.t()) :: map() | nil def fetch_actor(id) do %{host: id_host} = URI.parse(id) with %{"type" => type, "id" => remote_id} = actor <- fetch(id), "person" <- String.downcase(type), %{host: ^id_host} <- URI.parse(remote_id) do actor else _ -> nil end end @spec fetch_object(id :: String.t()) :: map() | nil def fetch_object(id) do %{host: id_host} = URI.parse(id) with %{"actor" => remote_actor} = object <- fetch(id), %{host: ^id_host} <- URI.parse(remote_actor) do object else _ -> nil end end @spec fetch_activity(id :: String.t()) :: map() | nil def fetch_activity(id) do fetch_object(id) end @spec fetch(uri :: String.t()) :: map() | nil defp fetch(uri) do Logger.debug("Attempting to fetch AP object at #{uri}") headers = [Accept: "application/activity+json, application/ld+json"] opts = [hackney: Application.get_env(:clacks, :hackney_opts, [])] with {:ok, %HTTPoison.Response{status_code: status_code, body: body}} when status_code in 200..299 <- HTTPoison.get(uri, headers, opts), {:ok, data} <- Jason.decode(body) do data else {:ok, %HTTPoison.Response{}} -> nil {:error, reason} -> Logger.warn("Couldn't fetch AP object at #{uri}: #{inspect(reason)}") nil end end end