tesla.ex 1.97 KB
Newer Older
1 2 3 4
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-onl

5 6 7
defmodule Pleroma.ReverseProxy.Client.Tesla do
  @behaviour Pleroma.ReverseProxy.Client

8
  @adapters [Tesla.Adapter.Gun, Tesla.Adapter.Mint]
9 10

  def request(method, url, headers, body, opts \\ []) do
11
    opts = Keyword.put(opts, :body_as, :chunks)
12 13

    with {:ok, response} <-
14 15 16 17 18
           Pleroma.HTTP.request(
             method,
             url,
             body,
             headers,
19
             Keyword.put(opts, :adapter, opts)
20 21 22 23
           ) do
      if is_map(response.body),
        do: {:ok, response.status, response.headers, response.body},
        else: {:ok, response.status, response.headers}
24 25 26 27 28 29 30
    else
      {:error, error} -> {:error, error}
    end
  end

  def stream_body(%{fin: true}), do: :done

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
  def stream_body(%{body: body} = client) do
    case body do
      {:fin, response} ->
        {:ok, response, Map.put(client, :fin, true)}

      {:nofin, response} ->
        client = Map.delete(client, :body)

        case response do
          nil ->
            stream_body(client)

          _binary ->
            {:ok, response, client}
        end
    end
  end

49 50 51 52
  def stream_body(client) do
    case read_chunk!(client) do
      {:fin, body} -> {:ok, body, Map.put(client, :fin, true)}
      {:nofin, part} -> {:ok, part, client}
53
      {:error, error} -> {:error, error}
54 55 56
    end
  end

Alexander Strizhakov's avatar
fix  
Alexander Strizhakov committed
57
  defp read_chunk!(%{pid: pid, stream: stream, opts: opts}) do
58
    adapter = check_adapter()
Alexander Strizhakov's avatar
fix  
Alexander Strizhakov committed
59
    adapter.read_chunk(pid, stream, opts)
60 61
  end

62 63 64 65 66
  defp read_chunk!(%{conn: conn, opts: opts}) do
    adapter = check_adapter()
    adapter.read_chunk(conn, opts)
  end

67
  def close(pid) do
68 69 70 71 72
    adapter = check_adapter()
    adapter.close(pid)
  end

  defp check_adapter do
73 74 75
    adapter = Application.get_env(:tesla, :adapter)

    unless adapter in @adapters do
76
      raise "#{adapter} doesn't support reading body in chunks"
77 78
    end

79
    adapter
80 81
  end
end