diff options
author | Christophe Romain <christophe.romain@process-one.net> | 2015-04-08 17:12:05 +0200 |
---|---|---|
committer | Christophe Romain <christophe.romain@process-one.net> | 2015-04-21 15:24:16 +0200 |
commit | e0563e3918984d151fbea45a5f6fc8255913726d (patch) | |
tree | e62bcc5cc538a722f81c3f53291e02594e576711 /src/nodetree_tree_odbc.erl | |
parent | Improve join/leave cluster scripts (diff) |
PubSub improvements
This commit contains
- code cleanup
- use of db_type instead of old mod_pubsub_odbc
- some minor optimizations
- some minor bugfixes
Diffstat (limited to '')
-rw-r--r-- | src/nodetree_tree_odbc.erl | 589 |
1 files changed, 216 insertions, 373 deletions
diff --git a/src/nodetree_tree_odbc.erl b/src/nodetree_tree_odbc.erl index eb966109b..38fb51c2a 100644 --- a/src/nodetree_tree_odbc.erl +++ b/src/nodetree_tree_odbc.erl @@ -36,437 +36,280 @@ %%% improvements.</p> -module(nodetree_tree_odbc). - +-behaviour(gen_pubsub_nodetree). -author('christophe.romain@process-one.net'). -include("pubsub.hrl"). - -include("jlib.hrl"). --define(PUBSUB, mod_pubsub_odbc). - --define(PLUGIN_PREFIX, <<"node_">>). --define(ODBC_SUFFIX, <<"_odbc">>). - --behaviour(gen_pubsub_nodetree). - -export([init/3, terminate/2, options/0, set_node/1, - get_node/3, get_node/2, get_node/1, get_nodes/2, - get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3, - get_subnodes/3, get_subnodes_tree/3, create_node/6, - delete_node/2]). + get_node/3, get_node/2, get_node/1, get_nodes/2, + get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3, + get_subnodes/3, get_subnodes_tree/3, create_node/6, + delete_node/2]). -export([raw_to_node/2]). -%% ================ -%% API definition -%% ================ +init(_Host, _ServerHost, _Opts) -> + ok. -%% @spec (Host, ServerHost, Opts) -> any() -%% Host = mod_pubsub:host() -%% ServerHost = host() -%% Opts = list() -%% @doc <p>Called during pubsub modules initialisation. Any pubsub plugin must -%% implement this function. It can return anything.</p> -%% <p>This function is mainly used to trigger the setup task necessary for the -%% plugin. It can be used for example by the developer to create the specific -%% module database schema if it does not exists yet.</p> -%% @spec () -> [Option] -%% Option = mod_pubsub:nodetreeOption() -%% @doc Returns the default pubsub node tree options. -%% @spec (Host, Node, From) -> pubsubNode() | {error, Reason} -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() -init(_Host, _ServerHost, _Opts) -> ok. +terminate(_Host, _ServerHost) -> + ok. -terminate(_Host, _ServerHost) -> ok. +options() -> + [{odbc, true} | nodetree_tree:options()]. -options() -> [{virtual_tree, false}, {odbc, true}]. +set_node(Record) when is_record(Record, pubsub_node) -> + {Host, Node} = Record#pubsub_node.nodeid, + Parent = case Record#pubsub_node.parents of + [] -> <<>>; + [First | _] -> First + end, + Type = Record#pubsub_node.type, + H = node_hometree_odbc:encode_host(Host), + N = ejabberd_odbc:escape(Node), + P = ejabberd_odbc:escape(Parent), + Nidx = case nodeidx(Host, Node) of + {result, OldNidx} -> + catch + ejabberd_odbc:sql_query_t([<<"delete from pubsub_node_option where " + "nodeid='">>, OldNidx, <<"';">>]), + catch + ejabberd_odbc:sql_query_t([<<"update pubsub_node set host='">>, + H, <<"' node='">>, N, + <<"' parent='">>, P, + <<"' type='">>, Type, + <<"' where nodeid='">>, + OldNidx, <<"';">>]), + OldNidx; + _ -> + catch + ejabberd_odbc:sql_query_t([<<"insert into pubsub_node(host, node, " + "parent, type) values('">>, + H, <<"', '">>, N, <<"', '">>, P, + <<"', '">>, Type, <<"');">>]), + case nodeidx(Host, Node) of + {result, NewNidx} -> NewNidx; + _ -> none % this should not happen + end + end, + case Nidx of + none -> + {error, ?ERR_INTERNAL_SERVER_ERROR}; + _ -> + lists:foreach(fun ({Key, Value}) -> + SKey = iolist_to_binary(atom_to_list(Key)), + SValue = ejabberd_odbc:escape( + list_to_binary( + lists:flatten(io_lib:fwrite("~p", [Value])))), + catch + ejabberd_odbc:sql_query_t([<<"insert into pubsub_node_option(nodeid, " + "name, val) values('">>, + Nidx, <<"', '">>, + SKey, <<"', '">>, SValue, <<"');">>]) + end, + Record#pubsub_node.options), + {result, Nidx} + end. -get_node(Host, Node, _From) -> get_node(Host, Node). +get_node(Host, Node, _From) -> + get_node(Host, Node). --spec(get_node/2 :: -( - Host :: mod_pubsub:host(), - NodeId :: mod_pubsub:nodeId()) - -> mod_pubsub:pubsubNode() - | {error, _} -). get_node(Host, Node) -> - H = (?PUBSUB):escape(Host), - N = (?PUBSUB):escape(Node), + H = node_hometree_odbc:encode_host(Host), + N = ejabberd_odbc:escape(Node), case catch - ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from " - "pubsub_node where host='">>, - H, <<"' and node='">>, N, <<"';">>]) - of - {selected, - [<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], - [RItem]} -> - raw_to_node(Host, RItem); - {'EXIT', _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; - _ -> {error, ?ERR_ITEM_NOT_FOUND} + ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from " + "pubsub_node where host='">>, + H, <<"' and node='">>, N, <<"';">>]) + of + {selected, + [<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], [RItem]} -> + raw_to_node(Host, RItem); + {'EXIT', _Reason} -> + {error, ?ERR_INTERNAL_SERVER_ERROR}; + _ -> + {error, ?ERR_ITEM_NOT_FOUND} end. --spec(get_node/1 :: -( - NodeIdx::mod_pubsub:nodeIdx()) - -> mod_pubsub:pubsubNode() - | {error, _} -). -get_node(NodeIdx) -> +get_node(Nidx) -> case catch - ejabberd_odbc:sql_query_t([<<"select host, node, parent, type from " - "pubsub_node where nodeid='">>, - NodeIdx, <<"';">>]) - of - {selected, - [<<"host">>, <<"node">>, <<"parent">>, <<"type">>], - [[Host, Node, Parent, Type]]} -> - raw_to_node(Host, [Node, Parent, Type, NodeIdx]); - {'EXIT', _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; - _ -> {error, ?ERR_ITEM_NOT_FOUND} + ejabberd_odbc:sql_query_t([<<"select host, node, parent, type from " + "pubsub_node where nodeid='">>, + Nidx, <<"';">>]) + of + {selected, + [<<"host">>, <<"node">>, <<"parent">>, <<"type">>], [[Host, Node, Parent, Type]]} -> + raw_to_node(Host, [Node, Parent, Type, Nidx]); + {'EXIT', _Reason} -> + {error, ?ERR_INTERNAL_SERVER_ERROR}; + _ -> + {error, ?ERR_ITEM_NOT_FOUND} end. -%% @spec (Host, From) -> [pubsubNode()] | {error, Reason} -%% Host = mod_pubsub:host() | mod_pubsub:jid() -get_nodes(Host, _From) -> get_nodes(Host). +get_nodes(Host, _From) -> + get_nodes(Host). --spec(get_nodes/1 :: -( - Host::mod_pubsub:host()) - -> [mod_pubsub:pubsubNode()] -). get_nodes(Host) -> - H = (?PUBSUB):escape(Host), + H = node_hometree_odbc:encode_host(Host), case catch - ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from " - "pubsub_node where host='">>, - H, <<"';">>]) - of - {selected, - [<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], - RItems} -> - lists:map(fun (Item) -> raw_to_node(Host, Item) end, - RItems); - _ -> [] + ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from " + "pubsub_node where host='">>, H, <<"';">>]) + of + {selected, + [<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], RItems} -> + [raw_to_node(Host, Item) || Item <- RItems]; + _ -> + [] end. -%% @spec (Host, Node, From) -> [{Depth, Record}] | {error, Reason} -%% Host = mod_pubsub:host() | mod_pubsub:jid() -%% Node = mod_pubsub:pubsubNode() -%% From = mod_pubsub:jid() -%% Depth = integer() -%% Record = pubsubNode() -%% @doc <p>Default node tree does not handle parents, return empty list.</p> -%% @spec (Host, Node, From) -> [{Depth, Record}] | {error, Reason} -%% Host = mod_pubsub:host() | mod_pubsub:jid() -%% Node = mod_pubsub:pubsubNode() -%% From = mod_pubsub:jid() -%% Depth = integer() -%% Record = pubsubNode() +get_parentnodes(_Host, _Node, _From) -> + []. + %% @doc <p>Default node tree does not handle parents, return a list %% containing just this node.</p> -get_parentnodes(_Host, _Node, _From) -> []. - --spec(get_parentnodes_tree/3 :: -( - Host :: mod_pubsub:host(), - NodeId :: mod_pubsub:nodeId(), - From :: jid()) - -> [{0, [mod_pubsub:pubsubNode(),...]}] -). - get_parentnodes_tree(Host, Node, From) -> case get_node(Host, Node, From) of - N when is_record(N, pubsub_node) -> [{0, [N]}]; - _Error -> [] + {error, _} -> []; + Record -> [{0, [Record]}] end. get_subnodes(Host, Node, _From) -> get_subnodes(Host, Node). -%% @spec (Host, Index) -> [pubsubNode()] | {error, Reason} -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() --spec(get_subnodes/2 :: -( - Host :: mod_pubsub:host(), - NodeId :: mod_pubsub:nodeId()) - -> [mod_pubsub:pubsubNode()] -). get_subnodes(Host, Node) -> - H = (?PUBSUB):escape(Host), - N = (?PUBSUB):escape(Node), + H = node_hometree_odbc:encode_host(Host), + N = ejabberd_odbc:escape(Node), case catch - ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from " - "pubsub_node where host='">>, - H, <<"' and parent='">>, N, <<"';">>]) - of - {selected, - [<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], - RItems} -> - lists:map(fun (Item) -> raw_to_node(Host, Item) end, - RItems); - _ -> [] + ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from " + "pubsub_node where host='">>, + H, <<"' and parent='">>, N, <<"';">>]) + of + {selected, + [<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], RItems} -> + [raw_to_node(Host, Item) || Item <- RItems]; + _ -> + [] end. get_subnodes_tree(Host, Node, _From) -> get_subnodes_tree(Host, Node). -%% @spec (Host, Index) -> [pubsubNode()] | {error, Reason} -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() --spec(get_subnodes_tree/2 :: -( - Host :: mod_pubsub:host(), - NodeId :: mod_pubsub:nodeId()) - -> [mod_pubsub:pubsubNode()] -). - get_subnodes_tree(Host, Node) -> - H = (?PUBSUB):escape(Host), - N = (?PUBSUB):escape(Node), + H = node_hometree_odbc:encode_host(Host), + N = ejabberd_odbc:escape(Node), case catch - ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from " - "pubsub_node where host='">>, - H, <<"' and node like '">>, N, <<"%';">>]) - of - {selected, - [<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], - RItems} -> - lists:map(fun (Item) -> raw_to_node(Host, Item) end, - RItems); - _ -> [] + ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from " + "pubsub_node where host='">>, + H, <<"' and node like '">>, N, <<"%';">>]) + of + {selected, + [<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], RItems} -> + [raw_to_node(Host, Item) || Item <- RItems]; + _ -> + [] end. -%% @spec (Host, Node, Type, Owner, Options, Parents) -> ok | {error, Reason} -%% Host = mod_pubsub:host() | mod_pubsub:jid() -%% Node = mod_pubsub:pubsubNode() -%% NodeType = mod_pubsub:nodeType() -%% Owner = mod_pubsub:jid() -%% Options = list() -%% Parents = list() - --spec(create_node/6 :: -( - Host :: mod_pubsub:host(), - NodeId :: mod_pubsub:nodeId(), - Type :: binary(), - Owner :: jid(), - Options :: mod_pubsub:nodeOptions(), - Parents :: [mod_pubsub:nodeId()]) - -> {ok, NodeIdx::mod_pubsub:nodeIdx()} - %%% - | {error, _} -). - create_node(Host, Node, Type, Owner, Options, Parents) -> BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), - case nodeid(Host, Node) of - {error, ?ERR_ITEM_NOT_FOUND} -> - ParentExists = case Host of - {_U, _S, _R} -> - %% This is special case for PEP handling - %% PEP does not uses hierarchy - true; - _ -> - case Parents of - [] -> true; - [Parent | _] -> - case nodeid(Host, Parent) of - {result, PNodeId} -> - case nodeowners(PNodeId) of - [{<<>>, Host, <<>>}] -> true; - Owners -> - lists:member(BJID, Owners) - end; - _ -> false - end; - _ -> false - end - end, - case ParentExists of - true -> - case set_node(#pubsub_node{nodeid = {Host, Node}, - parents = Parents, type = Type, - options = Options}) + case nodeidx(Host, Node) of + {error, ?ERR_ITEM_NOT_FOUND} -> + ParentExists = case Host of + {_U, _S, _R} -> + %% This is special case for PEP handling + %% PEP does not uses hierarchy + true; + _ -> + case Parents of + [] -> + true; + [Parent | _] -> + case nodeidx(Host, Parent) of + {result, PNode} -> + case nodeowners(PNode) of + [{<<>>, Host, <<>>}] -> true; + Owners -> lists:member(BJID, Owners) + end; + _ -> + false + end; + _ -> + false + end + end, + case ParentExists of + true -> + case set_node(#pubsub_node{nodeid = {Host, Node}, + parents = Parents, type = Type, + options = Options}) of - {result, NodeId} -> {ok, NodeId}; - Other -> Other - end; - false -> {error, ?ERR_FORBIDDEN} - end; - {result, _} -> {error, ?ERR_CONFLICT}; - Error -> Error + {result, Nidx} -> {ok, Nidx}; + Other -> Other + end; + false -> + {error, ?ERR_FORBIDDEN} + end; + {result, _} -> + {error, ?ERR_CONFLICT}; + Error -> + Error end. -%% @spec (Host, Node) -> [mod_pubsub:node()] -%% Host = mod_pubsub:host() | mod_pubsub:jid() -%% Node = mod_pubsub:pubsubNode() --spec(delete_node/2 :: -( - Host :: mod_pubsub:host(), - NodeId :: mod_pubsub:nodeId()) - -> [mod_pubsub:pubsubNode()] -). - delete_node(Host, Node) -> - H = (?PUBSUB):escape(Host), - N = (?PUBSUB):escape(Node), + H = node_hometree_odbc:encode_host(Host), + N = ejabberd_odbc:escape(Node), Removed = get_subnodes_tree(Host, Node), - catch - ejabberd_odbc:sql_query_t([<<"delete from pubsub_node where host='">>, - H, <<"' and node like '">>, N, <<"%';">>]), + catch ejabberd_odbc:sql_query_t([<<"delete from pubsub_node where host='">>, + H, <<"' and node like '">>, N, <<"%';">>]), Removed. %% helpers --spec(raw_to_node/2 :: -( - Host :: mod_pubsub:host(), - _ :: {NodeId::mod_pubsub:nodeId(), - Parent::mod_pubsub:nodeId(), - Type::binary(), - NodeIdx::mod_pubsub:nodeIdx()}) - -> mod_pubsub:pubsubNode() -). -raw_to_node(Host, [Node, Parent, Type, NodeIdx]) -> +raw_to_node(Host, [Node, Parent, Type, Nidx]) -> Options = case catch - ejabberd_odbc:sql_query_t([<<"select name,val from pubsub_node_option " - "where nodeid='">>, - NodeIdx, <<"';">>]) - of - {selected, [<<"name">>, <<"val">>], ROptions} -> - DbOpts = lists:map(fun ([Key, Value]) -> - RKey = - jlib:binary_to_atom(Key), - Tokens = element(2, - erl_scan:string( - binary_to_list(<<Value/binary, ".">>))), - RValue = element(2, - erl_parse:parse_term(Tokens)), - {RKey, RValue} - end, - ROptions), - Module = - jlib:binary_to_atom(<<(?PLUGIN_PREFIX)/binary, - Type/binary, - (?ODBC_SUFFIX)/binary>>), - StdOpts = Module:options(), - lists:foldl(fun ({Key, Value}, Acc) -> - lists:keyreplace(Key, 1, Acc, - {Key, Value}) - end, - StdOpts, DbOpts); - _ -> [] - end, + ejabberd_odbc:sql_query_t([<<"select name,val from pubsub_node_option " + "where nodeid='">>, Nidx, <<"';">>]) + of + {selected, [<<"name">>, <<"val">>], ROptions} -> + DbOpts = lists:map(fun ([Key, Value]) -> + RKey = jlib:binary_to_atom(Key), + Tokens = element(2, erl_scan:string(binary_to_list(<<Value/binary, ".">>))), + RValue = element(2, erl_parse:parse_term(Tokens)), + {RKey, RValue} + end, + ROptions), + Module = jlib:binary_to_atom(<<"node_", Type/binary, "_odbc">>), + StdOpts = Module:options(), + lists:foldl(fun ({Key, Value}, Acc) -> + lists:keyreplace(Key, 1, Acc, {Key, Value}) + end, + StdOpts, DbOpts); + _ -> + [] + end, Parents = case Parent of - <<>> -> []; - _ -> [Parent] - end, - #pubsub_node{nodeid = - {Host, Node}, - parents = Parents, - id = NodeIdx, type = Type, options = Options}. - -% @spec (NodeRecord) -> ok | {error, Reason} -%% Record = mod_pubsub:pubsub_node() --spec(set_node/1 :: -( - Record::mod_pubsub:pubsubNode()) - -> {result, NodeIdx::mod_pubsub:nodeIdx()} - %%% - | {error, _} -). -set_node(Record) -> - {Host, Node} = Record#pubsub_node.nodeid, - Parent = case Record#pubsub_node.parents of - [] -> <<>>; - [First | _] -> First - end, - Type = Record#pubsub_node.type, - H = (?PUBSUB):escape(Host), - N = (?PUBSUB):escape(Node), - P = (?PUBSUB):escape(Parent), - NodeIdx = case nodeid(Host, Node) of - {result, OldNodeIdx} -> - catch - ejabberd_odbc:sql_query_t([<<"delete from pubsub_node_option where " - "nodeid='">>, - OldNodeIdx, <<"';">>]), - catch - ejabberd_odbc:sql_query_t([<<"update pubsub_node set host='">>, - H, <<"' node='">>, N, - <<"' parent='">>, P, - <<"' type='">>, Type, - <<"' where nodeid='">>, - OldNodeIdx, <<"';">>]), - OldNodeIdx; - _ -> - catch - ejabberd_odbc:sql_query_t([<<"insert into pubsub_node(host, node, " - "parent, type) values('">>, - H, <<"', '">>, N, <<"', '">>, P, - <<"', '">>, Type, <<"');">>]), - case nodeid(Host, Node) of - {result, NewNodeIdx} -> NewNodeIdx; - _ -> none % this should not happen - end - end, - case NodeIdx of - none -> {error, ?ERR_INTERNAL_SERVER_ERROR}; - _ -> - lists:foreach(fun ({Key, Value}) -> - SKey = iolist_to_binary(atom_to_list(Key)), - SValue = - (?PUBSUB):escape(list_to_binary(lists:flatten(io_lib:fwrite("~p", - [Value])))), - catch - ejabberd_odbc:sql_query_t([<<"insert into pubsub_node_option(nodeid, " - "name, val) values('">>, - NodeIdx, <<"', '">>, - SKey, <<"', '">>, - SValue, <<"');">>]) - end, - Record#pubsub_node.options), - {result, NodeIdx} - end. - --spec(nodeid/2 :: -( - Host :: mod_pubsub:host(), - NodeId :: mod_pubsub:nodeId()) - -> {result, NodeIdx::mod_pubsub:nodeIdx()} - %%% - | {error, _} -). - -nodeid(Host, NodeId) -> - H = (?PUBSUB):escape(Host), - N = (?PUBSUB):escape(NodeId), + <<>> -> []; + _ -> [Parent] + end, + #pubsub_node{nodeid = {Host, Node}, + parents = Parents, + id = Nidx, type = Type, options = Options}. + +nodeidx(Host, Node) -> + H = node_hometree_odbc:encode_host(Host), + N = ejabberd_odbc:escape(Node), case catch - ejabberd_odbc:sql_query_t([<<"select nodeid from pubsub_node where " - "host='">>, - H, <<"' and node='">>, N, <<"';">>]) - of - {selected, [<<"nodeid">>], [[NodeIdx]]} -> - {result, NodeIdx}; - {'EXIT', _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; - _ -> {error, ?ERR_ITEM_NOT_FOUND} + ejabberd_odbc:sql_query_t([<<"select nodeid from pubsub_node where " + "host='">>, + H, <<"' and node='">>, N, <<"';">>]) + of + {selected, [<<"nodeid">>], [[Nidx]]} -> + {result, Nidx}; + {'EXIT', _Reason} -> + {error, ?ERR_INTERNAL_SERVER_ERROR}; + _ -> + {error, ?ERR_ITEM_NOT_FOUND} end. --spec(nodeowners/1 :: -( - NodeIdx::mod_pubsub:nodeIdx()) - -> Node_Owners::[ljid()] -). - -nodeowners(NodeIdx) -> - {result, Res} = node_hometree_odbc:get_node_affiliations(NodeIdx), - lists:foldl(fun ({LJID, owner}, Acc) -> [LJID | Acc]; - (_, Acc) -> Acc - end, - [], Res). +nodeowners(Nidx) -> + {result, Res} = node_hometree_odbc:get_node_affiliations(Nidx), + [LJID || {LJID, Aff} <- Res, Aff =:= owner]. |