mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
Limit result set of disco#items for mod_pubsub
The size of a list of nodes returned for disco#items request is now controlled by option 'max_nodes_discoitems'. The default value is 100. The name and the default value of the option is chosen to be consistent with mod_muc's 'max_rooms_discoitems' option.
This commit is contained in:
parent
d300a87059
commit
c604bdb897
@ -61,7 +61,7 @@
|
|||||||
{error, stanza_error()}.
|
{error, stanza_error()}.
|
||||||
|
|
||||||
-callback get_nodes(Host :: host(),
|
-callback get_nodes(Host :: host(),
|
||||||
From :: jid:jid())->
|
Limit :: non_neg_integer() | infinity)->
|
||||||
[pubsubNode()].
|
[pubsubNode()].
|
||||||
|
|
||||||
-callback get_nodes(Host :: host())->
|
-callback get_nodes(Host :: host())->
|
||||||
@ -80,7 +80,7 @@
|
|||||||
|
|
||||||
-callback get_subnodes(Host :: host(),
|
-callback get_subnodes(Host :: host(),
|
||||||
NodeId :: nodeId(),
|
NodeId :: nodeId(),
|
||||||
From :: jid:jid()) ->
|
Limit :: non_neg_integer() | infinity) ->
|
||||||
[pubsubNode()].
|
[pubsubNode()].
|
||||||
|
|
||||||
-callback get_subnodes_tree(Host :: host(),
|
-callback get_subnodes_tree(Host :: host(),
|
||||||
|
@ -498,6 +498,7 @@ disco_sm_items(Acc, _From, _To, _Node, _Lang) -> Acc.
|
|||||||
|
|
||||||
-spec disco_items(ljid(), binary(), jid()) -> [disco_item()].
|
-spec disco_items(ljid(), binary(), jid()) -> [disco_item()].
|
||||||
disco_items(Host, <<>>, From) ->
|
disco_items(Host, <<>>, From) ->
|
||||||
|
MaxNodes = mod_pubsub_opt:max_nodes_discoitems(serverhost(Host)),
|
||||||
Action =
|
Action =
|
||||||
fun(#pubsub_node{nodeid = {_, Node}, options = Options,
|
fun(#pubsub_node{nodeid = {_, Node}, options = Options,
|
||||||
type = Type, id = Nidx, owners = O}, Acc) ->
|
type = Type, id = Nidx, owners = O}, Acc) ->
|
||||||
@ -513,7 +514,7 @@ disco_items(Host, <<>>, From) ->
|
|||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
NodeBloc = fun() ->
|
NodeBloc = fun() ->
|
||||||
case tree_call(Host, get_nodes, [Host]) of
|
case tree_call(Host, get_nodes, [Host, MaxNodes]) of
|
||||||
Nodes when is_list(Nodes) ->
|
Nodes when is_list(Nodes) ->
|
||||||
{result, lists:foldl(Action, [], Nodes)};
|
{result, lists:foldl(Action, [], Nodes)};
|
||||||
Error ->
|
Error ->
|
||||||
@ -1007,8 +1008,9 @@ iq_disco_info(ServerHost, Host, SNode, From, Lang) ->
|
|||||||
|
|
||||||
-spec iq_disco_items(host(), binary(), jid(), undefined | rsm_set()) ->
|
-spec iq_disco_items(host(), binary(), jid(), undefined | rsm_set()) ->
|
||||||
{result, disco_items()} | {error, stanza_error()}.
|
{result, disco_items()} | {error, stanza_error()}.
|
||||||
iq_disco_items(Host, <<>>, From, _RSM) ->
|
iq_disco_items(Host, <<>>, _From, _RSM) ->
|
||||||
case tree_action(Host, get_subnodes, [Host, <<>>, From]) of
|
MaxNodes = mod_pubsub_opt:max_nodes_discoitems(serverhost(Host)),
|
||||||
|
case tree_action(Host, get_subnodes, [Host, <<>>, MaxNodes]) of
|
||||||
{error, #stanza_error{}} = Err ->
|
{error, #stanza_error{}} = Err ->
|
||||||
Err;
|
Err;
|
||||||
Nodes when is_list(Nodes) ->
|
Nodes when is_list(Nodes) ->
|
||||||
@ -1039,6 +1041,7 @@ iq_disco_items(Host, Item, From, RSM) ->
|
|||||||
[_Node, _ItemId] ->
|
[_Node, _ItemId] ->
|
||||||
{result, #disco_items{}};
|
{result, #disco_items{}};
|
||||||
[Node] ->
|
[Node] ->
|
||||||
|
MaxNodes = mod_pubsub_opt:max_nodes_discoitems(serverhost(Host)),
|
||||||
Action = fun(#pubsub_node{id = Nidx, type = Type, options = Options, owners = O}) ->
|
Action = fun(#pubsub_node{id = Nidx, type = Type, options = Options, owners = O}) ->
|
||||||
Owners = node_owners_call(Host, Type, Nidx, O),
|
Owners = node_owners_call(Host, Type, Nidx, O),
|
||||||
{NodeItems, RsmOut} = case get_allowed_items_call(
|
{NodeItems, RsmOut} = case get_allowed_items_call(
|
||||||
@ -1046,7 +1049,7 @@ iq_disco_items(Host, Item, From, RSM) ->
|
|||||||
{result, R} -> R;
|
{result, R} -> R;
|
||||||
_ -> {[], undefined}
|
_ -> {[], undefined}
|
||||||
end,
|
end,
|
||||||
case tree_call(Host, get_subnodes, [Host, Node, From]) of
|
case tree_call(Host, get_subnodes, [Host, Node, MaxNodes]) of
|
||||||
SubNodes when is_list(SubNodes) ->
|
SubNodes when is_list(SubNodes) ->
|
||||||
Nodes = lists:map(
|
Nodes = lists:map(
|
||||||
fun(#pubsub_node{nodeid = {_, SubNode}, options = SubOptions}) ->
|
fun(#pubsub_node{nodeid = {_, SubNode}, options = SubOptions}) ->
|
||||||
@ -3154,7 +3157,7 @@ send_last_pep(From, To) ->
|
|||||||
Host = host(ServerHost),
|
Host = host(ServerHost),
|
||||||
Publisher = jid:tolower(From),
|
Publisher = jid:tolower(From),
|
||||||
Owner = jid:remove_resource(Publisher),
|
Owner = jid:remove_resource(Publisher),
|
||||||
case tree_action(Host, get_nodes, [Owner, From]) of
|
case tree_action(Host, get_nodes, [Owner, infinity]) of
|
||||||
Nodes when is_list(Nodes) ->
|
Nodes when is_list(Nodes) ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = Nidx, options = Options}) ->
|
fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = Nidx, options = Options}) ->
|
||||||
@ -4123,6 +4126,8 @@ mod_opt_type(last_item_cache) ->
|
|||||||
econf:bool();
|
econf:bool();
|
||||||
mod_opt_type(max_items_node) ->
|
mod_opt_type(max_items_node) ->
|
||||||
econf:non_neg_int();
|
econf:non_neg_int();
|
||||||
|
mod_opt_type(max_nodes_discoitems) ->
|
||||||
|
econf:non_neg_int(infinity);
|
||||||
mod_opt_type(max_subscriptions_node) ->
|
mod_opt_type(max_subscriptions_node) ->
|
||||||
econf:non_neg_int();
|
econf:non_neg_int();
|
||||||
mod_opt_type(force_node_config) ->
|
mod_opt_type(force_node_config) ->
|
||||||
@ -4168,6 +4173,7 @@ mod_options(Host) ->
|
|||||||
{ignore_pep_from_offline, true},
|
{ignore_pep_from_offline, true},
|
||||||
{last_item_cache, false},
|
{last_item_cache, false},
|
||||||
{max_items_node, ?MAXITEMS},
|
{max_items_node, ?MAXITEMS},
|
||||||
|
{max_nodes_discoitems, 100},
|
||||||
{nodetree, ?STDTREE},
|
{nodetree, ?STDTREE},
|
||||||
{pep_mapping, []},
|
{pep_mapping, []},
|
||||||
{plugins, [?STDNODE]},
|
{plugins, [?STDNODE]},
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
-export([ignore_pep_from_offline/1]).
|
-export([ignore_pep_from_offline/1]).
|
||||||
-export([last_item_cache/1]).
|
-export([last_item_cache/1]).
|
||||||
-export([max_items_node/1]).
|
-export([max_items_node/1]).
|
||||||
|
-export([max_nodes_discoitems/1]).
|
||||||
-export([max_subscriptions_node/1]).
|
-export([max_subscriptions_node/1]).
|
||||||
-export([name/1]).
|
-export([name/1]).
|
||||||
-export([nodetree/1]).
|
-export([nodetree/1]).
|
||||||
@ -73,6 +74,12 @@ max_items_node(Opts) when is_map(Opts) ->
|
|||||||
max_items_node(Host) ->
|
max_items_node(Host) ->
|
||||||
gen_mod:get_module_opt(Host, mod_pubsub, max_items_node).
|
gen_mod:get_module_opt(Host, mod_pubsub, max_items_node).
|
||||||
|
|
||||||
|
-spec max_nodes_discoitems(gen_mod:opts() | global | binary()) -> 'infinity' | non_neg_integer().
|
||||||
|
max_nodes_discoitems(Opts) when is_map(Opts) ->
|
||||||
|
gen_mod:get_opt(max_nodes_discoitems, Opts);
|
||||||
|
max_nodes_discoitems(Host) ->
|
||||||
|
gen_mod:get_module_opt(Host, mod_pubsub, max_nodes_discoitems).
|
||||||
|
|
||||||
-spec max_subscriptions_node(gen_mod:opts() | global | binary()) -> 'undefined' | non_neg_integer().
|
-spec max_subscriptions_node(gen_mod:opts() | global | binary()) -> 'undefined' | non_neg_integer().
|
||||||
max_subscriptions_node(Opts) when is_map(Opts) ->
|
max_subscriptions_node(Opts) when is_map(Opts) ->
|
||||||
gen_mod:get_opt(max_subscriptions_node, Opts);
|
gen_mod:get_opt(max_subscriptions_node, Opts);
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
-author('christophe.romain@process-one.net').
|
-author('christophe.romain@process-one.net').
|
||||||
|
|
||||||
-include_lib("stdlib/include/qlc.hrl").
|
-include_lib("stdlib/include/qlc.hrl").
|
||||||
|
-include_lib("stdlib/include/ms_transform.hrl").
|
||||||
|
|
||||||
-include("pubsub.hrl").
|
-include("pubsub.hrl").
|
||||||
-include("xmpp.hrl").
|
-include("xmpp.hrl").
|
||||||
@ -81,11 +82,21 @@ get_node(Nidx) ->
|
|||||||
_ -> {error, xmpp:err_item_not_found(?T("Node not found"), ejabberd_option:language())}
|
_ -> {error, xmpp:err_item_not_found(?T("Node not found"), ejabberd_option:language())}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_nodes(Host, _From) ->
|
|
||||||
get_nodes(Host).
|
|
||||||
|
|
||||||
get_nodes(Host) ->
|
get_nodes(Host) ->
|
||||||
mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, _ = '_'}).
|
get_nodes(Host, infinity).
|
||||||
|
|
||||||
|
get_nodes(Host, infinity) ->
|
||||||
|
mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, _ = '_'});
|
||||||
|
get_nodes(Host, Limit) ->
|
||||||
|
case mnesia:select(
|
||||||
|
pubsub_node,
|
||||||
|
ets:fun2ms(
|
||||||
|
fun(#pubsub_node{nodeid = {H, _}} = Node) when H == Host ->
|
||||||
|
Node
|
||||||
|
end), Limit, read) of
|
||||||
|
'$end_of_table' -> [];
|
||||||
|
{Nodes, _} -> Nodes
|
||||||
|
end.
|
||||||
|
|
||||||
get_parentnodes(Host, Node, _From) ->
|
get_parentnodes(Host, Node, _From) ->
|
||||||
case catch mnesia:read({pubsub_node, {Host, Node}}) of
|
case catch mnesia:read({pubsub_node, {Host, Node}}) of
|
||||||
@ -109,25 +120,40 @@ get_parentnodes_tree(Host, Node, Level, Acc) ->
|
|||||||
Acc
|
Acc
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_subnodes(Host, Node, _From) ->
|
get_subnodes(Host, <<>>, infinity) ->
|
||||||
get_subnodes(Host, Node).
|
mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, parents = [], _ = '_'});
|
||||||
|
get_subnodes(Host, <<>>, Limit) ->
|
||||||
get_subnodes(Host, <<>>) ->
|
case mnesia:select(
|
||||||
Q = qlc:q([N
|
pubsub_node,
|
||||||
|| #pubsub_node{nodeid = {NHost, _},
|
ets:fun2ms(
|
||||||
parents = Parents} =
|
fun(#pubsub_node{nodeid = {H, _}, parents = []} = Node) when H == Host ->
|
||||||
N
|
Node
|
||||||
<- mnesia:table(pubsub_node),
|
end), Limit, read) of
|
||||||
Host == NHost, Parents == []]),
|
'$end_of_table' -> [];
|
||||||
qlc:e(Q);
|
{Nodes, _} -> Nodes
|
||||||
get_subnodes(Host, Node) ->
|
end;
|
||||||
|
get_subnodes(Host, Node, infinity) ->
|
||||||
Q = qlc:q([N
|
Q = qlc:q([N
|
||||||
|| #pubsub_node{nodeid = {NHost, _},
|
|| #pubsub_node{nodeid = {NHost, _},
|
||||||
parents = Parents} =
|
parents = Parents} =
|
||||||
N
|
N
|
||||||
<- mnesia:table(pubsub_node),
|
<- mnesia:table(pubsub_node),
|
||||||
Host == NHost, lists:member(Node, Parents)]),
|
Host == NHost, lists:member(Node, Parents)]),
|
||||||
qlc:e(Q).
|
qlc:e(Q);
|
||||||
|
get_subnodes(Host, Node, Limit) ->
|
||||||
|
case mnesia:select(
|
||||||
|
pubsub_node,
|
||||||
|
ets:fun2ms(
|
||||||
|
fun(#pubsub_node{nodeid = {H, _}, parents = Ps} = N)
|
||||||
|
when H == Host andalso Ps /= [] -> N
|
||||||
|
end), Limit, read) of
|
||||||
|
'$end_of_table' -> [];
|
||||||
|
{Nodes, _} ->
|
||||||
|
lists:filter(
|
||||||
|
fun(#pubsub_node{parents = Parents}) ->
|
||||||
|
lists:member(Node, Parents)
|
||||||
|
end, Nodes)
|
||||||
|
end.
|
||||||
|
|
||||||
get_subnodes_tree(Host, Node, _From) ->
|
get_subnodes_tree(Host, Node, _From) ->
|
||||||
get_subnodes_tree(Host, Node).
|
get_subnodes_tree(Host, Node).
|
||||||
|
@ -140,16 +140,25 @@ get_node(Nidx) ->
|
|||||||
{error, xmpp:err_item_not_found(?T("Node not found"), ejabberd_option:language())}
|
{error, xmpp:err_item_not_found(?T("Node not found"), ejabberd_option:language())}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_nodes(Host, _From) ->
|
|
||||||
get_nodes(Host).
|
|
||||||
|
|
||||||
get_nodes(Host) ->
|
get_nodes(Host) ->
|
||||||
|
get_nodes(Host, infinity).
|
||||||
|
|
||||||
|
get_nodes(Host, Limit) ->
|
||||||
H = node_flat_sql:encode_host(Host),
|
H = node_flat_sql:encode_host(Host),
|
||||||
case catch
|
Query = fun(mssql, _) when is_integer(Limit), Limit>=0 ->
|
||||||
ejabberd_sql:sql_query_t(
|
ejabberd_sql:sql_query_t(
|
||||||
?SQL("select @(node)s, @(parent)s, @(plugin)s, @(nodeid)d from pubsub_node "
|
?SQL("select top %(Limit)d @(node)s, @(parent)s, @(plugin)s, @(nodeid)d "
|
||||||
"where host=%(H)s"))
|
"from pubsub_node where host=%(H)s"));
|
||||||
of
|
(_, _) when is_integer(Limit), Limit>=0 ->
|
||||||
|
ejabberd_sql:sql_query_t(
|
||||||
|
?SQL("select @(node)s, @(parent)s, @(plugin)s, @(nodeid)d "
|
||||||
|
"from pubsub_node where host=%(H)s limit %(Limit)d"));
|
||||||
|
(_, _) ->
|
||||||
|
ejabberd_sql:sql_query_t(
|
||||||
|
?SQL("select @(node)s, @(parent)s, @(plugin)s, @(nodeid)d "
|
||||||
|
"from pubsub_node where host=%(H)s"))
|
||||||
|
end,
|
||||||
|
case ejabberd_sql:sql_query_t(Query) of
|
||||||
{selected, RItems} ->
|
{selected, RItems} ->
|
||||||
[raw_to_node(Host, Item) || Item <- RItems];
|
[raw_to_node(Host, Item) || Item <- RItems];
|
||||||
_ ->
|
_ ->
|
||||||
@ -178,16 +187,23 @@ get_parentnodes_tree(Host, Node, Level, Acc) ->
|
|||||||
Acc
|
Acc
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_subnodes(Host, Node, _From) ->
|
get_subnodes(Host, Node, Limit) ->
|
||||||
get_subnodes(Host, Node).
|
|
||||||
|
|
||||||
get_subnodes(Host, Node) ->
|
|
||||||
H = node_flat_sql:encode_host(Host),
|
H = node_flat_sql:encode_host(Host),
|
||||||
case catch
|
Query = fun(mssql, _) when is_integer(Limit), Limit>=0 ->
|
||||||
ejabberd_sql:sql_query_t(
|
ejabberd_sql:sql_query_t(
|
||||||
?SQL("select @(node)s, @(parent)s, @(plugin)s, @(nodeid)d from pubsub_node "
|
?SQL("select top %(Limit)d @(node)s, @(parent)s, @(plugin)s, @(nodeid)d "
|
||||||
"where host=%(H)s and parent=%(Node)s"))
|
"from pubsub_node where host=%(H)s and parent=%(Node)s"));
|
||||||
of
|
(_, _) when is_integer(Limit), Limit>=0 ->
|
||||||
|
ejabberd_sql:sql_query_t(
|
||||||
|
?SQL("select @(node)s, @(parent)s, @(plugin)s, @(nodeid)d "
|
||||||
|
"from pubsub_node where host=%(H)s and parent=%(Node)s "
|
||||||
|
"limit %(Limit)d"));
|
||||||
|
(_, _) ->
|
||||||
|
ejabberd_sql:sql_query_t(
|
||||||
|
?SQL("select @(node)s, @(parent)s, @(plugin)s, @(nodeid)d "
|
||||||
|
"from pubsub_node where host=%(H)s and parent=%(Node)s"))
|
||||||
|
end,
|
||||||
|
case ejabberd_sql:sql_query_t(Query) of
|
||||||
{selected, RItems} ->
|
{selected, RItems} ->
|
||||||
[raw_to_node(Host, Item) || Item <- RItems];
|
[raw_to_node(Host, Item) || Item <- RItems];
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -65,10 +65,10 @@ get_node(Nidx) ->
|
|||||||
{Host, Node} = nodeid(Nidx),
|
{Host, Node} = nodeid(Nidx),
|
||||||
node_record(Host, Node, Nidx).
|
node_record(Host, Node, Nidx).
|
||||||
|
|
||||||
get_nodes(Host, _From) ->
|
get_nodes(Host) ->
|
||||||
get_nodes(Host).
|
get_nodes(Host, infinity).
|
||||||
|
|
||||||
get_nodes(_Host) ->
|
get_nodes(_Host, _Limit) ->
|
||||||
[].
|
[].
|
||||||
|
|
||||||
get_parentnodes(_Host, _Node, _From) ->
|
get_parentnodes(_Host, _Node, _From) ->
|
||||||
@ -77,10 +77,7 @@ get_parentnodes(_Host, _Node, _From) ->
|
|||||||
get_parentnodes_tree(Host, Node, From) ->
|
get_parentnodes_tree(Host, Node, From) ->
|
||||||
[{0, [get_node(Host, Node, From)]}].
|
[{0, [get_node(Host, Node, From)]}].
|
||||||
|
|
||||||
get_subnodes(Host, Node, _From) ->
|
get_subnodes(_Host, _Node, _From) ->
|
||||||
get_subnodes(Host, Node).
|
|
||||||
|
|
||||||
get_subnodes(_Host, _Node) ->
|
|
||||||
[].
|
[].
|
||||||
|
|
||||||
get_subnodes_tree(Host, Node, _From) ->
|
get_subnodes_tree(Host, Node, _From) ->
|
||||||
|
Loading…
Reference in New Issue
Block a user