0
votes

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.

1
The packet are probably already parsed where you process them in ejabberd.Mickaël Rémond
Hi @MickaëlRémond - sorry didnt understand - do you mean to say that I should be leveraging the xml module to extract the data points from the ejabberd packet? When I print the packet at the offline_message_hook, I get something like the below - so thus I believe I do need to either put this in double quotes (how?) and then put on Riak, or else I should use the xml parser to extract / save the data in some structure?vikram17000
{xmlel,<<"message">>,[{<<"type">>,<<"chat">>},{<<"id">>,<<"purplefe7f4130">>},{<<"to">>,<<"[email protected]">>}],[{xmlel,<<"active">>,[{<<"xmlns">>,<<"http://jabber.org/protocol/chatstates">>}],[]},{xmlel,<<"body">>,[],[{xmlcdata,<<"my text message">>}]}]}vikram17000
That's what I mean it is pre-parsed. This is not an XML string.Mickaël Rémond
Thanks @MickaëlRémond - apolgoies for the repeated questions but can you help advise please how do I go about saving this packet on Riak? All I want to do is store this offline message via the offline_message_hook. Calling the standard Riak key-value storage methods fails as am not able to backslash the double quotes in this packet... Thanks much once again.vikram17000

1 Answers

1
votes

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.