Current section

Files

Jump to
dream_http_client src dream_http_client@storage.erl
Raw

src/dream_http_client@storage.erl

-module(dream_http_client@storage).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/dream_http_client/storage.gleam").
-export([load_recordings/1, save_recordings/2, save_recording_immediately/2]).
-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(
" File I/O for recordings\n"
"\n"
" Handles loading and saving recording files to/from the filesystem.\n"
).
-file("src/dream_http_client/storage.gleam", 162).
-spec build_file_path(binary()) -> binary().
build_file_path(Directory) ->
Normalized_directory = case gleam_stdlib:string_ends_with(
Directory,
<<"/"/utf8>>
) of
true ->
Directory;
false ->
<<Directory/binary, "/"/utf8>>
end,
<<Normalized_directory/binary, "recordings.json"/utf8>>.
-file("src/dream_http_client/storage.gleam", 43).
?DOC(
" Load recordings from a JSON file\n"
"\n"
" Reads and decodes recordings from `{directory}/recordings.json`. This function\n"
" is used internally by the recorder when starting in Playback mode, but can also\n"
" be called directly to inspect or manipulate recordings.\n"
"\n"
" ## Parameters\n"
"\n"
" - `directory`: The directory containing the `recordings.json` file\n"
"\n"
" ## Returns\n"
"\n"
" - `Ok(List(Recording))`: Successfully loaded recordings (empty list if file doesn't exist)\n"
" - `Error(String)`: Error message if file exists but cannot be read or decoded\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" // Load recordings for inspection\n"
" case storage.load_recordings(\"mocks/api\") {\n"
" Ok(recordings) -> {\n"
" io.println(\"Loaded \" <> int.to_string(list.length(recordings)) <> \" recordings\")\n"
" }\n"
" Error(reason) -> io.println_error(\"Failed to load: \" <> reason)\n"
" }\n"
" ```\n"
"\n"
" ## Notes\n"
"\n"
" - Returns an empty list (not an error) if the file doesn't exist\n"
" - This is the expected behavior for Playback mode when no recordings have been created yet\n"
" - File format must match the versioned JSON structure (see `recording.RecordingFile`)\n"
).
-spec load_recordings(binary()) -> {ok,
list(dream_http_client@recording:recording())} |
{error, binary()}.
load_recordings(Directory) ->
File_path = build_file_path(Directory),
case simplifile:read(File_path) of
{ok, Content} ->
case dream_http_client@recording:decode_recording_file(Content) of
{ok, File} ->
{ok, erlang:element(3, File)};
{error, Reason} ->
{error,
<<"Failed to decode recording file: "/utf8,
Reason/binary>>}
end;
{error, enoent} ->
{ok, []};
{error, Read_error} ->
{error,
<<"Failed to read recording file: "/utf8,
(gleam@string:inspect(Read_error))/binary>>}
end.
-file("src/dream_http_client/storage.gleam", 116).
?DOC(
" Save recordings to a JSON file\n"
"\n"
" Writes all recordings to `{directory}/recordings.json` in the versioned JSON format.\n"
" Creates the directory if it doesn't exist. This function overwrites any existing\n"
" recordings file.\n"
"\n"
" ## Parameters\n"
"\n"
" - `directory`: The directory where `recordings.json` will be written\n"
" - `recordings`: List of recordings to save\n"
"\n"
" ## Returns\n"
"\n"
" - `Ok(Nil)`: Successfully saved all recordings\n"
" - `Error(String)`: Error message if directory creation or file write fails\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" let recordings = [\n"
" create_test_recording(),\n"
" create_another_recording(),\n"
" ]\n"
"\n"
" case storage.save_recordings(\"mocks/api\", recordings) {\n"
" Ok(_) -> io.println(\"Saved recordings successfully\")\n"
" Error(reason) -> io.println_error(\"Failed to save: \" <> reason)\n"
" }\n"
" ```\n"
"\n"
" ## Notes\n"
"\n"
" - Directory is created automatically if it doesn't exist\n"
" - Existing `recordings.json` file is overwritten (use `load_recordings` first to merge)\n"
" - File format includes version field for future compatibility\n"
).
-spec save_recordings(binary(), list(dream_http_client@recording:recording())) -> {ok,
nil} |
{error, binary()}.
save_recordings(Directory, Recordings) ->
File_path = build_file_path(Directory),
_pipe = case simplifile:create_directory_all(Directory) of
{ok, nil} ->
{ok, nil};
{error, eexist} ->
{ok, nil};
{error, Directory_error} ->
{error,
<<<<<<"Failed to create directory "/utf8, Directory/binary>>/binary,
": "/utf8>>/binary,
(gleam@string:inspect(Directory_error))/binary>>}
end,
gleam@result:'try'(
_pipe,
fun(_) ->
Recording_file = {recording_file, <<"1.0"/utf8>>, Recordings},
Json_value = dream_http_client@recording:encode_recording_file(
Recording_file
),
Json_string = gleam@json:to_string(Json_value),
case simplifile:write(File_path, Json_string) of
{ok, nil} ->
{ok, nil};
{error, Write_error} ->
{error,
<<<<<<"Failed to write recording file "/utf8,
File_path/binary>>/binary,
": "/utf8>>/binary,
(gleam@string:inspect(Write_error))/binary>>}
end
end
).
-file("src/dream_http_client/storage.gleam", 73).
?DOC(
" Save a single recording immediately by appending to existing recordings\n"
"\n"
" Loads existing recordings, prepends the new recording, and saves all.\n"
" This uses a read-modify-write approach that prioritizes reliability over performance.\n"
"\n"
" **Performance Tradeoff:** This function performs O(n) file I/O operations where n is\n"
" the number of existing recordings. For typical use cases (recording once, playback often),\n"
" this is acceptable. If you need high-performance recording with deferred saves or delta\n"
" files, please create an issue at https://github.com/TrustBound/dream/issues.\n"
).
-spec save_recording_immediately(
binary(),
dream_http_client@recording:recording()
) -> {ok, nil} | {error, binary()}.
save_recording_immediately(Directory, Recording) ->
gleam@result:'try'(
load_recordings(Directory),
fun(Existing) -> save_recordings(Directory, [Recording | Existing]) end
).