Search code examples
erlangejabberdriak

Storing ejabberd packets in Riak


I'm trying to save offline ejabberd messages in Riak. I earlier had problems connecting to Riak but those are resolved now with the help of this forum. But now, with my limited Erlang / ejabberd understanding, I'm failing to get the ejabberd packet saved as a string and then put on Riak. Essentially, when the offline_message_hook is latched, I take the Packet argument and then want to put a backslash for each double quote, so that I can then take this revised string and save as a string value on Riak. However I seem to be struggling with modifying the incoming packet to replace the " chars with \".

Is this the right approach? Or am I missing something here in my design? My application relies on the xml format, so should I instead parse the packet using the p1_xml module and reconstruct the xml using the extracted data elements before storing it on Riak.

Apologies for the very basic and multiple questions but appreciate if someone can throw some light here!

The code that I use to try and replace the " with \" in the incoming packet is: (it doesnt quite work):

NewPacket = re:replace(Packet, "\"", "\\\"", [{return, list}, global]),

So essentially, I would be passing the NewPacket as a value to my Riak calls.


Solution

  • ejabberd is compliant with Riak and it is already storing packets in Riak. For example, mod_offline does that.

    You can look directly in ejabberd code to find how to do that. For example, in mod_offline, here is how ejabberd store the offline message:

    store_offline_msg(Host, {User, _}, Msgs, Len, MaxOfflineMsgs,
                      riak) ->
        Count = if MaxOfflineMsgs =/= infinity ->
                        Len + count_offline_messages(User, Host);
                   true -> 0
                end,
        if
            Count > MaxOfflineMsgs ->
                discard_warn_sender(Msgs);
            true ->
                lists:foreach(
                  fun(#offline_msg{us = US,
                                   timestamp = TS} = M) ->
                          ejabberd_riak:put(M, offline_msg_schema(),
                                            [{i, TS}, {'2i', [{<<"us">>, US}]}])
                  end, Msgs)
        end.
    

    The code of ejabberd_riak:put/3 is:

    put(Rec, RecSchema, IndexInfo) ->
        Key = encode_key(proplists:get_value(i, IndexInfo, element(2, Rec))),
        SecIdxs = [encode_index_key(K, V) ||
                      {K, V} <- proplists:get_value('2i', IndexInfo, [])],
        Table = element(1, Rec),
        Value = encode_record(Rec, RecSchema),
        case put_raw(Table, Key, Value, SecIdxs) of
            ok ->
                ok;
            {error, _} = Error ->
                log_error(Error, put, [{record, Rec},
                                       {index_info, IndexInfo}]),
                Error
        end.
    
    put_raw(Table, Key, Value, Indexes) ->
        Bucket = make_bucket(Table),
        Obj = riakc_obj:new(Bucket, Key, Value, "application/x-erlang-term"),
        Obj1 = if Indexes /= [] ->
                       MetaData = dict:store(<<"index">>, Indexes, dict:new()),
                       riakc_obj:update_metadata(Obj, MetaData);
                  true ->
                       Obj
               end,
        catch riakc_pb_socket:put(get_random_pid(), Obj1).
    

    You should have already the proper API to do what you want in ejabberd regarding Riak packet storage.