Riak Commit Hook CRDT Increment Counter - erlang

I have a commit hook that I want to update a counter.
Currently I have:
-module(bucket_counter).
-export([precommit/1]).
-record(crdt_op, {mod, op, ctx}).
-define(CRDT_OP, #crdt_op).
-define(V1_COUNTER_TYPE, riak_kv_pncounter).
precommit(RObj) ->
{ok, Client} = riak:local_client(),
Bucket = {<<"counters">>, <<"update_counts">>},
Id = <<"all">>,
Counter = case Client:get(Bucket, Id) of
{error, notfound} -> riak_object:new(Bucket, Id, 0);
{ok, Obj} -> Obj
end,
io:format("Counter ~p~n", [Counter]),
{{Context,_},_} = riak_kv_crdt:value(Counter, ?V1_COUNTER_TYPE),
Op = ?CRDT_OP{mod=?V1_COUNTER_TYPE, op={increment, 1}, ctx=Context},
Counter2 = riak_kv_crdt:update(Counter, <<"1234">>, Op),
io:format("Gen ~p~n", [Counter2]),
%Counter3 = riak_kv_crdt:merge(Counter2),
Client:put(Counter2),
RObj.
This produces the error:
#riak_kv_put_fsm:decode_precommit:887 Problem invoking pre-commit hook bucket_counter:precommit -> error:function_clause
[{riak_kv_crdt,update_crdt,[[{riak_dt_pncounter,{{dict,5,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[[<<"dot">>|{<<252,97,47,244,1,104,136,26>>,{1,63622971158}}]],[],[],[],[],[],[[<<"content-type">>,97,112,112,108,105,99,97,116,105,111,110,47,114,105,97,107,95,99,111,117,110,116,101,114],[<<"X-Riak-VTag">>,53,87,81,75,79,113,110,77,80,111,117,49,71,101,120,122,52,67,89,115,66,122]],[[<<"index">>]],[],[[<<"X-Riak-Last-Modified">>|{1455,751958,325156}]],[],[]}}},{crdt,riak_dt_pncounter,"application/riak_counter",[{<<252,97,47,244,1,104,136,26>>,1,0}]}}}],<<"1234">>,{crdt_op,riak_kv_pncounter,{increment,1},<<>>}],[{file,"src/riak_kv_crdt.erl"},{line,234}]},{riak_kv_crdt,update,3,[{file,"src/riak_kv_crdt.erl"},{line,61}]},{bucket_counter,precommit,1,[{file,"bucket_counter.erl"},{line,24}]},{riak_kv_put_fsm,invoke_hook,4,[{file,"src/riak_kv_put_fsm.erl"},{line,853}]},{riak_kv_put_fsm,precommit,2,[{file,"src/riak_kv_put_fsm.erl"},{line,503}]},{gen_fsm,handle_msg,7,[{file,"gen_fsm.erl"},{line,505}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]
Looking into riak_kv source, It looks like merge only works with Maps and Sets when you have a context:
https://github.com/basho/riak_kv/blob/master/src/riak_kv_crdt.erl#L246
I have tried removing the context but it then crashes because of siblings:
riak_index:parse_object_hook:116 Siblings not allowed: {r_object,{<<"counters">>,<<"update_counts">>},<<"all">>,[{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,49,67,49,85,69,121,66,118,111,84,56,85,118,81,104,104,106,74,101,98,49,71]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,750950,430934}]],[],[]}}},<<69,2,0,0,0,17,114,105,97,107,95,100,116,95,112,110,99,111,117,110,116,101,114,71,2,131,108,0,0,0,1,104,3,109,0,0,0,8,252,97,47,244,156,20,105,128,97,1,97,0,106>>},{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,49,67,49,85,69,121,66,118,111,84,56,85,118,81,104,104,106,74,101,98,49,71]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,750950,430934}]],[],[]}}},<<69,1,71,1,0,0,0,22,70,1,131,108,0,0,0,1,104,2,109,0,0,0,4,49,50,51,52,97,1,106,0,0,0,4,70,1,131,106>>}],[{<<252,97,47,244,156,20,105,128>>,{1,63622970068}}],{dict,1,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[clean|true]],[]}}},undefined}
Updating to map gives me a sibling error:
-module(bucket_counter).
-export([precommit/1]).
-record(crdt_op, {mod, op, ctx}).
-define(CRDT_OP, #crdt_op).
-define(V1_COUNTER_TYPE, riak_kv_pncounter).
precommit(RObj) ->
{ok, Client} = riak:local_client(),
Bucket = {<<"counters">>, <<"update_counts">>},
Id = <<"all">>,
{Counter, Context} = case Client:get(Bucket, Id) of
{error, notfound} ->
Obj = riak_object:new(Bucket, Id, 0),
{Obj, undefined};
{ok, Obj} ->
{{CountContext,_},_} = riak_kv_crdt:value(Obj, riak_dt_map),
{Obj, CountContext}
end,
io:format("Counter ~p~n", [Counter]),
Op = ?CRDT_OP{mod=riak_dt_map, op={update,[{update,{<<"count">>,riak_dt_emcntr},increment}]}, ctx=Context},
Counter2 = riak_kv_crdt:update(Counter, <<"1234">>, Op),
io:format("Gen ~p~n", [Counter2]),
%Counter3 = riak_kv_crdt:merge(Counter2),
Client:put(Counter2),
RObj.
riak_index:parse_object_hook:116 Siblings not allowed: {r_object,{<<"counters">>,<<"update_counts">>},<<"all">>,[{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},<<69,2,0,0,0,11,114,105,97,107,95,100,116,95,109,97,112,77,1,131,80,0,0,0,132,120,1,203,96,206,97,96,96,96,204,96,202,5,82,44,134,70,198,38,137,140,89,80,33,136,32,107,114,126,105,94,73,10,3,95,81,102,98,118,124,74,73,124,106,110,114,94,73,81,6,19,138,42,168,86,184,40,22,227,224,66,25,204,137,140,64,200,144,149,149,193,148,5,4,0,198,254,26,118>>},{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},0}],[],{dict,1,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[clean|true]],[]}}},undefined}
2016-02-18 00:48:25.966 [debug] <0.2105.0>#riak_kv_put_fsm:decode_precommit:880 Pre-commit hook riak_index:parse_object_hook failed with reason {siblings_not_allowed,{r_object,{<<"counters">>,<<"update_counts">>},<<"all">>,[{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},<<69,2,0,0,0,11,114,105,97,107,95,100,116,95,109,97,112,77,1,131,80,0,0,0,132,120,1,203,96,206,97,96,96,96,204,96,202,5,82,44,134,70,198,38,137,140,89,80,33,136,32,107,114,126,105,94,73,10,3,95,81,102,98,118,124,74,73,124,106,110,114,94,73,81,6,19,138,42,168,86,184,40,22,227,224,66,25,204,137,140,64,200,144,149,149,193,148,5,4,0,198,254,26,118>>},{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},0}],[],{dict,1,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[clean|true]],[]}}},undefined}}

I have figured it out, I was going off of 1.4 documentation and instead I needed to do riak_kv_crdt:new(Bucket, Id, riak_dt_map)

Related

{aborted, {bad_type, {...} } on mnesia:write/3

Supressing irrelevant code, i've the following:
% somefile.erl
-record(task, {description, date, completed = false}).
init() ->
{atomic, _} = mnesia:create_table(task, [{attributes, record_info(fields, task)}]).
In other file, where the {aborted, {bad_type, {}}} is ocurring:
-record(task, {id, description, date, completed = false}).
create_task(Req, State) ->
Task = create_task_record(),
Transaction = fun() -> mnesia:write(task, Task, write) end,
{atomic, _} = mnesia:transaction(Transaction),
% ...
When i'm running the code, in the line {atomic, _} = mnesia:transaction(Transaction), i'm receiving the error {aborted, {bad_type, {task, ...}}}.
After hours trying to find, the problem here is in the record task definition. I wasn't using the hrl to share definitions, so i have the definition where i was using it, because of this, in one file the definition was missing the id attribute, so i was having different types.

Ejabberd get room online occupants within module

I am currently trying to get the occupants of a room in a custom Ejabberd module within the muc_filter_message hook, but all attempts to get the room state are timing out.
error:
2016-07-25 10:43:04.802 [error] <0.13909.0>#ejabberd_hooks:run_fold1:368 {timeout,{gen_fsm,sync_send_all_state_event,[<0.13909.0>,get_state]}}
imports + hook function (cut down)
-behaviour(gen_mod).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("jlib.hrl").
-include("mod_muc_room.hrl").
-include("mod_muc.hrl").
-include("ejabberd_http.hrl").
-include("ejabberd_web_admin.hrl").
-include("ejabberd_commands.hrl").
muc_message_sent(Stanza, MUCState, RoomJID, FromJID, FromNick) ->
{_, RoomName, Host, _, _, _, _} = RoomJID,
OccuList = get_room_occupants(RoomName, Host),
?INFO_MSG("muc_message_sent OccuList ~p~n", [OccuList]),
Stanza.
Code for room occupants retrieval:
get_room_occupants(Room, Host) ->
case get_room_pid(Room, Host) of
room_not_found ->
?INFO_MSG("muc_message_sent get_room_occ ~p~n", [room]);
Pid -> get_room_occupants(Pid)
end.
get_room_occupants(Pid) ->
?INFO_MSG("muc_message_sent get_room_pstate ~p~n", [Pid]),
S = get_room_state(Pid),
?INFO_MSG("muc_message_sent get_room_state S ~p~n", [S]),
lists:map(
fun({_LJID, Info}) ->
{jid:to_string(Info#user.jid),
Info#user.nick,
atom_to_list(Info#user.role)}
end,
dict:to_list(S#state.users)).
%% #doc Get the Pid of an existing MUC room, or 'room_not_found'.
get_room_pid(Name, Service) ->
case mnesia:dirty_read(muc_online_room, {Name, Service}) of
[] ->
?INFO_MSG("muc_message_sent get_room_pid ~p~n", [failed]),
room_not_found;
[Room] ->
?INFO_MSG("muc_message_sent get_room_pid ~p~n", [pid]),
Room#muc_online_room.pid
end.
get_room_state(Room_pid) ->
{ok, R} = gen_fsm:sync_send_all_state_event(Room_pid, get_state),
R.
The get_room_occupants code is pulled directly from mod_muc_admin where it works fine (but I couldn't find a way to directly use the functions within that module). Been stuck on this for a while now so any ideas appreciated.

User send packet hook returning `badmatch` error

I am using user send packet hook in my custom module, I am not understanding why getting badmatch error for each of the packet received. i have added declaration part here too.
**Code**
-module(mod_post_log).
-behaviour(gen_mod).
-export([start/2,stop/1,log_user_send/4,post_result/1,send_message/3]).
**strong text**
-include("ejabberd.hrl").
-include("jlib.hrl").
-include("logger.hrl").
start(Host, _Opts) ->
ok = case inets:start() of
{error, {already_started, inets}} ->
ok;
ok ->
ok
end,
ejabberd_hooks:add(user_send_packet, Host,
?MODULE, log_user_send, 50),
ok.
stop(Host) ->
ejabberd_hooks:delete(user_send_packet, Host,
?MODULE, log_user_send, 50),
ok.
log_user_send(Packet, _C2SState, From, To) ->
ok = log_packet(From, To, Packet),
Packet.
log_packet(From, To, #xmlel{name = <<"message">>} = Packet) ->
MessageId = xml:get_tag_attr_s(<<"id">>, Packet),
Type = xml:get_tag_attr_s(list_to_binary("type"), Packet),
send_message(From, To, MessageId, Type),
%% send_message(From, To, xml:get_tag_attr_s(list_to_binary("id"), Packet),xml:get_tag_attr_s(list_to_binary("type"), Packet)),
%% ?INFO_MSG("mod_ack_receipt - MsgID: ~p To: ~p From: ~p", [MessageId, To, From]),
ok = log_message(From, To, Packet);
log_packet(_From, _To, _Packet) ->
ok.
log_message(From, To, #xmlel{attrs = Attrs} = Packet) ->
Type = lists:keyfind(<<"type">>, 1, Attrs),
log_message_filter(Type, From, To, Packet).
log_message_filter({<<"type">>, Type}, From, To, Packet)
when Type =:= <<"chat">>;
Type =:= <<"groupchat">> ->
log_chat(From, To, Packet);
log_message_filter(_Other, _From, _To, _Packet) ->
ok.
log_chat(From, To, #xmlel{children = Els} = Packet) ->
case get_body(Els) of
no_body ->
ok;
{ok, _Body} ->
log_chat_with_body(From, To, Packet)
end.
log_chat_with_body(From, To, Packet) ->
case should_acknowledge(Packet) of
S when (S==true) ->
post_xml(From, To, Packet);
false ->
ok
end,
Packet.
should_acknowledge(#xmlel{name = <<"message">>} = Packet) ->
case {xml:get_attr_s(<<"type">>, Packet#xmlel.attrs),
xml:get_subtag_cdata(Packet, <<"body">>)} of
{<<"error">>, _} ->
false;
{_, <<>>} ->
%% Empty body
false;
_ ->
true
end;
should_acknowledge(#xmlel{}) ->
false.
post_xml(From, To, Packet) ->
Ts = to_iso_8601_date(os:timestamp()),
MessageId = xml:get_tag_attr_s(list_to_binary("id"), Packet),
Type = xml:get_tag_attr_s(list_to_binary("type"), Packet),
Chat_sent = xml:get_tag_attr_s(list_to_binary("chat_sent"), Packet),
Subject = xml:get_path_s(Packet, [{elem, list_to_binary("subject")},cdata]),
Body = xml:get_path_s(Packet,[{elem, list_to_binary("body")}, cdata]),
Sep = "&",
Post = [
"from=", From#jid.luser, Sep,
"to=", To#jid.luser, Sep,
"body=", binary_to_list(Body), Sep,
"type=", binary_to_list(Type),Sep,
"chat_sent=", binary_to_list(Chat_sent),Sep,
"subject=",binary_to_list(Subject),Sep,
"message_id=", binary_to_list(MessageId),Sep,
"xml=",xml:element_to_binary(Packet),Sep,
"done=11"
],
Url = get_opt(url),
TsHeader = get_opt(ts_header, "X-Message-Timestamp"),
FromHeader = get_opt(from_header, "X-Message-From"),
ToHeader = get_opt(to_header, "X-Message-To"),
HttpOptions = get_opt(http_options, []),
ReqOptions = get_opt(req_options, []),
{ok, _ReqId} = httpc:request(post,
{Url, [], "application/x-www-form-urlencoded", list_to_binary(Post)},
HttpOptions,
[ {sync, false},
{receiver, {?MODULE, post_result, []}}
| ReqOptions ]),
?INFO_MSG("post http - MsgID: xml: ~p", [post]),
ok.
post_result({_ReqId, {error, Reason}}) ->
report_error([ {error, Reason } ]);
post_result({_ReqId, Result}) ->
{StatusLine, Headers, Body} = Result,
{_HttpVersion, StatusCode, ReasonPhrase} = StatusLine,
if StatusCode < 200;
StatusCode > 299 ->
ok = report_error([ {status_code, StatusCode},
{reason_phrase, ReasonPhrase},
{headers, Headers},
{body, Body} ]),
ok;
true ->
ok
end.
send_message(From, To, MessageId,Type) ->
Packet = #xmlel{name = <<"iq">>,
attrs = [{<<"to">>, From},{<<"ack">>, MessageId}, {<<"type">>, <<"result">>},{<<"chattype">>, Type}],
children =
[#xmlel{name = <<"ack">>,
attrs = [{<<"xmlns">>,<<"xmpp:ack">> }],
children = []}]},
ejabberd_router:route(From, From, Packet).
get_body(Els) ->
XmlEls = [ El || El <- Els, is_record(El, xmlel) ],
case lists:keyfind(<<"body">>, #xmlel.name, XmlEls) of
false ->
no_body;
#xmlel{children = InnerEls} ->
case lists:keyfind(xmlcdata, 1, InnerEls) of
false ->
no_body;
{xmlcdata, Body} ->
{ok, Body}
end
end.
get_opt(Opt) ->
get_opt(Opt, undefined).
get_opt(Opt, Default) ->
F = fun(Val) when is_binary(Val) -> binary_to_list(Val);
(Val) -> Val
end,
gen_mod:get_module_opt(global, ?MODULE, Opt, F, Default).
report_error(ReportArgs) ->
ok = error_logger:error_report([ mod_post_log_cannot_post | ReportArgs ]).
**Error Log**
{{badmatch,{xmlel,<<"message">>,
[{<<"xml:lang">>,<<"en">>},
{<<"to">>,<<"123456789#xyz.myapp.com">>},
{<<"id">>,<<"AF1xJ-149">>},
{<<"chat_sent">>,<<"2015-12-15T06:45:29.399Z">>},
{<<"type">>,<<"chat">>}],
[{xmlel,<<"size">>,[],[{xmlcdata,<<"0">>}]},
{xmlel,<<"subject">>,[],[{xmlcdata,<<"poke">>}]},
{xmlel,<<"body">>,[],[{xmlcdata,<<"95">>}]},
{xmlel,<<"request">>,
[{<<"xmlns">>,<<"urn:xmpp:receipts">>}],
[]}]}},
[{mod_post_log,log_packet,3,
[{file,"src/mod_post_log.erl"},{line,44}]},
{mod_post_log,log_user_send,4,
[{file,"src/mod_post_log.erl"},{line,33}]},
{ejabberd_hooks,safe_apply,3,
[{file,"src/ejabberd_hooks.erl"},{line,382}]},
{ejabberd_hooks,run_fold1,4,
[{file,"src/ejabberd_hooks.erl"},{line,365}]},
{ejabberd_c2s,session_established2,2,
[{file,"src/ejabberd_c2s.erl"},{line,1296}]},
{p1_fsm,handle_msg,10,[{file,"src/p1_fsm.erl"},{line,582}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,237}]}]}
In file src/mod_post_log.erl at line 44 in function mod_post_log:log_packet/3 is some match operator which doesn't expect to get
{xmlel,<<"message">>,
[{<<"xml:lang">>,<<"en">>},
{<<"to">>,<<"123456789#xyz.myapp.com">>},
{<<"id">>,<<"AF1xJ-149">>},
{<<"chat_sent">>,<<"2015-12-15T06:45:29.399Z">>},
{<<"type">>,<<"chat">>}],
[{xmlel,<<"size">>,[],[{xmlcdata,<<"0">>}]},
{xmlel,<<"subject">>,[],[{xmlcdata,<<"poke">>}]},
{xmlel,<<"body">>,[],[{xmlcdata,<<"95">>}]},
{xmlel,<<"request">>,
[{<<"xmlns">>,<<"urn:xmpp:receipts">>}],
[]}]}
it would be much better to see full module "mod_post_log.erl" as is.
But i think that problem is here :
MessageId = xml:get_tag_attr_s(<<"id">>, Packet),
Packet is a record, and function wait for iolist, so it should be something like
MessageId = xml:get_tag_attr_s(<<"id">>, Packet#xmlel.{{see record declaration}}),

Implementing mod_blocking on MongooseIM

I'm trying to implement mod_blocking that will work only with mod_privacy in odbc module.
I keep getting the response:
<error code='500' type='wait'><internal-server-error0 xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error>
Here is my code:
process_blocklist_block(LUser, LServer, JIDs) ->
Filter = fun (List) ->
AlreadyBlocked = list_to_blocklist_jids(List, []),
lists:foldr(fun (JID, List1) ->
case lists:member(JID, AlreadyBlocked)
of
true -> List1;
false ->
[#listitem{type = jid,
value = JID,
action = deny,
order = 0,
match_all = true}
| List1]
end
end,
List, JIDs)
end,
case process_blocklist_block(LUser, LServer, Filter,odbc)
of
{atomic, {ok, Default, List}} ->
UserList = make_userlist(Default, List),
broadcast_list_update(LUser, LServer, Default,
UserList),
broadcast_blocklist_event(LUser, LServer,
{block, JIDs}),
{result, [], UserList};
_ -> {error, ?ERR_INTERNAL_SERVER_ERROR}
end.
process_blocklist_block(LUser, LServer, Filter, odbc) ->
F = fun () ->
Default = case mod_privacy_odbc:sql_get_default_privacy_list_t(LUser)
of
{selected, [<<"name">>], []} ->
Name = <<"Blocked contacts">>,
mod_privacy_odbc:sql_add_privacy_list(LUser, Name),
mod_privacy_odbc:sql_set_default_privacy_list(LUser, Name),
Name;
{selected, [<<"name">>], [[Name]]} -> Name
end,
{selected, [<<"id">>], [[ID]]} = mod_privacy_odbc:sql_get_privacy_list_id_t(LUser, Default),
case mod_privacy_odbc:sql_get_privacy_list_data_by_id_t(ID)
of
{selected,
[<<"t">>, <<"value">>, <<"action">>, <<"ord">>,
<<"match_all">>, <<"match_iq">>, <<"match_message">>,
<<"match_presence_in">>, <<"match_presence_out">>],
RItems = [_ | _]} ->
List = lists:map(fun mod_privacy_odbc:raw_to_item/1, RItems);
_ -> List = []
end,
NewList = Filter(List),
NewRItems = lists:map(fun mod_privacy_odbc:item_to_raw/1, NewList),
mod_privacy_odbc:sql_set_privacy_list(ID, NewRItems),
{ok, Default, NewList}
end,
ejabberd_odbc:sql_transaction(LServer, F).
I've checked all the queries. They work fine. I struggling with understanding the logic of this piece of code. What is the best way to debug this code, so i can understand when my logic is failing? Could anyone point me in the right direction?
UserList = make_userlist(Default, List),
broadcast_list_update(LUser, LServer, Default,
UserList),
broadcast_blocklist_event(LUser, LServer,
{block, JIDs}),
{result, [], UserList};
_ -> {error, ?ERR_INTERNAL_SERVER_ERROR}
if you expect
_ -> {error, ?ERR_INTERNAL_SERVER_ERROR}
is the point where server returns 'internal server error', you can just change this place to
_Otherwise ->
?WARNING_MSG("Got some unexpected result in mod_priv ~100000p",[_Otherwise]),
{error, ?ERR_INTERNAL_SERVER_ERROR)
and then look at log/ejabberd.log
Of course you need to start mongooseim with loglevel at least 3 in the ejabberd.cfg

Erlang: supervisor:start_child/2 error has me baffled

I'm making slight modifications to Logan/Merritt/Carlson's simple cache, Chapter 6, pp 149-169, Erlang and OTP in Action. So far, no code changes, just renaming the modules.
I start the application:
application:start(gridz).
ok
I insert an item:
gridz_maker:insert(blip, blop).
I get this error:
** exception error: no match of right hand side value
{error,
{function_clause,
[{gridz_edit,init,
[{blop,86400}],
[{file,"src/gridz_edit.erl"},{line,51}]},
{gen_server,init_it,6,
[{file,"gen_server.erl"},{line,304}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]}}
in function gridz_maker:insert/2 (src/gridz_maker.erl, line 15)
Here's the code:
insert(Key, Value) ->
case gridz_store:lookup(Key) of
{ok, Pid} -> gridz_edit:replace(Pid, Value);
{error, _} -> {ok, Pid} = gridz_edit:create(Value), %% line 15
gridz_store:insert(Key, Pid)
end.
I look at line 15:
{error, _} -> {ok, Pid} = gridz_edit:create(Value),
I expect the error because this is a new item. gridz:edit is a gen_server (sc_element in Logan et/al.) Here's the code for create/1:
create(Value) ->
create(Value, ?DEFAULT_LEASE_TIME).
create(Value, LeaseTime) ->
gridz_sup:start_child(Value, LeaseTime).
And here's the code for gridz_sup:start_child/2:
start_child(Value, LeaseTime) ->
supervisor:start_child(?SERVER, [Value, LeaseTime]).
init([]) ->
Grid = {gridz_edit, {gridz_edit, start_link, []},
temporary, brutal_kill, worker, [gridz_edit]},
Children = [Grid],
RestartStrategy = {simple_one_for_one, 0, 1},
{ok, {RestartStrategy, Children}}.
If I execute supervisor:start_child/2 directly, here's what I get:
{error,{function_clause,[{gridz_edit,init,
[{blop,50400}],
[{file,"src/gridz_edit.erl"},{line,51}]},
{gen_server,init_it,6,
[{file,"gen_server.erl"},{line,304}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]}}
Line 51 in gridz_edit is an init function:
init([Value, LeaseTime]) ->
Now = calendar:local_time(),
StartTime = calendar:datetime_to_gregorian_seconds(Now),
{ok,
#state{value = Value,
lease_time = LeaseTime,
start_time = StartTime},
time_left(StartTime, LeaseTime)}.
If I execute it directly, it works:
120> gridz_edit:init([blop, (60 * 60 * 24)]).
{ok,{state,blop,86400,63537666408},86400000}
So now I'm baffled. What am I missing? Why does supervisor:start_child/2 throw an error?
Thanks,
LRP
The error says you are passing in a tuple with 2 members, {blop,86400}, when you seem to be expecting a list of 2 members: [Value, LeaseTime]. In your direct execution, you are also using a list, so it works. You should figure out where the tuple is being created, and create a list instead.

Resources