From 5a9cdd3cc89507d4d74f8bded56ce5e037b3b56e Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Fri, 23 Feb 2024 07:08:18 +0100 Subject: wip --- learn-you-some-erlang/reminder/src/event.erl | 61 ++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 learn-you-some-erlang/reminder/src/event.erl (limited to 'learn-you-some-erlang/reminder/src/event.erl') diff --git a/learn-you-some-erlang/reminder/src/event.erl b/learn-you-some-erlang/reminder/src/event.erl new file mode 100644 index 0000000..58b5b57 --- /dev/null +++ b/learn-you-some-erlang/reminder/src/event.erl @@ -0,0 +1,61 @@ +-module(event). +-export([start/2, start_link/2, cancel/1]). +-export([init/3, loop/1]). +-record(state, {server, + name="", + to_go=0}). + +%%% Public interface +start(EventName, DateTime) -> + spawn(?MODULE, init, [self(), EventName, DateTime]). + +start_link(EventName, DateTime) -> + spawn_link(?MODULE, init, [self(), EventName, DateTime]). + +cancel(Pid) -> + %% Monitor in case the process is already dead + Ref = erlang:monitor(process, Pid), + Pid ! {self(), Ref, cancel}, + receive + {Ref, ok} -> + erlang:demonitor(Ref, [flush]), + ok; + {'DOWN', Ref, process, Pid, _Reason} -> + ok + end. + +%%% Event's innards +init(Server, EventName, DateTime) -> + loop(#state{server=Server, + name=EventName, + to_go=time_to_go(DateTime)}). + +%% Loop uses a list for times in order to go around the ~49 days limit +%% on timeouts. +loop(S = #state{server=Server, to_go=[T|Next]}) -> + receive + {Server, Ref, cancel} -> + Server ! {Ref, ok} + after T*1000 -> + if Next =:= [] -> + Server ! {done, S#state.name}; + Next =/= [] -> + loop(S#state{to_go=Next}) + end + end. + +%%% private functions +time_to_go(TimeOut={{_,_,_}, {_,_,_}}) -> + Now = calendar:local_time(), + ToGo = calendar:datetime_to_gregorian_seconds(TimeOut) - + calendar:datetime_to_gregorian_seconds(Now), + Secs = if ToGo > 0 -> ToGo; + ToGo =< 0 -> 0 + end, + normalize(Secs). + +%% Because Erlang is limited to about 49 days (49*24*60*60*1000) in +%% milliseconds, the following function is used +normalize(N) -> + Limit = 49*24*60*60, + [N rem Limit | lists:duplicate(N div Limit, Limit)]. -- cgit v1.2.3