Skip to content

Commit c896989

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

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

lib/tesla/adapter/hackney.ex

Lines changed: 45 additions & 2 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,7 +71,12 @@ 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_stream(response)
78+
false -> handle(response)
79+
end
7280
end
7381

7482
defp request_stream(method, url, headers, body, opts) do
@@ -106,6 +114,41 @@ if Code.ensure_loaded?(:hackney) do
106114

107115
defp handle({:ok, status, headers, body}), do: {:ok, status, headers, body}
108116

117+
defp handle_stream({:ok, status, headers, ref}) when is_reference(ref) do
118+
state = :hackney_manager.get_state(ref)
119+
120+
body =
121+
Stream.resource(
122+
fn -> state end,
123+
fn
124+
{:done, state} ->
125+
{:halt, state}
126+
127+
{:ok, data, state} ->
128+
{[data], state}
129+
130+
{:error, reason} ->
131+
raise inspect(reason)
132+
133+
state ->
134+
{[], :hackney_response.stream_body(state)}
135+
end,
136+
&:hackney_response.close/1
137+
)
138+
139+
{:ok, status, headers, body}
140+
end
141+
142+
defp handle_stream(response) do
143+
case handle(response) do
144+
{:ok, _status, _headers, ref} = response when is_reference(ref) ->
145+
handle_stream(response)
146+
147+
response ->
148+
response
149+
end
150+
end
151+
109152
defp handle_async_response({ref, %{headers: headers, status: status}})
110153
when not (is_nil(headers) or is_nil(status)) do
111154
{: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)