c95d35bb912c6a215f5db83d5cd11ff155129934
[anni] / lib / pleroma / web / activity_pub / mrf / media_proxy_warming_policy.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do
6   @moduledoc "Preloads any attachments in the MediaProxy cache by prefetching them"
7   @behaviour Pleroma.Web.ActivityPub.MRF.Policy
8
9   alias Pleroma.HTTP
10   alias Pleroma.Web.MediaProxy
11
12   require Logger
13
14   @adapter_options [
15     pool: :media,
16     recv_timeout: 10_000
17   ]
18
19   @impl true
20   def history_awareness, do: :auto
21
22   defp prefetch(url) do
23     # Fetching only proxiable resources
24     if MediaProxy.enabled?() and MediaProxy.url_proxiable?(url) do
25       # If preview proxy is enabled, it'll also hit media proxy (so we're caching both requests)
26       prefetch_url = MediaProxy.preview_url(url)
27
28       Logger.debug("Prefetching #{inspect(url)} as #{inspect(prefetch_url)}")
29
30       if Pleroma.Config.get(:env) == :test do
31         fetch(prefetch_url)
32       else
33         ConcurrentLimiter.limit(__MODULE__, fn ->
34           Task.start(fn -> fetch(prefetch_url) end)
35         end)
36       end
37     end
38   end
39
40   defp fetch(url), do: HTTP.get(url, [], @adapter_options)
41
42   defp preload(%{"object" => %{"attachment" => attachments}} = _message) do
43     Enum.each(attachments, fn
44       %{"url" => url} when is_list(url) ->
45         url
46         |> Enum.each(fn
47           %{"href" => href} ->
48             prefetch(href)
49
50           x ->
51             Logger.debug("Unhandled attachment URL object #{inspect(x)}")
52         end)
53
54       x ->
55         Logger.debug("Unhandled attachment #{inspect(x)}")
56     end)
57   end
58
59   @impl true
60   def filter(%{"type" => type, "object" => %{"attachment" => attachments} = _object} = message)
61       when type in ["Create", "Update"] and is_list(attachments) and length(attachments) > 0 do
62     preload(message)
63
64     {:ok, message}
65   end
66
67   @impl true
68   def filter(message), do: {:ok, message}
69
70   @impl true
71   def describe, do: {:ok, %{}}
72 end