summaryrefslogtreecommitdiffstats
path: root/src/core/advanced_event.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/advanced_event.erl')
-rw-r--r--src/core/advanced_event.erl154
1 files changed, 154 insertions, 0 deletions
diff --git a/src/core/advanced_event.erl b/src/core/advanced_event.erl
new file mode 100644
index 0000000..d4a5b7e
--- /dev/null
+++ b/src/core/advanced_event.erl
@@ -0,0 +1,154 @@
+-module(advanced_event).
+-behaviour(gen_server).
+-export([start_link/0, start_link/1, notify/2, sync_notify/2,
+ add_handler/3, delete_handler/3
+ %, call/3, call/4
+ ]).
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
+
+-record(handler, {module :: atom(),
+ id,
+ state}).
+
+-callback init(InitArgs :: term()) ->
+ {ok, State :: term()}.
+-callback handle_event(Event :: term(), State :: term()) ->
+ {ok, NewState :: term()} |
+ {handled, NewState :: term()} |
+ handled_and_remove |
+ remove_handler.
+-callback handle_call(Request :: term(), State :: term()) ->
+ {ok, Reply :: term(), NewState :: term()} |
+ {remove_handler, Reply :: term()}.
+-callback handle_info(Info :: term(), State :: term()) ->
+ {ok, NewState :: term()} |
+ remove_handler.
+-callback terminate(Args :: (term() | {stop, Reason :: term()} |
+ stop | remove_handler |
+ {error, {'EXIT', Reason :: term()}} |
+ {error, term()}),
+ State :: term()) ->
+ term().
+-callback code_change(OldVsn :: (term() | {down, term()}),
+ State :: term(), Extra :: term()) ->
+ {ok, NewState :: term()}.
+
+-type handler() :: atom() | {atom(), term()}.
+-type emgr_name() :: {'local', atom()} | {'global', atom()}.
+-type emgr_ref() :: atom() | {atom(), atom()} | {'global', atom()} | pid().
+-type start_ret() :: {'ok', pid()} | {'error', term()}.
+
+-define(NO_CALLBACK, 'no callback module').
+
+%-spec start_link() -> start_ret().
+start_link() ->
+ gen_server:start_link(?MODULE, [], []).
+
+%-spec start_link(emgr_name()) -> start_ret().
+start_link(Name) ->
+ gen_server:start_link(Name, ?MODULE, [], []).
+
+init(_Args) ->
+ process_flag(trap_exit, true),
+ {ok, []}.
+
+-spec add_handler(emgr_ref(), handler(), term()) -> term().
+add_handler(Manager, Handler, Args) -> gen_server:call(Manager, {add_handler, Handler, Args}).
+
+-spec delete_handler(emgr_ref(), handler(), term()) -> term().
+delete_handler(Manager, Handler, Args) -> gen_server:call(Manager, {delete_handler, Handler, Args}).
+
+-spec notify(emgr_ref(), term()) -> 'ok'.
+notify(Manager, Event) -> gen_server:cast(Manager, {notify, Event}).
+
+-spec sync_notify(emgr_ref(), term()) -> 'ok'.
+sync_notify(Manager, Event) -> gen_server:call(Manager, {sync_notify, Event}).
+
+%-spec call(emgr_ref(), handler(), term()) -> term().
+%call(M, Handler, Query) -> call1(M, Handler, Query).
+
+%-spec call(emgr_ref(), handler(), term(), timeout()) -> term().
+%call(M, Handler, Query, Timeout) -> call1(M, Handler, Query, Timeout).
+
+
+-spec handle_call(term(), {pid(), term()}, list()) -> {reply, term(), list()}.
+handle_call({add_handler, Handler, Args}, _From, Handlers) ->
+ {Module, Id} = case Handler of
+ {_Mod, _Id} ->
+ Handler;
+ Mod ->
+ {Mod, undefined}
+ end,
+ case catch Module:init(Args) of
+ {ok, State} ->
+ {reply,ok,[#handler{module=Module,id=Id,state=State}|Handlers]};
+ Other ->
+ {reply,Other,Handlers}
+ end;
+handle_call({delete_handler, Handler, Args}, _From, Handlers) ->
+ {Module, Id} = case Handler of
+ {_Mod, _Id} ->
+ Handler;
+ Mod ->
+ {Mod, undefined}
+ end,
+ case remove_from_list(Module, Id, Handlers) of
+ error ->
+ {reply,{error,module_not_found},Handlers};
+ {H,Hs} ->
+ case catch (H#handler.module):terminate(Args, (H#handler.state)) of
+ Result ->
+ {reply,Result,Hs}
+ end
+ end;
+handle_call({sync_notify,Event}, _From, Handlers) ->
+ Handlers1 = call_handlers(Event, Handlers),
+ {reply,ok,Handlers1}.
+
+handle_cast({notify,Event}, Handlers) ->
+ Handlers1 = call_handlers(Event, Handlers),
+ {noreply,Handlers1}.
+
+handle_info(_Msg, Handlers) ->
+ {noreply,Handlers}.
+
+remove_from_list(Module, Id, [Handler|Handlers]) ->
+ case Handler of
+ #handler{module=Module,id=Id} ->
+ {Handler,Handlers};
+ _ ->
+ case remove_from_list(Module, id, Handlers) of
+ {H,Hs} ->
+ {H,[Handler|Hs]};
+ error ->
+ error
+ end
+ end;
+remove_from_list(_, _, []) ->
+ error.
+
+call_handlers(Event, [Handler|Handlers]) ->
+ case catch (Handler#handler.module):handle_event(Event, Handler#handler.state) of
+ {ok, State} ->
+ Rest = call_handlers(Event, Handlers),
+ [Handler#handler{state=State}|Rest];
+ {handled, State} ->
+ [Handler#handler{state=State}|Handlers];
+ remove_handler ->
+ (Handler#handler.module):terminate(remove_handler, Handler#handler.state),
+ call_handlers(Event, Handlers);
+ handled_and_remove ->
+ (Handler#handler.module):terminate(remove_handler, Handler#handler.state),
+ []
+ end;
+call_handlers(_, []) ->
+ [].
+
+terminate(Reason, [Handler|Handlers]) ->
+ (Handler#handler.module):terminate({stop, Reason}, (Handler#handler.state)),
+ terminate(Reason, Handlers);
+terminate(_Reason, []) ->
+ ok.
+
+code_change(_OldVersion, Config, _Extra) ->
+ {ok, Config}.