Search code examples
erlangejabberderlang-supervisorejabberd-module

How can I receive messages sent to a PID which running inside a gen_server


  • I have a ejabberd server

  • I have a custom module, my_apns_module.erl which is run by ejabberd server like this:

    start_link(Host, Opts) ->
      Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
      ?GEN_SERVER:start_link({local, Proc}, ?MODULE,
                             [Host, Opts], []).
    start(Host, Opts) ->
      Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
      ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]},
                   temporary, 1000, worker, [?MODULE]},
      supervisor:start_child(ejabberd_sup, ChildSpec).
    
    stop(Host) ->
      Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
      ?GEN_SERVER:call(Proc, stop),
      supervisor:delete_child(ejabberd_sup, Proc),
      ok.
    
    init([Host, _Opts]) ->
       ...
    
    handle_call(stop, _From, State) ->
      {stop, normal, ok, State}.
    
    handle_cast(_Msg, State) -> {noreply, State}.
    
    handle_info(#offline_msg{us = _UserServer,
              from = From, to = To, packet = Packet} = _Msg, State) ->
      ...
    
    handle_info(_Info, State) ->
      {noreply, State}.
    
    terminate(_Reason, State) ->
      Host = State#state.host,
      ok.
    
    code_change(_OldVsn, State, _Extra) -> {ok, State}.
    
  • Inside init I run another APNs application to send push notifictions. https://github.com/inaka/apns4erl

    init([Host, _Opts]) ->
          apns:start(),
          case apns:connect(cert, ?APNS_CONNECTION) of
               {ok, PID} -> ?INFO_MSG("apns connection successful with PID ~p~n", [PID]);
               {error, timeout} -> ?ERROR_MSG("apns connection unsuccessful reason timed out", [])
          end,
          {ok, #state{host = Host}}.
    
  • This is working as I can send notifications.

  • Now the documentation (https://github.com/inaka/apns4erl) says:

If network goes down or something unexpected happens the gun connection with APNs will go down. In that case apns4erl will send a message {reconnecting, ServerPid} to the client process, that means apns4erl lost the connection and it is trying to reconnect. Once the connection has been recover a {connection_up, ServerPid} message will be send.

My question is:

  • what code should I write inside my_apns_module.erl to receive {reconnecting, ServerPid} or {connection_up, ServerPid}?

Solution

  • Messages sent to a gen_server process, e.g. GenServerPid ! {ok, 10}}, are handled by:

    handle_info(Msg, State)
    

    So, you could do something like this:

    handle_info({reconnecting, ServerPid}=Msg, State) ->
         %%do something here, like log Msg or change State;
    handl_info({connection_up, ServerPid}=Msg, State) ->
         %%do something here, like log Msg or change State;   
    handle_info(#offline_msg{us = _UserServer,
              from = From, to = To, packet = Packet} = _Msg, State) ->
         %%do something.
    

    Response to comment:

    This is your current code:

    init([Host, _Opts]) ->
          apns:start(),
          case apns:connect(cert, ?APNS_CONNECTION) of
               {ok, PID} -> ?INFO_MSG("apns connection successful with PID ~p~n", [PID]);
               {error, timeout} -> ?ERROR_MSG("apns connection unsuccessful reason timed out", [])
          end,
          {ok, #state{host = Host}}.
    

    You could change that to something like this:

    init([Host, _Opts]) ->
        spawn(?MODULE, start_apns, []),
        ...
    
    
    start_apns() ->
    
              apns:start(),
              case apns:connect(cert, ?APNS_CONNECTION) of
                   {ok, PID} -> ?INFO_MSG("apns connection successful with PID ~p~n", [PID]);
                   {error, timeout} -> ?ERROR_MSG("apns connection unsuccessful reason timed out", [])
              end,
              apns_loop().
    
    apns_loop() ->
        receive
            {reconnecting, ServerPid} -> %%do something;
            {connection_up, ServerPid} -> %% do something;
            Other -> %% do something
        end,
        apns_loop().
      
    

    After you start the apns process, the apns process will enter a loop and wait for messages.