Skip to content

Instantly share code, notes, and snippets.

@bfolkens
Last active April 5, 2022 21:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bfolkens/c5b6f4d8470e2320d855c654510cd523 to your computer and use it in GitHub Desktop.
Save bfolkens/c5b6f4d8470e2320d855c654510cd523 to your computer and use it in GitHub Desktop.
Stream wrapper around HTTPoison.get!(...)
defmodule HTTPDownloader do
@moduledoc """
Stream wrapper around HTTPoison.get!(...)
Source: https://elixirforum.com/t/how-to-stream-file-from-aws-to-client-through-elixir-backend/20693/15?u=bfolkens
HTTPDownloader.stream!(url_to_my_s3_file)
|> Enum.each(fn chunk -> send_chunk_to_client(client_conn, chunk) end)
"""
def stream!(url) do
Stream.resource(
fn -> start_request(url) end,
fn ref ->
case receive_response(ref) do
#returning the chunk to the stream
{:ok, {:chunk, chunk}} ->
HTTPoison.stream_next(ref)
{[chunk], ref}
{:ok, msg} ->
IO.inspect(msg)
HTTPoison.stream_next(ref)
{[], ref}
{:error, error} ->
IO.puts("ERROR")
raise("error #{inspect error}")
:done -> {:halt, ref}
end
end,
fn ref -> :hackney.stop_async(ref) end
)
end
defp start_request(url) do
{:ok, ref} = HTTPoison.get(url, %{}, stream_to: self(), async: :once)
ref
end
defp receive_response(ref) do
id = ref.id
receive do
%HTTPoison.AsyncStatus{code: code, id: ^id} when 200 <= code and code < 300 ->
{:ok, {:status_code, code}}
%HTTPoison.AsyncStatus{code: code, id: ^id} ->
{:error, {:status_code, code}}
%HTTPoison.AsyncHeaders{headers: headers, id: ^id}->
{:ok, {:headers, headers}}
%HTTPoison.AsyncChunk{chunk: chunk, id: ^id}->
{:ok, {:chunk, chunk}}
%HTTPoison.AsyncEnd{id: ^id}-> :done
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment