Skip to content

Commit

Permalink
Merge pull request #1202 from esl/accum-stage-three
Browse files Browse the repository at this point in the history
Accum stage three
  • Loading branch information
michalwski committed Mar 6, 2017
2 parents 65e17fb + ee7dc3d commit f7352e2
Show file tree
Hide file tree
Showing 9 changed files with 317 additions and 218 deletions.
311 changes: 161 additions & 150 deletions apps/ejabberd/src/ejabberd_c2s.erl

Large diffs are not rendered by default.

20 changes: 11 additions & 9 deletions apps/ejabberd/src/mod_blocking.erl
Expand Up @@ -37,7 +37,7 @@ stop(Host) ->
?MODULE, process_iq_set, 50),
ok.

process_iq_get(_, _From = #jid{luser = LUser, lserver = LServer},
process_iq_get(Acc, _From = #jid{luser = LUser, lserver = LServer},
_, #iq{xmlns = ?NS_BLOCKING}, _) ->
Res = case mod_privacy_backend:get_privacy_list(LUser, LServer, <<"blocking">>) of
{error, not_found} ->
Expand All @@ -47,16 +47,17 @@ process_iq_get(_, _From = #jid{luser = LUser, lserver = LServer},
E ->
{error, E}
end,
case Res of
{ok, Lst} ->
{result, blocking_query_response(Lst)};
{error, _} ->
{error, ?ERR_INTERNAL_SERVER_ERROR}
end;
IqRes = case Res of
{ok, Lst} ->
{result, blocking_query_response(Lst)};
{error, _} ->
{error, ?ERR_INTERNAL_SERVER_ERROR}
end,
mongoose_acc:put(iq_result, IqRes, Acc);
process_iq_get(Val, _, _, _, _) ->
Val.

process_iq_set(_, From, _To, #iq{xmlns = ?NS_BLOCKING, sub_el = SubEl}) ->
process_iq_set(Acc, From, _To, #iq{xmlns = ?NS_BLOCKING, sub_el = SubEl}) ->
%% collect needed data
#jid{luser = LUser, lserver = LServer} = From,
#xmlel{name = BType} = SubEl,
Expand All @@ -73,7 +74,8 @@ process_iq_set(_, From, _To, #iq{xmlns = ?NS_BLOCKING, sub_el = SubEl}) ->
%% process
Res = process_blocking_iq_set(Type, LUser, LServer, CurrList, Usrs),
%% respond / notify
complete_iq_set(blocking_command, LUser, LServer, Res);
Res1 = complete_iq_set(blocking_command, LUser, LServer, Res),
mongoose_acc:put(iq_result, Res1, Acc);
process_iq_set(Val, _, _, _) ->
Val.

Expand Down
29 changes: 16 additions & 13 deletions apps/ejabberd/src/mod_muc_light.erl
Expand Up @@ -296,10 +296,10 @@ add_rooms_to_roster(Acc, UserUS) ->
end, Acc, get_rooms_info(lists:sort(
mod_muc_light_db_backend:get_user_rooms(UserUS, undefined)))).

-spec process_iq_get(Acc :: any(), From :: ejabberd:jid(), To :: ejabberd:jid(),
-spec process_iq_get(Acc :: mongoose_acc:t(), From :: ejabberd:jid(), To :: ejabberd:jid(),
IQ :: ejabberd:iq(), ActiveList :: binary()) ->
{stop, {result, [jlib:xmlel()]}} | {error, jlib:xmlel()}.
process_iq_get(_Acc, #jid{ lserver = FromS } = From, To, #iq{} = IQ, _ActiveList) ->
{stop, mongoose_acc:t()} | mongoose_acc:t().
process_iq_get(Acc, #jid{ lserver = FromS } = From, To, #iq{} = IQ, _ActiveList) ->
MUCHost = gen_mod:get_module_opt_subhost(FromS, ?MODULE, default_host()),
case {mod_muc_light_codec_backend:decode(From, To, IQ),
gen_mod:get_module_opt_by_subhost(MUCHost, ?MODULE, blocking, ?DEFAULT_BLOCKING)} of
Expand All @@ -309,17 +309,20 @@ process_iq_get(_Acc, #jid{ lserver = FromS } = From, To, #iq{} = IQ, _ActiveList
{get, Blocking#blocking{ items = Items }}, From, jid:to_lus(To),
fun(_, _, Packet) -> put(encode_res, Packet) end),
#xmlel{ children = ResponseChildren } = erase(encode_res),
{stop, {result, ResponseChildren}};
Result = {result, ResponseChildren},
{stop, mongoose_acc:put(iq_result, Result, Acc)};
{{ok, {get, #blocking{}}}, false} ->
{stop, {error, ?ERR_BAD_REQUEST}};
Result = {error, ?ERR_BAD_REQUEST},
{stop, mongoose_acc:put(iq_result, Result, Acc)};
_ ->
{error, ?ERR_BAD_REQUEST}
Result = {error, ?ERR_BAD_REQUEST},
mongoose_acc:put(iq_result, Result, Acc)
end.

-spec process_iq_set(Acc :: any(), From :: ejabberd:jid(),
-spec process_iq_set(Acc :: mongoose_acc:t(), From :: ejabberd:jid(),
To :: ejabberd:jid(), IQ :: ejabberd:iq()) ->
{stop, {result, [jlib:xmlel()]}} | {error, jlib:xmlel()}.
process_iq_set(_Acc, #jid{ lserver = FromS } = From, To, #iq{} = IQ) ->
{stop, mongoose_acc:t()} | mongoose_acc:t().
process_iq_set(Acc, #jid{ lserver = FromS } = From, To, #iq{} = IQ) ->
MUCHost = gen_mod:get_module_opt_subhost(FromS, ?MODULE, default_host()),
case {mod_muc_light_codec_backend:decode(From, To, IQ),
gen_mod:get_module_opt_by_subhost(MUCHost, ?MODULE, blocking, ?DEFAULT_BLOCKING)} of
Expand All @@ -328,17 +331,17 @@ process_iq_set(_Acc, #jid{ lserver = FromS } = From, To, #iq{} = IQ) ->
ConditionFun = fun({_, _, {WhoU, WhoS}}) -> WhoU =:= <<>> orelse WhoS =:= <<>> end,
case lists:any(ConditionFun, Items) of
true ->
{stop, {error, ?ERR_BAD_REQUEST}};
{stop, mongoose_acc:put(iq_result, {error, ?ERR_BAD_REQUEST}, Acc)};
false ->
ok = mod_muc_light_db_backend:set_blocking(jid:to_lus(From), MUCHost, Items),
mod_muc_light_codec_backend:encode(Blocking, From, jid:to_lus(To), RouteFun),
#xmlel{ children = ResponseChildren } = erase(encode_res),
{stop, {result, ResponseChildren}}
{stop, mongoose_acc:put(iq_result, {result, ResponseChildren}, Acc)}
end;
{{ok, {set, #blocking{}}}, false} ->
{stop, {error, ?ERR_BAD_REQUEST}};
{stop, mongoose_acc:put(iq_result, {error, ?ERR_BAD_REQUEST}, Acc)};
_ ->
{error, ?ERR_BAD_REQUEST}
mongoose_acc:put(iq_result, {error, ?ERR_BAD_REQUEST}, Acc)
end.

-spec is_room_owner(Acc :: boolean(), Room :: ejabberd:jid(), User :: ejabberd:jid()) -> boolean().
Expand Down
4 changes: 2 additions & 2 deletions apps/ejabberd/src/mod_offline.erl
Expand Up @@ -474,8 +474,8 @@ find_x_expire(TimeStamp, [El | Els]) ->
find_x_expire(TimeStamp, Els)
end.

pop_offline_messages(Ls, User, Server) ->
Ls ++ pop_offline_messages(User, Server).
pop_offline_messages(Acc, User, Server) ->
mongoose_acc:append(offline_messages, pop_offline_messages(User, Server), Acc).

pop_offline_messages(User, Server) ->
LUser = jid:nodeprep(User),
Expand Down
76 changes: 39 additions & 37 deletions apps/ejabberd/src/mod_privacy.erl
Expand Up @@ -154,25 +154,26 @@ stop(Host) ->
%% Handlers
%% ------------------------------------------------------------------

process_iq_get(_,
_From = #jid{luser = LUser, lserver = LServer},
_To,
#iq{xmlns = ?NS_PRIVACY, sub_el = #xmlel{children = Els}},
#userlist{name = Active}) ->
case xml:remove_cdata(Els) of
[] ->
process_lists_get(LUser, LServer, Active);
[#xmlel{name = Name, attrs = Attrs}] ->
case Name of
<<"list">> ->
ListName = xml:get_attr(<<"name">>, Attrs),
process_list_get(LUser, LServer, ListName);
_ ->
{error, ?ERR_BAD_REQUEST}
end;
_ ->
{error, ?ERR_BAD_REQUEST}
end;
process_iq_get(Acc,
_From = #jid{luser = LUser, lserver = LServer},
_To,
#iq{xmlns = ?NS_PRIVACY, sub_el = #xmlel{children = Els}},
#userlist{name = Active}) ->
Res = case xml:remove_cdata(Els) of
[] ->
process_lists_get(LUser, LServer, Active);
[#xmlel{name = Name, attrs = Attrs}] ->
case Name of
<<"list">> ->
ListName = xml:get_attr(<<"name">>, Attrs),
process_list_get(LUser, LServer, ListName);
_ ->
{error, ?ERR_BAD_REQUEST}
end;
_ ->
{error, ?ERR_BAD_REQUEST}
end,
mongoose_acc:put(iq_result, Res, Acc);
process_iq_get(Val, _, _, _, _) ->
Val.

Expand All @@ -199,26 +200,27 @@ process_list_get(LUser, LServer, {value, Name}) ->
process_list_get(_LUser, _LServer, false) ->
{error, ?ERR_BAD_REQUEST}.

process_iq_set(_, From, _To, #iq{xmlns = ?NS_PRIVACY, sub_el = SubEl}) ->
process_iq_set(Acc, From, _To, #iq{xmlns = ?NS_PRIVACY, sub_el = SubEl}) ->
#jid{luser = LUser, lserver = LServer} = From,
#xmlel{children = Els} = SubEl,
case xml:remove_cdata(Els) of
[#xmlel{name = Name, attrs = Attrs, children = SubEls}] ->
ListName = xml:get_attr(<<"name">>, Attrs),
case Name of
<<"list">> ->
process_list_set(LUser, LServer, ListName,
xml:remove_cdata(SubEls));
<<"active">> ->
process_active_set(LUser, LServer, ListName);
<<"default">> ->
process_default_set(LUser, LServer, ListName);
_ ->
{error, ?ERR_BAD_REQUEST}
end;
_ ->
{error, ?ERR_BAD_REQUEST}
end;
Res = case xml:remove_cdata(Els) of
[#xmlel{name = Name, attrs = Attrs, children = SubEls}] ->
ListName = xml:get_attr(<<"name">>, Attrs),
case Name of
<<"list">> ->
process_list_set(LUser, LServer, ListName,
xml:remove_cdata(SubEls));
<<"active">> ->
process_active_set(LUser, LServer, ListName);
<<"default">> ->
process_default_set(LUser, LServer, ListName);
_ ->
{error, ?ERR_BAD_REQUEST}
end;
_ ->
{error, ?ERR_BAD_REQUEST}
end,
mongoose_acc:put(iq_result, Res, Acc);
process_iq_set(Val, _, _, _) ->
Val.

Expand Down
3 changes: 2 additions & 1 deletion apps/ejabberd/src/mod_roster.erl
Expand Up @@ -514,7 +514,8 @@ get_subscription_lists(Acc, User, Server) ->
LServer = jid:nameprep(Server),
Items = ?BACKEND:get_subscription_lists(Acc, LUser, LServer),
JID = jid:make(User, Server, <<>>),
fill_subscription_lists(JID, LServer, Items, [], [], []).
SubLists = fill_subscription_lists(JID, LServer, Items, [], [], []),
mongoose_acc:put(subscription_lists, SubLists, Acc).


fill_subscription_lists(JID, LServer, [#roster{} = I | Is], F, T, P) ->
Expand Down
6 changes: 4 additions & 2 deletions apps/ejabberd/src/mod_shared_roster_ldap.erl
Expand Up @@ -151,7 +151,8 @@ process_item(RosterItem, _Host) ->
_ -> RosterItem#roster{subscription = both, ask = none}
end.

get_subscription_lists({F, T, P}, User, Server) ->
get_subscription_lists(Acc, User, Server) ->
{F, T, P} = mongoose_acc:get(subscription_lists, Acc, {[], [], []}),
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
US = {LUser, LServer},
Expand All @@ -161,7 +162,8 @@ get_subscription_lists({F, T, P}, User, Server) ->
end,
DisplayedGroups)),
SRJIDs = [{U1, S1, <<"">>} || {U1, S1} <- SRUsers],
{lists:usort(SRJIDs ++ F), lists:usort(SRJIDs ++ T), P}.
NewLists = {lists:usort(SRJIDs ++ F), lists:usort(SRJIDs ++ T), P},
mongoose_acc:put(subscription_lists, NewLists, Acc).

get_jid_info({Subscription, Groups}, User, Server, JID) ->
LUser = jid:nodeprep(User),
Expand Down
53 changes: 50 additions & 3 deletions apps/ejabberd/src/mongoose_acc.erl
Expand Up @@ -12,8 +12,8 @@
-include("ejabberd.hrl").

%% API
-export([new/0, from_kv/2, put/3, get/2, get/3, append/3, to_map/1]).
-export([from_element/1, from_map/1, update/2, is_acc/1]).
-export([new/0, from_kv/2, put/3, get/2, get/3, append/3, to_map/1, remove/2]).
-export([from_element/1, from_map/1, update/2, is_acc/1, require/2]).
-export([initialise/3, terminate/3, dump/1]).
-export_type([t/0]).

Expand Down Expand Up @@ -64,7 +64,7 @@ from_kv(K, V) ->
-spec from_element(xmlel()) -> t().
from_element(El) ->
#xmlel{name = Name, attrs = Attrs} = El,
Type = xml:get_attr_s(<<"type">>, Attrs),
Type = exml_query:attr(El, <<"type">>, undefined),
#{element => El, mongoose_acc => true, name => Name, attrs => Attrs, type => Type}.

-spec from_map(map()) -> t().
Expand Down Expand Up @@ -108,6 +108,25 @@ append(Key, Val, P) ->
L = get(Key, P, []),
maps:put(Key, append(Val, L), P).

-spec remove(Key :: atom(), Accumulator :: t()) -> t().
remove(Key, Accumulator) ->
maps:remove(Key, Accumulator).

%% @doc Make sure the acc has certain keys - some of them require expensive computations and
%% are therefore not calculated upon instantiation, this func is saying "I will need these,
%% please prepare them for me"
-spec require(atom() | [atom()], t()) -> t().
require([], Acc) ->
Acc;
require([Key|Tail], Acc) ->
Acc1 = case maps:is_key(Key, Acc) of
true -> Acc;
false -> produce(Key, Acc)
end,
require(Tail, Acc1);
require(Key, Acc) ->
require([Key], Acc).

%%%%% internal %%%%%

append(Val, L) when is_list(L), is_list(Val) ->
Expand All @@ -120,3 +139,31 @@ dump(_, []) ->
dump(Acc, [K|Tail]) ->
?ERROR_MSG("~p = ~p", [K, maps:get(K, Acc)]),
dump(Acc, Tail).


%% @doc pattern-match to figure out (a) which attrs can be 'required' (b) how to cook them
produce(xmlns, Acc) ->
read_children(Acc);
produce(command, Acc) ->
read_children(Acc).


%% @doc scan xml children to look for namespace; the name of xml element containing namespace
%% defines the purpose of a stanza, we store it as 'command'; if absent, we store 'undefined'.
read_children(Acc) ->
#xmlel{children = Children} = mongoose_acc:get(element, Acc),
read_children(Acc, Children).

read_children(Acc, []) ->
Acc;
read_children(Acc, [Chld|Tail]) ->
{Xmlns, Command} = case exml_query:attr(Chld, <<"xmlns">>, undefined) of
undefined ->
{undefined, undefined};
X ->
#xmlel{name = Name} = Chld,
{X, Name}
end,
Acc1 = mongoose_acc:put(command, Command, mongoose_acc:put(xmlns, Xmlns, Acc)),
read_children(Acc1, Tail).

33 changes: 32 additions & 1 deletion apps/ejabberd/test/acc_SUITE.erl
Expand Up @@ -21,7 +21,7 @@ all() ->
groups() ->
[
{basic, [sequence],
[store_and_retrieve ]
[store_and_retrieve, init_from_element, get_and_require ]
}
].

Expand All @@ -38,3 +38,34 @@ store_and_retrieve(_C) ->
ok.


init_from_element(_C) ->
Acc = mongoose_acc:from_element(sample_stanza()),
mongoose_acc:dump(Acc),
?PRT("Acc", Acc),
?assertEqual(mongoose_acc:get(name, Acc), <<"iq">>),
?assertEqual(mongoose_acc:get(type, Acc), <<"set">>),
ok.


get_and_require(_C) ->
Acc = mongoose_acc:from_element(sample_stanza()),
?assertEqual(mongoose_acc:get(command, Acc, nope), nope),
?assertEqual(mongoose_acc:get(xmlns, Acc, nope), nope),
Acc1 = mongoose_acc:require(command, Acc),
?assertEqual(mongoose_acc:get(command, Acc1), <<"block">>),
?assertEqual(mongoose_acc:get(xmlns, Acc, nope), nope),
Acc2 = mongoose_acc:require([command, xmlns], Acc),
?assertEqual(mongoose_acc:get(xmlns, Acc2), <<"urn:xmpp:blocking">>),
ok.


sample_stanza() ->
{xmlel, <<"iq">>,
[{<<"xml:lang">>, <<"en">>}, {<<"type">>, <<"set">>}],
[{xmlel, <<"block">>,
[{<<"xmlns">>, <<"urn:xmpp:blocking">>}],
[{xmlel, <<"item">>,
[{<<"jid">>, <<"bob37.814302@localhost">>}],
[]}]}]}.


0 comments on commit f7352e2

Please sign in to comment.