logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

tesla.ex (2211B)


  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. defmodule Pleroma.ReverseProxy.Client.Tesla do
  5. @behaviour Pleroma.ReverseProxy.Client
  6. alias Pleroma.Gun.ConnectionPool
  7. @type headers() :: [{String.t(), String.t()}]
  8. @type status() :: pos_integer()
  9. @spec request(atom(), String.t(), headers(), String.t(), keyword()) ::
  10. {:ok, status(), headers}
  11. | {:ok, status(), headers, map()}
  12. | {:error, atom() | String.t()}
  13. | no_return()
  14. @impl true
  15. def request(method, url, headers, body, opts \\ []) do
  16. check_adapter()
  17. opts = Keyword.put(opts, :body_as, :chunks)
  18. with {:ok, response} <-
  19. Pleroma.HTTP.request(
  20. method,
  21. url,
  22. body,
  23. headers,
  24. opts
  25. ) do
  26. if is_map(response.body) and method != :head do
  27. {:ok, response.status, response.headers, response.body}
  28. else
  29. conn_pid = response.opts[:adapter][:conn]
  30. ConnectionPool.release_conn(conn_pid)
  31. {:ok, response.status, response.headers}
  32. end
  33. else
  34. {:error, error} -> {:error, error}
  35. end
  36. end
  37. @impl true
  38. @spec stream_body(map()) ::
  39. {:ok, binary(), map()} | {:error, atom() | String.t()} | :done | no_return()
  40. def stream_body(%{pid: pid, fin: true}) do
  41. ConnectionPool.release_conn(pid)
  42. :done
  43. end
  44. def stream_body(client) do
  45. case read_chunk!(client) do
  46. {:fin, body} ->
  47. {:ok, body, Map.put(client, :fin, true)}
  48. {:nofin, part} ->
  49. {:ok, part, client}
  50. {:error, error} ->
  51. {:error, error}
  52. end
  53. end
  54. defp read_chunk!(%{pid: pid, stream: stream, opts: opts}) do
  55. adapter = check_adapter()
  56. adapter.read_chunk(pid, stream, opts)
  57. end
  58. @impl true
  59. @spec close(map) :: :ok | no_return()
  60. def close(%{pid: pid}) do
  61. ConnectionPool.release_conn(pid)
  62. end
  63. defp check_adapter do
  64. adapter = Application.get_env(:tesla, :adapter)
  65. unless adapter == Tesla.Adapter.Gun do
  66. raise "#{adapter} doesn't support reading body in chunks"
  67. end
  68. adapter
  69. end
  70. end