akkoma/lib/pleroma/uploaders/uploader.ex

85 lines
2.7 KiB
Elixir
Raw Permalink Normal View History

# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Uploaders.Uploader do
import Pleroma.Web.Gettext
@mix_env Mix.env()
@moduledoc """
2018-11-23 09:40:45 -07:00
Defines the contract to put and get an uploaded file to any backend.
"""
2018-11-23 09:40:45 -07:00
@doc """
Instructs how to get the file from the backend.
2020-06-24 00:03:48 -06:00
Used by `Pleroma.Web.Plugs.UploadedMedia`.
2018-11-23 09:40:45 -07:00
"""
@type get_method :: {:static_dir, directory :: String.t()} | {:url, url :: String.t()}
@callback get_file(file :: String.t()) :: {:ok, get_method()}
@doc """
Put a file to the backend.
2018-11-23 09:40:45 -07:00
Returns:
2018-11-29 13:11:45 -07:00
* `:ok` which assumes `{:ok, upload.path}`
2018-11-23 09:40:45 -07:00
* `{:ok, spec}` where spec is:
* `{:file, filename :: String.t}` to handle reads with `get_file/1` (recommended)
2018-11-29 13:11:45 -07:00
This allows to correctly proxy or redirect requests to the backend, while allowing to migrate backends without breaking any URL.
* `{url, url :: String.t}` to bypass `get_file/2` and use the `url` directly in the activity.
2018-11-23 09:40:45 -07:00
* `{:error, String.t}` error information if the file failed to be saved to the backend.
2019-01-21 14:44:14 -07:00
* `:wait_callback` will wait for an http post request at `/api/pleroma/upload_callback/:upload_path` and call the uploader's `http_callback/3` method.
2018-11-23 09:40:45 -07:00
"""
2019-01-21 14:44:14 -07:00
@type file_spec :: {:file | :url, String.t()}
@callback put_file(upload :: struct()) ::
2019-01-21 14:44:14 -07:00
:ok | {:ok, file_spec()} | {:error, String.t()} | :wait_callback
@callback delete_file(file :: String.t()) :: :ok | {:error, String.t()}
2019-01-21 14:44:14 -07:00
@callback http_callback(Plug.Conn.t(), Map.t()) ::
{:ok, Plug.Conn.t()}
| {:ok, Plug.Conn.t(), file_spec()}
| {:error, Plug.Conn.t(), String.t()}
@optional_callbacks http_callback: 2
@spec put_file(module(), upload :: struct()) :: {:ok, file_spec()} | {:error, String.t()}
2018-11-29 13:11:45 -07:00
def put_file(uploader, upload) do
case uploader.put_file(upload) do
:ok -> {:ok, {:file, upload.path}}
2019-01-21 14:44:14 -07:00
:wait_callback -> handle_callback(uploader, upload)
{:ok, _} = ok -> ok
{:error, _} = error -> error
end
end
defp handle_callback(uploader, upload) do
:global.register_name({__MODULE__, upload.path}, self())
receive do
{__MODULE__, pid, conn, params} ->
case uploader.http_callback(conn, params) do
{:ok, conn, ok} ->
send(pid, {__MODULE__, conn})
{:ok, ok}
{:error, conn, error} ->
send(pid, {__MODULE__, conn})
{:error, error}
end
after
2019-07-18 06:30:18 -06:00
callback_timeout() -> {:error, dgettext("errors", "Uploader callback timeout")}
end
end
defp callback_timeout do
case @mix_env do
2019-07-18 06:30:18 -06:00
:test -> 1_000
_ -> 30_000
2018-11-29 13:11:45 -07:00
end
end
end