Skip to content

Instantly share code, notes, and snippets.

@fpdevil
Forked from elbrujohalcon/gen_event_repeater.erl
Created August 19, 2013 11:53
Show Gist options
  • Save fpdevil/6268346 to your computer and use it in GitHub Desktop.
Save fpdevil/6268346 to your computer and use it in GitHub Desktop.
%%%-------------------------------------------------------------------
%%% @author Fernando Benavides <[email protected]>
%%% @copyright (C) 2011 Inaka Networks S.R.L.
%%% @doc It listens and just repeats...
%%% @end
%%%-------------------------------------------------------------------
-module(gen_event_repeater).
-author('Fernando Benavides <[email protected]>').
-behaviour(gen_event).
-export([start/2, start/1, start_link/1, start_link/2]).
-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]).
-include("elog.hrl").
-include("records.hrl").
-record(state, {dispatcher :: pid(),
reference :: reference()}).
-type state() :: #state{}.
%% ====================================================================
%% External functions
%% ====================================================================
-spec start(pid() | atom() | {global, atom()}) -> {ok, pid()}.
start(Source) ->
subscribe(Source, gen_event:start()).
-spec start({local, atom()} | {global, atom()}, pid() | atom() | {global, atom()}) -> {ok, pid()}.
start(Name, Source) ->
subscribe(Source, gen_event:start(Name)).
-spec start_link(pid() | atom() | {global, atom()}) -> {ok, pid()}.
start_link(Source) ->
subscribe(Source, gen_event:start_link()).
-spec start_link({local, atom()} | {global, atom()}, pid() | atom() | {global, atom()}) -> {ok, pid()}.
start_link(Name, Source) ->
subscribe(Source, gen_event:start_link(Name)).
%% ====================================================================
%% Server functions
%% ====================================================================
%% @hidden
-spec init(pid()) -> {ok, state()}.
init(Dispatcher) ->
Ref = erlang:monitor(process, Dispatcher),
{ok, #state{dispatcher = Dispatcher, reference = Ref}}.
%% @hidden
-spec handle_event(term(), state()) -> {ok, state()}.
handle_event(Event, State) ->
gen_event:notify(State#state.dispatcher, Event),
{ok, State}.
%% @hidden
-spec handle_call(term(), state()) -> {ok, ok, state()}.
handle_call(_Call, State) -> {ok, ok, State}.
%% @hidden
-spec handle_info(term(), state()) -> {ok, state()} | remove_handler.
handle_info({'DOWN', Ref, _Type, _Dispatcher, Info}, State = #state{reference = Ref}) ->
?WARN("Our dispatcher (~p) died... removing ourselves from the source...~n\t~p~n", [State#state.dispatcher, Info]),
remove_handler;
handle_info(Info, State) ->
State#state.dispatcher ! Info,
{ok, State}.
%% @hidden
-spec terminate(term(), state()) -> ok.
terminate(remove_handler, _State) ->
ok;
terminate(stop, State) ->
?INFO("Source dispatcher stopped. Stopping our own dispatcher too...~n", []),
gen_event:stop(State#state.dispatcher);
terminate(Reason, State) ->
?INFO("Source dispatcher exited (~p). Exiting our own dispatcher too...~n", [Reason]),
exit(State#state.dispatcher, Reason).
%% @hidden
-spec code_change(term(), state(), term()) -> {ok, state()}.
code_change(_OldVsn, State, _Extra) -> {ok, State}.
%% ====================================================================
%% Private functions
%% ====================================================================
subscribe(Source, {ok, Pid}) ->
try gen_event:add_handler(Source, {?MODULE, Pid}, Pid) of
ok -> {ok, Pid}
catch
_:Error ->
?WARN("gen_event:add_handler error:~n~p~n", [Error]),
gen_event:stop(Pid),
throw(Error)
end;
subscribe(Source, {error, {already_started, Pid}}) ->
try
case lists:member({?MODULE, Pid}, gen_event:which_handlers(Source)) of
true ->
{ok, Pid};
false ->
ok = gen_event:add_handler(Source, {?MODULE, Pid}, Pid),
{ok, Pid}
end
catch
_:Error ->
?WARN("gen_event:add_handler error:~n~p~n", [Error]),
gen_event:stop(Pid),
throw(Error)
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment