From fe4a256c05727f43c6c793b620b1638b88c830b3 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 9 Oct 2010 15:04:16 +0200 Subject: Add advanced_event behaviour and use it for account events --- .gitmodules | 3 + cmake/erlang | 1 + cmake/erlang/ErlangTarget.cmake | 35 ------- cmake/erlang/FindErlang.cmake | 6 -- src/core/CMakeLists.txt | 7 +- src/core/advanced_event.erl | 154 +++++++++++++++++++++++++++++++ src/core/ephraim_account.erl | 2 +- src/core/ephraim_account_event_proxy.erl | 4 +- src/core/ephraim_conn.erl | 2 +- src/core/ephraim_conv.erl | 4 +- src/core/ephraim_conv_handler.erl | 10 +- src/core/ephraim_event_proxy.erl | 2 +- src/core/ephraim_roster.erl | 2 +- src/core/ephraim_roster_handler.erl | 6 +- 14 files changed, 178 insertions(+), 60 deletions(-) create mode 100644 .gitmodules create mode 160000 cmake/erlang delete mode 100644 cmake/erlang/ErlangTarget.cmake delete mode 100644 cmake/erlang/FindErlang.cmake create mode 100644 src/core/advanced_event.erl diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..565d4bc --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cmake/erlang"] + path = cmake/erlang + url = git://git.universe-factory.net/cmake-erlang diff --git a/cmake/erlang b/cmake/erlang new file mode 160000 index 0000000..60f4725 --- /dev/null +++ b/cmake/erlang @@ -0,0 +1 @@ +Subproject commit 60f4725115653919e9179ad5f01359568e145047 diff --git a/cmake/erlang/ErlangTarget.cmake b/cmake/erlang/ErlangTarget.cmake deleted file mode 100644 index 2afbc7a..0000000 --- a/cmake/erlang/ErlangTarget.cmake +++ /dev/null @@ -1,35 +0,0 @@ -macro(erl_target name) - parse_arguments(ARGS "HEADERS;OPTIONS" "" ${ARGN}) - - set(headers "") - set(out_files "") - - foreach(header ${ARGS_HEADERS}) - list(APPEND headers "${CMAKE_CURRENT_SOURCE_DIR}/${header}") - endforeach(header ${ARGS_HEADERS}) - - foreach(src ${ARGS_DEFAULT_ARGS}) - set(in_file "${CMAKE_CURRENT_SOURCE_DIR}/${src}") - string(REPLACE ".erl" ".beam" src ${src}) - set(out_file "${CMAKE_CURRENT_BINARY_DIR}/${src}") - - add_custom_command( - OUTPUT - ${out_file} - COMMAND - ${ERLC_EXECUTABLE} - "-o" ${CMAKE_CURRENT_BINARY_DIR} - ${ARGS_OPTIONS} - ${in_file} - DEPENDS - ${in_file} - ${headers} - ) - - list(APPEND out_files "${CMAKE_CURRENT_BINARY_DIR}/${src}") - endforeach(src ${ARGS_DEFAULT_ARGS}) - - add_custom_target( - ${name} ALL DEPENDS ${out_files} - ) -endmacro(erl_target) diff --git a/cmake/erlang/FindErlang.cmake b/cmake/erlang/FindErlang.cmake deleted file mode 100644 index e7cb60f..0000000 --- a/cmake/erlang/FindErlang.cmake +++ /dev/null @@ -1,6 +0,0 @@ -find_program(ERLC_EXECUTABLE NAMES erlc) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Erlang DEFAULT_MSG ERLC_EXECUTABLE) -mark_as_advanced(ERLC_EXECUTABLE) - diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 75055bb..96f760b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,17 +1,18 @@ erl_target(ephraim-core + advanced_event.erl ephraim.erl ephraim_account.erl - ephraim_account_event_proxy.erl + ephraim_account_event_proxy.erl USING advanced_event ephraim_accounts.erl ephraim_config.erl ephraim_conn.erl ephraim_conv.erl - ephraim_conv_handler.erl + ephraim_conv_handler.erl USING advanced_event ephraim_conv_man.erl ephraim_event_proxy.erl ephraim_gui.erl ephraim_roster.erl - ephraim_roster_handler.erl + ephraim_roster_handler.erl USING advanced_event OPTIONS +debug_info ) 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}. diff --git a/src/core/ephraim_account.erl b/src/core/ephraim_account.erl index b71cb08..ad25483 100644 --- a/src/core/ephraim_account.erl +++ b/src/core/ephraim_account.erl @@ -6,7 +6,7 @@ start_link(Account) -> {ok, Pid} = supervisor:start_link(?MODULE, []), - {ok, EventManager} = supervisor:start_child(Pid, {event_man, {gen_event, start_link, []}, permanent, 1000, worker, [gen_event]}), + {ok, EventManager} = supervisor:start_child(Pid, {event_man, {advanced_event, start_link, []}, permanent, 1000, worker, [advanced_event]}), ephraim_event_proxy:start(Account, EventManager), ephraim_account_event_proxy:start(Account, EventManager), diff --git a/src/core/ephraim_account_event_proxy.erl b/src/core/ephraim_account_event_proxy.erl index 726b0e0..9f52d10 100644 --- a/src/core/ephraim_account_event_proxy.erl +++ b/src/core/ephraim_account_event_proxy.erl @@ -1,11 +1,11 @@ -module(ephraim_account_event_proxy). --behaviour(gen_event). +-behaviour(advanced_event). -export([start/2]). -export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]). start(Account, EventManager) -> - gen_event:add_handler(EventManager, ?MODULE, Account). + advanced_event:add_handler(EventManager, ?MODULE, Account). init(Account) -> {ok, Account}. diff --git a/src/core/ephraim_conn.erl b/src/core/ephraim_conn.erl index 308f385..9bc6d2f 100644 --- a/src/core/ephraim_conn.erl +++ b/src/core/ephraim_conn.erl @@ -57,7 +57,7 @@ connected({send_packet, Packet}, Data) -> {next_state,connected,Data}. handle_info(Msg = #received_packet{}, State, Data) -> - gen_event:notify(Data#conn_state.event_manager, {received_packet,Msg}), + advanced_event:notify(Data#conn_state.event_manager, {received_packet,Msg}), {next_state, State, Data}; handle_info(Msg, State, Data) -> io:format("ephraim_conn: ~p~n", [Msg]), diff --git a/src/core/ephraim_conv.erl b/src/core/ephraim_conv.erl index d6ab742..1c51067 100644 --- a/src/core/ephraim_conv.erl +++ b/src/core/ephraim_conv.erl @@ -15,7 +15,7 @@ -spec start_link(pid(), pid(), pid(), binary()) -> ok. start_link(EventManager, Conn, Roster, JID) -> - gen_event:notify(EventManager, {view_update, {conversation, JID, new}}), + advanced_event:notify(EventManager, {view_update, {conversation, JID, new}}), {jid,MyJID} = ephraim_config:get(jid), gen_server:start_link(?MODULE, #conv_state{event_manager=EventManager,connection=Conn,roster=Roster,my_jid=list_to_binary(MyJID),jid=JID}, []). @@ -36,7 +36,7 @@ handle_call(_Msg, _From, State) -> update_view(State, From, Type, Body) -> Alias = ephraim_roster:get_alias(State#conv_state.roster, From), - gen_event:notify(State#conv_state.event_manager, {view_update, {conversation, State#conv_state.jid, {message, Alias, Type, Body}}}). + advanced_event:notify(State#conv_state.event_manager, {view_update, {conversation, State#conv_state.jid, {message, Alias, Type, Body}}}). handle_cast({received_message, From, Type, Body}, State) -> update_view(State, From, Type, Body), diff --git a/src/core/ephraim_conv_handler.erl b/src/core/ephraim_conv_handler.erl index 681e53a..6949661 100644 --- a/src/core/ephraim_conv_handler.erl +++ b/src/core/ephraim_conv_handler.erl @@ -1,6 +1,6 @@ -module(ephraim_conv_handler). -include_lib("exmpp/include/exmpp_client.hrl"). --behaviour(gen_event). +-behaviour(advanced_event). -export([start/4]). -export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]). @@ -13,7 +13,7 @@ }). start(Supervisor, EventManager, Conn, Roster) -> - gen_event:add_handler(EventManager, ?MODULE, #conv_handler_state{supervisor=Supervisor,event_manager=EventManager,connection=Conn,roster=Roster}). + advanced_event:add_handler(EventManager, ?MODULE, #conv_handler_state{supervisor=Supervisor,event_manager=EventManager,connection=Conn,roster=Roster}). init(State) -> {ok, State}. @@ -44,12 +44,12 @@ get_conv(State, JID) -> handle_event({view_request, {conversation,JID,new}}, State) -> {NewState, _} = get_conv(State, JID), - {ok, NewState}; + {handled, NewState}; handle_event({view_request, {conversation,JID,{send_message,Type,Body}}}, State) -> {NewState, Conv} = get_conv(State, JID), ephraim_conv:send_message(Conv, Type, Body), - {ok, NewState}; + {handled, NewState}; handle_event({received_packet, #received_packet{packet_type=message, raw_packet=Packet}}, State) -> From = exmpp_xml:get_attribute(Packet, from, <<"unknown">>), @@ -69,7 +69,7 @@ handle_event({received_packet, #received_packet{packet_type=message, raw_packet= io:format("Received strange message from ~p:~n~p~n", [From, Packet]), State end, - {ok, NewState}; + {handled, NewState}; handle_event(_Event, State) -> {ok, State}. diff --git a/src/core/ephraim_event_proxy.erl b/src/core/ephraim_event_proxy.erl index 4b0e35b..dacc34c 100644 --- a/src/core/ephraim_event_proxy.erl +++ b/src/core/ephraim_event_proxy.erl @@ -11,7 +11,7 @@ init(State) -> {ok, State}. handle_event({view_request, {account, Account, Event}}, {Account, EventManager}) -> - gen_event:notify(EventManager, {view_request, Event}), + advanced_event:notify(EventManager, {view_request, Event}), {ok, {Account, EventManager}}; handle_event(_Event, State) -> diff --git a/src/core/ephraim_roster.erl b/src/core/ephraim_roster.erl index 955b108..3538533 100644 --- a/src/core/ephraim_roster.erl +++ b/src/core/ephraim_roster.erl @@ -112,7 +112,7 @@ viewUpdate(State, JID, RosterEntry) -> if RosterEntry#roster_entry.subscription =:= undefined -> ok; true -> - gen_event:notify(State#roster_state.event_manager, {view_update, {roster_update, JID, RosterEntry#roster_entry.name, RosterEntry#roster_entry.subscription, + advanced_event:notify(State#roster_state.event_manager, {view_update, {roster_update, JID, RosterEntry#roster_entry.name, RosterEntry#roster_entry.subscription, sets:to_list(RosterEntry#roster_entry.groups), dict:to_list(RosterEntry#roster_entry.resources), RosterEntry#roster_entry.avatar}}), ok diff --git a/src/core/ephraim_roster_handler.erl b/src/core/ephraim_roster_handler.erl index fa7c1c7..8056797 100644 --- a/src/core/ephraim_roster_handler.erl +++ b/src/core/ephraim_roster_handler.erl @@ -1,14 +1,14 @@ -module(ephraim_roster_handler). -include_lib("exmpp/include/exmpp_client.hrl"). --behaviour(gen_event). +-behaviour(advanced_event). -export([start/2, stop/1]). -export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]). start(EventManager, Roster) -> - gen_event:add_handler(EventManager, ?MODULE, Roster). + advanced_event:add_handler(EventManager, ?MODULE, Roster). stop(EventManager) -> - gen_event:delete_handler(EventManager, ?MODULE, []). + advanced_event:delete_handler(EventManager, ?MODULE, []). init(Roster) -> {ok, Roster}. -- cgit v1.2.3