Packages

Automatically clean-up temporary files when processes exit

Current section

Files

Jump to
process_file src process_file.erl
Raw

src/process_file.erl

-module(process_file).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/process_file.gleam").
-export([start/0, supervised/0, register/2]).
-export_type([process_file_manager/0, message/0, state/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-opaque process_file_manager() :: {process_file_manager,
mala:bag_table(gleam@erlang@process:pid_(), binary()),
gleam@erlang@process:subject(message())}.
-opaque message() :: {registration, binary(), gleam@erlang@process:subject(nil)} |
{monitored_process_down, gleam@erlang@process:pid_()}.
-type state() :: {state, mala:bag_table(gleam@erlang@process:pid_(), binary())}.
-file("src/process_file.gleam", 88).
-spec handle_registration(state(), binary(), gleam@erlang@process:subject(nil)) -> gleam@otp@actor:next(state(), message()).
handle_registration(State, Path, Reply) ->
Pid@1 = case gleam@erlang@process:subject_owner(Reply) of
{ok, Pid} -> Pid;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"registee must be alive"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"process_file"/utf8>>,
function => <<"handle_registration"/utf8>>,
line => 94,
value => _assert_fail,
start => 2919,
'end' => 2968,
pattern_start => 2930,
pattern_end => 2937})
end,
_ = gleam@erlang@process:monitor(Pid@1),
case mala_ffi:bag_insert(erlang:element(2, State), Pid@1, Path) of
{ok, _} -> nil;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"ETS table exists"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"process_file"/utf8>>,
function => <<"handle_registration"/utf8>>,
line => 100,
value => _assert_fail@1,
start => 3229,
'end' => 3283,
pattern_start => 3240,
pattern_end => 3245})
end,
gleam@erlang@process:send(Reply, nil),
gleam@otp@actor:continue(State).
-file("src/process_file.gleam", 109).
-spec handle_monitored_process_down(state(), gleam@erlang@process:pid_()) -> gleam@otp@actor:next(state(), message()).
handle_monitored_process_down(State, Pid) ->
Table = erlang:element(2, State),
Files@1 = case mala_ffi:bag_get(Table, Pid) of
{ok, Files} -> Files;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"ETS table exists"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"process_file"/utf8>>,
function => <<"handle_monitored_process_down"/utf8>>,
line => 115,
value => _assert_fail,
start => 3626,
'end' => 3669,
pattern_start => 3637,
pattern_end => 3646})
end,
case mala_ffi:bag_delete_key(Table, Pid) of
{ok, _} -> nil;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"ETS table exists"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"process_file"/utf8>>,
function => <<"handle_monitored_process_down"/utf8>>,
line => 116,
value => _assert_fail@1,
start => 3694,
'end' => 3740,
pattern_start => 3705,
pattern_end => 3710})
end,
case simplifile:delete_all(Files@1) of
{ok, _} -> nil;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"deletion must succeed"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"process_file"/utf8>>,
function => <<"handle_monitored_process_down"/utf8>>,
line => 120,
value => _assert_fail@2,
start => 3922,
'end' => 3969,
pattern_start => 3933,
pattern_end => 3938})
end,
gleam@otp@actor:continue(State).
-file("src/process_file.gleam", 78).
-spec handle_message(state(), message()) -> gleam@otp@actor:next(state(), message()).
handle_message(State, Message) ->
case Message of
{monitored_process_down, Pid} ->
handle_monitored_process_down(State, Pid);
{registration, Path, Reply} ->
handle_registration(State, Path, Reply)
end.
-file("src/process_file.gleam", 142).
-spec convert_down_message(gleam@erlang@process:down()) -> message().
convert_down_message(Down) ->
Pid@1 = case Down of
{process_down, _, Pid, _} -> Pid;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"process_file manager actor should never be monitoring a port"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"process_file"/utf8>>,
function => <<"convert_down_message"/utf8>>,
line => 143,
value => _assert_fail,
start => 4534,
'end' => 4581,
pattern_start => 4545,
pattern_end => 4574})
end,
{monitored_process_down, Pid@1}.
-file("src/process_file.gleam", 126).
-spec initialise(gleam@erlang@process:subject(message())) -> {ok,
gleam@otp@actor:initialised(state(), message(), process_file_manager())} |
{error, any()}.
initialise(Subject) ->
Table = mala:new(),
Handle = {process_file_manager, Table, Subject},
Selector = begin
_pipe = gleam_erlang_ffi:new_selector(),
_pipe@1 = gleam@erlang@process:select(_pipe, Subject),
gleam@erlang@process:select_monitors(
_pipe@1,
fun convert_down_message/1
)
end,
_pipe@2 = gleam@otp@actor:initialised({state, Table}),
_pipe@3 = gleam@otp@actor:selecting(_pipe@2, Selector),
_pipe@4 = gleam@otp@actor:returning(_pipe@3, Handle),
{ok, _pipe@4}.
-file("src/process_file.gleam", 24).
?DOC(
" Create a new process file manager. Typically you should use the\n"
" `supervised` function instead of this one, adding it to your application's\n"
" supervision tree.\n"
).
-spec start() -> {ok, gleam@otp@actor:started(process_file_manager())} |
{error, gleam@otp@actor:start_error()}.
start() ->
_pipe = gleam@otp@actor:new_with_initialiser(1000, fun initialise/1),
_pipe@1 = gleam@otp@actor:on_message(_pipe, fun handle_message/2),
gleam@otp@actor:start(_pipe@1).
-file("src/process_file.gleam", 32).
?DOC(" A supervision specification for a new process file manager.\n").
-spec supervised() -> gleam@otp@supervision:child_specification(process_file_manager()).
supervised() ->
gleam@otp@supervision:worker(fun start/0).
-file("src/process_file.gleam", 45).
?DOC(
" Register a file system path as being owned by the process that calls this\n"
" function, so when the process exits the process file manager will delete\n"
" any file or directory at the path. If there is no file at that location\n"
" then nothing happens.\n"
"\n"
" The first time a process calls this function they will be registered by the\n"
" manager process, but subsequent calls work directly with ETS and do not\n"
" produce any work for the manager.\n"
).
-spec register(process_file_manager(), binary()) -> {ok, nil} | {error, nil}.
register(Manager, New_path) ->
Owner = erlang:self(),
Table = erlang:element(2, Manager),
gleam@result:'try'(
mala_ffi:bag_has_key(Table, Owner),
fun(Already_registered) -> case Already_registered of
true ->
mala_ffi:bag_insert(Table, Owner, New_path);
false ->
{ok,
gleam@otp@actor:call(
erlang:element(3, Manager),
1000,
fun(_capture) ->
{registration, New_path, _capture}
end
)}
end end
).