Current section
Files
Jump to
Current section
Files
src/olive@watcher.erl
-module(olive@watcher).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([start/1]).
-export_type([message/0, state/0, internal_msg/0, watch_events/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.
?MODULEDOC(
" The `watcher` module watches a list of dir and triggers a `FilesChanged` message\n"
" to be handled by calling code.\n"
).
-type message() :: files_changed.
-type state() :: {state,
gleam@option:option(gleam@erlang@process:timer()),
gleam@erlang@process:subject(message())}.
-opaque internal_msg() :: trigger_files_changed | ignore_changes.
-type watch_events() :: event_needing_rebuild | other_events.
-file("src/olive/watcher.gleam", 55).
-spec maybe_cancel_timer(gleam@option:option(gleam@erlang@process:timer())) -> nil.
maybe_cancel_timer(Timer) ->
case Timer of
{some, Timer@1} ->
gleam@erlang@process:cancel_timer(Timer@1),
nil;
none ->
nil
end.
-file("src/olive/watcher.gleam", 37).
-spec do_loop(internal_msg(), state()) -> gleam@otp@actor:next(any(), state()).
do_loop(Msg, State) ->
case Msg of
ignore_changes ->
gleam@otp@actor:continue(State);
trigger_files_changed ->
maybe_cancel_timer(erlang:element(2, State)),
Timer = gleam@erlang@process:send_after(
erlang:element(3, State),
50,
files_changed
),
gleam@otp@actor:continue(
begin
_record = State,
{state, {some, Timer}, erlang:element(3, _record)}
end
)
end.
-file("src/olive/watcher.gleam", 106).
?DOC(" Converts an atom to an event\n").
-spec atom_to_watch_events() -> gleam@dynamic@decode:decoder(watch_events()).
atom_to_watch_events() ->
Modified = erlang:binary_to_atom(<<"modified"/utf8>>),
Renamed = erlang:binary_to_atom(<<"renamed"/utf8>>),
gleam@dynamic@decode:new_primitive_decoder(
<<"Atom"/utf8>>,
fun(Data) -> case gleam_erlang_ffi:atom_from_dynamic(Data) of
{ok, Ev} when Ev =:= Modified ->
{ok, event_needing_rebuild};
{ok, Ev@1} when Ev@1 =:= Renamed ->
{ok, event_needing_rebuild};
_ ->
{ok, other_events}
end end
).
-file("src/olive/watcher.gleam", 82).
-spec watch_decoder(gleam@dynamic:dynamic_()) -> internal_msg().
watch_decoder(Msg) ->
Decoder = begin
gleam@dynamic@decode:subfield(
[2, 1],
gleam@dynamic@decode:list(atom_to_watch_events()),
fun(Events) -> gleam@dynamic@decode:success(Events) end
)
end,
case gleam@dynamic@decode:run(Msg, Decoder) of
{ok, Events@1} ->
case gleam@list:contains(Events@1, event_needing_rebuild) of
true ->
trigger_files_changed;
false ->
ignore_changes
end;
{error, _} ->
olive@logging:error(<<"Error occured while watching files"/utf8>>),
ignore_changes
end.
-file("src/olive/watcher.gleam", 65).
-spec watch_folder(binary()) -> {ok,
gleam@erlang@process:selector(internal_msg())} |
{error, nil}.
watch_folder(Dir) ->
Atom = erlang:binary_to_atom(<<"fs_watcher_"/utf8, Dir/binary>>),
case fs:start_link(Atom, Dir) of
{ok, _} ->
fs:subscribe(Atom),
Selectors = begin
_pipe = gleam_erlang_ffi:new_selector(),
gleam@erlang@process:selecting_anything(
_pipe,
fun watch_decoder/1
)
end,
{ok, Selectors};
{error, _} ->
olive@logging:error(
<<"Error occured while watching folder: "/utf8, Dir/binary>>
),
{error, nil}
end.
-file("src/olive/watcher.gleam", 26).
-spec start(gleam@erlang@process:subject(message())) -> {ok,
gleam@erlang@process:subject(internal_msg())} |
{error, gleam@otp@actor:start_error()}.
start(Watch_subject) ->
gleam@otp@actor:start_spec(
{spec, fun() -> case watch_folder(<<"src"/utf8>>) of
{ok, Selectors} ->
{ready, {state, none, Watch_subject}, Selectors};
{error, _} ->
{failed,
<<"Could not start watch actor with folder src"/utf8>>}
end end, 5000, fun do_loop/2}
).