2024-02-11 14:11:52 -07:00
|
|
|
# Pleroma: A lightweight social networking server
|
|
|
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
|
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
|
|
|
defmodule Pleroma.Web.RichMedia.Backfill do
|
2024-06-11 11:06:51 -06:00
|
|
|
use Pleroma.Workers.WorkerHelper,
|
|
|
|
queue: "rich_media_backfill",
|
|
|
|
unique: [period: 300, states: Oban.Job.states(), keys: [:op, :url_hash]]
|
|
|
|
|
2024-02-11 14:11:52 -07:00
|
|
|
alias Pleroma.Web.RichMedia.Card
|
|
|
|
alias Pleroma.Web.RichMedia.Parser
|
|
|
|
alias Pleroma.Web.RichMedia.Parser.TTL
|
|
|
|
alias Pleroma.Workers.RichMediaExpirationWorker
|
|
|
|
|
|
|
|
require Logger
|
|
|
|
|
|
|
|
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
|
|
|
|
|
|
|
|
def start(%{url: url} = args) when is_binary(url) do
|
|
|
|
url_hash = Card.url_to_hash(url)
|
|
|
|
|
|
|
|
args =
|
|
|
|
args
|
|
|
|
|> Map.put(:url_hash, url_hash)
|
|
|
|
|
2024-06-11 11:06:51 -06:00
|
|
|
__MODULE__.enqueue("rich_media_backfill", args)
|
|
|
|
end
|
|
|
|
|
|
|
|
def perform(%Oban.Job{args: %{"op" => "rich_media_backfill", "url" => url} = args})
|
|
|
|
when is_binary(url) do
|
|
|
|
run(args)
|
2024-02-11 14:11:52 -07:00
|
|
|
end
|
|
|
|
|
2024-06-11 11:06:51 -06:00
|
|
|
def run(%{"url" => url, "url_hash" => url_hash} = args) do
|
2024-02-11 14:11:52 -07:00
|
|
|
case Parser.parse(url) do
|
|
|
|
{:ok, fields} ->
|
|
|
|
{:ok, card} = Card.create(url, fields)
|
|
|
|
|
|
|
|
maybe_schedule_expiration(url, fields)
|
|
|
|
|
2024-06-11 11:06:51 -06:00
|
|
|
if Map.has_key?(args, "activity_id") do
|
2024-02-11 14:11:52 -07:00
|
|
|
stream_update(args)
|
|
|
|
end
|
|
|
|
|
|
|
|
warm_cache(url_hash, card)
|
2024-06-11 11:06:51 -06:00
|
|
|
:ok
|
2024-02-11 14:11:52 -07:00
|
|
|
|
|
|
|
{:error, {:invalid_metadata, fields}} ->
|
|
|
|
Logger.debug("Rich media incomplete or invalid metadata for #{url}: #{inspect(fields)}")
|
2024-06-11 11:06:51 -06:00
|
|
|
negative_cache(url_hash, :timer.minutes(30))
|
2024-02-11 14:11:52 -07:00
|
|
|
|
|
|
|
{:error, :body_too_large} ->
|
|
|
|
Logger.error("Rich media error for #{url}: :body_too_large")
|
2024-06-11 11:06:51 -06:00
|
|
|
negative_cache(url_hash, :timer.minutes(30))
|
2024-02-11 14:11:52 -07:00
|
|
|
|
|
|
|
{:error, {:content_type, type}} ->
|
|
|
|
Logger.debug("Rich media error for #{url}: :content_type is #{type}")
|
2024-06-11 11:06:51 -06:00
|
|
|
negative_cache(url_hash, :timer.minutes(30))
|
2024-02-11 14:11:52 -07:00
|
|
|
|
|
|
|
e ->
|
|
|
|
Logger.debug("Rich media error for #{url}: #{inspect(e)}")
|
2024-06-11 11:06:51 -06:00
|
|
|
{:error, e}
|
2024-02-11 14:11:52 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-06-11 11:06:51 -06:00
|
|
|
def run(e) do
|
|
|
|
Logger.error("Rich media failure - invalid args: #{inspect(e)}")
|
|
|
|
{:discard, :invalid}
|
2024-02-11 14:11:52 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
defp maybe_schedule_expiration(url, fields) do
|
2024-02-18 20:24:27 -07:00
|
|
|
case TTL.process(fields, url) do
|
|
|
|
{:ok, ttl} when is_number(ttl) ->
|
2024-02-11 14:11:52 -07:00
|
|
|
timestamp = DateTime.from_unix!(ttl)
|
|
|
|
|
|
|
|
RichMediaExpirationWorker.new(%{"url" => url}, scheduled_at: timestamp)
|
|
|
|
|> Oban.insert()
|
|
|
|
|
|
|
|
_ ->
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-06-11 11:06:51 -06:00
|
|
|
defp stream_update(%{"activity_id" => activity_id}) do
|
|
|
|
Logger.info("Rich media backfill: streaming update for activity #{activity_id}")
|
|
|
|
|
2024-02-11 14:11:52 -07:00
|
|
|
Pleroma.Activity.get_by_id(activity_id)
|
|
|
|
|> Pleroma.Activity.normalize()
|
|
|
|
|> Pleroma.Web.ActivityPub.ActivityPub.stream_out()
|
|
|
|
end
|
|
|
|
|
|
|
|
defp warm_cache(key, val), do: @cachex.put(:rich_media_cache, key, val)
|
2024-05-07 20:10:49 -06:00
|
|
|
|
2024-06-11 11:06:51 -06:00
|
|
|
def negative_cache(key, ttl \\ :timer.minutes(30)) do
|
|
|
|
@cachex.put(:rich_media_cache, key, nil, ttl: ttl)
|
|
|
|
{:discard, :error}
|
2024-05-07 20:10:49 -06:00
|
|
|
end
|
|
|
|
end
|