Current section
Files
Jump to
Current section
Files
src/dream_http_client@stream.erl
-module(dream_http_client@stream).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/dream_http_client/stream.gleam").
-export([stream_request/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Streaming HTTP request functionality\n"
"\n"
" This module provides streaming HTTP request functionality that returns\n"
" a yielder of response chunks as they arrive. Use this for:\n"
"\n"
" - Large file downloads\n"
" - Streaming AI responses\n"
" - Real-time data feeds\n"
" - Any case where you want to process data incrementally\n"
"\n"
" ## Quick Start\n"
"\n"
" ```gleam\n"
" import dream_http_client/client\n"
" import dream_http_client/stream\n"
" import gleam/yielder\n"
"\n"
" client.new\n"
" |> client.host(\"cdn.example.com\")\n"
" |> client.path(\"/large-file.zip\")\n"
" |> stream.stream_request()\n"
" |> yielder.each(fn(chunk) {\n"
" // Process each chunk as it arrives\n"
" save_chunk(chunk)\n"
" })\n"
" ```\n"
"\n"
" ## Processing Streams\n"
"\n"
" The yielder can be consumed with `yielder.each()`, `yielder.to_list()`, or\n"
" other yielder functions. Each chunk is a `BytesTree` that you can convert\n"
" to a string or process as binary data.\n"
).
-file("src/dream_http_client/stream.gleam", 46).
?DOC(
" Convert a ClientRequest to a gleam/http/request.Request\n"
"\n"
" Internal helper function that converts the builder-style ClientRequest\n"
" to the standard gleam/http Request type.\n"
).
-spec to_http_request(dream_http_client@client:client_request()) -> gleam@http@request:request(binary()).
to_http_request(Client_request) ->
{request,
erlang:element(2, Client_request),
erlang:element(8, Client_request),
erlang:element(9, Client_request),
erlang:element(3, Client_request),
erlang:element(4, Client_request),
erlang:element(5, Client_request),
erlang:element(6, Client_request),
erlang:element(7, Client_request)}.
-file("src/dream_http_client/stream.gleam", 102).
?DOC(
" Create a yielder that streams HTTP response chunks\n"
"\n"
" Sends an HTTP request and returns a yielder that produces chunks of the\n"
" response body as they arrive from the server. This allows you to process\n"
" large responses incrementally without loading the entire response into memory.\n"
"\n"
" The yielder produces `Next(chunk, new_state)` for each chunk until the stream\n"
" completes, then produces `Done`.\n"
"\n"
" ## Parameters\n"
"\n"
" - `req`: The configured HTTP request\n"
"\n"
" ## Returns\n"
"\n"
" A `Yielder` that produces `BytesTree` chunks. Use `yielder.each()` to process\n"
" chunks, or `yielder.to_list()` to collect all chunks.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream_http_client/client\n"
" import dream_http_client/stream\n"
" import gleam/yielder\n"
" import gleam/bytes_tree\n"
"\n"
" // Stream and process chunks\n"
" client.new\n"
" |> client.host(\"api.example.com\")\n"
" |> client.path(\"/stream\")\n"
" |> stream.stream_request()\n"
" |> yielder.each(fn(chunk) {\n"
" let body = bytes_tree.to_string(chunk)\n"
" process_chunk(body)\n"
" })\n"
"\n"
" // Or collect all chunks\n"
" let chunks = client.new\n"
" |> client.host(\"cdn.example.com\")\n"
" |> client.path(\"/file.zip\")\n"
" |> stream.stream_request()\n"
" |> yielder.to_list()\n"
" ```\n"
).
-spec stream_request(dream_http_client@client:client_request()) -> gleam@yielder:yielder(gleam@bytes_tree:bytes_tree()).
stream_request(Req) ->
Http_req = to_http_request(Req),
gleam@yielder:unfold(none, fun(State) -> case State of
none ->
Request_result = dream_http_client@internal:start_httpc_stream(
Http_req
),
Owner = dream_http_client@internal:extract_owner_pid(
Request_result
),
case dream_http_client@internal:receive_next(Owner) of
{ok, Bin} ->
{next,
gleam@bytes_tree:from_bit_array(Bin),
{some, Owner}};
{error, _} ->
done
end;
{some, Owner@1} ->
case dream_http_client@internal:receive_next(Owner@1) of
{ok, Bin@1} ->
{next,
gleam@bytes_tree:from_bit_array(Bin@1),
{some, Owner@1}};
{error, _} ->
done
end
end end).