Skip to content

Commit a9e7766

Browse files
author
Tim Smart
committed
Add stream_response option to hackney adapter
1 parent c1e0f2d commit a9e7766

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

lib/tesla/adapter/hackney.ex

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ if Code.ensure_loaded?(:hackney) do
4242
end
4343

4444
defp format_body(data) when is_list(data), do: IO.iodata_to_binary(data)
45-
defp format_body(data) when is_binary(data) or is_reference(data), do: data
45+
46+
defp format_body(data)
47+
when is_binary(data) or is_reference(data) or is_function(data),
48+
do: data
4649

4750
defp request(env, opts) do
4851
request(
@@ -68,14 +71,22 @@ if Code.ensure_loaded?(:hackney) do
6871
end
6972

7073
defp request(method, url, headers, body, opts) do
71-
handle(:hackney.request(method, url, headers, body || '', opts))
74+
response = :hackney.request(method, url, headers, body || '', opts)
75+
76+
case Keyword.get(opts, :stream_response, false) do
77+
true -> handle(response, :stream)
78+
false -> handle(response)
79+
end
7280
end
7381

7482
defp request_stream(method, url, headers, body, opts) do
7583
with {:ok, ref} <- :hackney.request(method, url, headers, :stream, opts) do
7684
case send_stream(ref, body) do
77-
:ok -> handle(:hackney.start_response(ref))
78-
error -> handle(error)
85+
:ok ->
86+
handle(:hackney.start_response(ref))
87+
88+
error ->
89+
handle(error)
7990
end
8091
else
8192
e -> handle(e)
@@ -106,6 +117,31 @@ if Code.ensure_loaded?(:hackney) do
106117

107118
defp handle({:ok, status, headers, body}), do: {:ok, status, headers, body}
108119

120+
defp handle({:ok, status, headers, ref}, :stream) when is_reference(ref) do
121+
state = :hackney_manager.get_state(ref)
122+
123+
body =
124+
Stream.resource(
125+
fn -> state end,
126+
fn
127+
{:done, state} ->
128+
{:halt, state}
129+
130+
{:ok, data, state} ->
131+
{[data], state}
132+
133+
{:error, reason} ->
134+
raise inspect(reason)
135+
136+
state ->
137+
{[], :hackney_response.stream_body(state)}
138+
end,
139+
&:hackney_response.close/1
140+
)
141+
142+
{:ok, status, headers, body}
143+
end
144+
109145
defp handle_async_response({ref, %{headers: headers, status: status}})
110146
when not (is_nil(headers) or is_nil(status)) do
111147
{:ok, status, headers, ref}

test/tesla/adapter/hackney_test.exs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,16 @@ defmodule Tesla.Adapter.HackneyTest do
6262

6363
assert {:error, :fake_error} = call(request)
6464
end
65+
66+
test "get with `stream_response: true` option" do
67+
request = %Env{
68+
method: :get,
69+
url: "#{@http}/ip"
70+
}
71+
72+
assert {:ok, %Env{} = response} = call(request, stream_response: true)
73+
74+
assert response.status == 200
75+
assert(is_function(response.body))
76+
end
6577
end

0 commit comments

Comments
 (0)