Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- %% Event server
- -module(evserv).
- -compile(export_all).
- -record(state, {events, %% list of #event{} records
- clients}). %% list of Pids
- -record(event, {name="",
- description="",
- pid,
- clientpid,
- timeout={{1970,1,1},{0,0,0}}}).
- %%% User Interface
- start() ->
- register(?MODULE, Pid=spawn(?MODULE, init, [])),
- Pid.
- start_link() ->
- register(?MODULE, Pid=spawn_link(?MODULE, init, [])),
- Pid.
- terminate() ->
- ?MODULE ! shutdown.
- init() ->
- %% Loading events from a static file could be done here.
- %% You would need to pass an argument to init (maybe change the functions
- %% start/0 and start_link/0 to start/1 and start_link/1) telling where the
- %% resource to find the events is. Then load it from here.
- %% Another option is to just pass the event straight to the server
- %% through this function.
- loop(#state{events=orddict:new(),
- clients=orddict:new()}).
- subscribe(Pid) ->
- Ref = erlang:monitor(process, whereis(?MODULE)),
- ?MODULE ! {self(), Ref, {subscribe, Pid}},
- receive
- {Ref, ok} ->
- {ok, Ref};
- {'DOWN', Ref, process, _Pid, Reason} ->
- {error, Reason}
- after 5000 ->
- {error, timeout}
- end.
- add_event(Name, Description, TimeOut, Pid) ->
- Ref = make_ref(),
- ?MODULE ! {self(), Ref, {add, Name, Description, TimeOut, Pid}},
- receive
- {Ref, Msg} -> Msg
- after 5000 ->
- {error, timeout}
- end.
- add_event2(Name, Description, TimeOut) ->
- Ref = make_ref(),
- ?MODULE ! {self(), Ref, {add, Name, Description, TimeOut}},
- receive
- {Ref, {error, Reason}} -> erlang:error(Reason);
- {Ref, Msg} -> Msg
- after 5000 ->
- {error, timeout}
- end.
- cancel(Name) ->
- Ref = make_ref(),
- ?MODULE ! {self(), Ref, {cancel, Name}},
- receive
- {Ref, ok} -> ok
- after 5000 ->
- {error, timeout}
- end.
- listen(Delay) ->
- receive
- M = {done, _Name, _Description} ->
- [M | listen(0)]
- after Delay*1000 ->
- []
- end.
- %%% The Server itself
- loop(S=#state{}) ->
- receive
- {Pid, MsgRef, {subscribe, Client}} ->
- Ref = erlang:monitor(process, Client),
- NewClients = orddict:store(Ref, Client, S#state.clients),
- Pid ! {MsgRef, ok},
- loop(S#state{clients=NewClients});
- {Pid, MsgRef, {add, Name, Description, TimeOut, Pid}} ->
- case valid_datetime(TimeOut) of
- true ->
- EventPid = event:start_link(Name, TimeOut),
- NewEvents = orddict:store(Name,
- #event{name=Name,
- description=Description,
- pid=EventPid,
- clientpid=Pid,
- timeout=TimeOut
- },
- S#state.events),
- Pid ! {MsgRef, ok},
- loop(S#state{events=NewEvents});
- false ->
- Pid ! {MsgRef, {error, bad_timeout}},
- loop(S)
- end;
- {Pid, MsgRef, {cancel, Name}} ->
- Events = case orddict:find(Name, S#state.events) of
- {ok, E} ->
- event:cancel(E#event.pid),
- orddict:erase(Name, S#state.events);
- error ->
- S#state.events
- end,
- Pid ! {MsgRef, ok},
- loop(S#state{events=Events});
- {done, Name} ->
- case orddict:find(Name, S#state.events) of
- {ok, E} ->
- send_to_clients({done, E#event.name, E#event.description},
- E#event.clientpid),
- NewEvents = orddict:erase(Name, S#state.events),
- loop(S#state{events=NewEvents});
- error ->
- %% This may happen if we cancel an event and
- %% it fires at the same time
- loop(S)
- end;
- shutdown ->
- exit(shutdown);
- {'DOWN', Ref, process, _Pid, _Reason} ->
- loop(S#state{clients=orddict:erase(Ref, S#state.clients)});
- code_change ->
- ?MODULE:loop(S);
- {Pid, debug} -> %% used as a hack to let me do some unit testing
- Pid ! S,
- loop(S);
- Unknown ->
- io:format("Unknown message: ~p~n",[Unknown]),
- loop(S)
- end.
- %%% Internal Functions
- send_to_clients(Msg, Pid) ->
- Pid ! Msg.
- valid_datetime({Date,Time}) ->
- try
- calendar:valid_date(Date) andalso valid_time(Time)
- catch
- error:function_clause -> %% not in {{Y,M,D},{H,Min,S}} format
- false
- end;
- valid_datetime(_) ->
- false.
- %% calendar has valid_date, but nothing for days.
- %% This function is based on its interface.
- %% Ugly, but ugh.
- valid_time({H,M,S}) -> valid_time(H,M,S).
- valid_time(H,M,S) when H >= 0, H < 24,
- M >= 0, M < 60,
- S >= 0, S < 60 -> true;
- valid_time(_,_,_) -> false.
- przeslij(P) ->
- receive
- M = {done, _Name, _Description} ->
- P![self(),M],przeslij(P) end.
- klient(P, C)->subscribe(self()),
- add_event("Alarm", "pobudka", C , self()),
- przeslij(P).
- klient2(P, C)->subscribe(self()),
- add_event("Alarm - 2", "pobudka", C , self()),
- przeslij(P).
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement