25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-24 16:23:40 +01:00

PubSub improvements

This commit contains
- code cleanup
- use of db_type instead of old mod_pubsub_odbc
- some minor optimizations
- some minor bugfixes
This commit is contained in:
Christophe Romain 2015-04-08 17:12:05 +02:00
parent 63926efd20
commit e0563e3918
31 changed files with 6999 additions and 15289 deletions

View File

@ -27,8 +27,7 @@
%% ------------------------------- %% -------------------------------
%% Pubsub constants %% Pubsub constants
-define(ERR_EXTENDED(E, C), -define(ERR_EXTENDED(E, C), mod_pubsub:extended_error(E, C)).
mod_pubsub:extended_error(E, C)).
%% The actual limit can be configured with mod_pubsub's option max_items_node %% The actual limit can be configured with mod_pubsub's option max_items_node
-define(MAXITEMS, 10). -define(MAXITEMS, 10).
@ -40,7 +39,6 @@
%% ------------------------------- %% -------------------------------
%% Pubsub types %% Pubsub types
%% @type hostPubsub() = string().
-type(hostPubsub() :: binary()). -type(hostPubsub() :: binary()).
%% <p><tt>hostPubsub</tt> is the name of the PubSub service. For example, it can be %% <p><tt>hostPubsub</tt> is the name of the PubSub service. For example, it can be
%% <tt>"pubsub.localhost"</tt>.</p> %% <tt>"pubsub.localhost"</tt>.</p>
@ -60,11 +58,14 @@
%% @type nodeId() = binary(). %% @type nodeId() = binary().
%% <p>A node is defined by a list of its ancestors. The last element is the name %% <p>A node is defined by a list of its ancestors. The last element is the name
%% of the current node. For example: %% of the current node. For example:
%% of the current node. For example:
%% ```<<"/home/localhost/user">>'''</p> %% ```<<"/home/localhost/user">>'''</p>
-type(nodeIdx() :: pos_integer()). -type(nodeIdx() :: pos_integer() | binary()).
%% @type nodeIdx() = integer(). %% @type nodeIdx() = integer() | binary().
%% note: pos_integer() should always be used, but we allow anything else coded
%% as binary, so one can have a custom implementation of nodetree with custom
%% indexing (see nodetree_virtual). this also allows to use any kind of key for
%% indexing nodes, as this can be usefull with external backends such as odbc.
-type(itemId() :: binary()). -type(itemId() :: binary()).
%% @type itemId() = string(). %% @type itemId() = string().
@ -72,28 +73,12 @@
-type(subId() :: binary()). -type(subId() :: binary()).
%% @type subId() = string(). %% @type subId() = string().
%% @type payload() = [#xmlelement{} | #xmlcdata{}].
%% @type stanzaError() = #xmlelement{}.
%% Example:
%% Example:
%% ```{xmlelement, "error",
%% [{"code", Code}, {"type", Type}],
%% [{xmlelement, Condition, [{"xmlns", ?NS_STANZAS}], []}]}'''
%% @type pubsubIQResponse() = #xmlelement{}.
%% Example:
%% ```{xmlelement, "pubsub",
%% [{"xmlns", ?NS_PUBSUB_EVENT}],
%% [{xmlelement, "affiliations", [],
%% []}]}'''
-type(nodeOption() :: -type(nodeOption() ::
{Option::atom(), {Option::atom(),
Value::binary() | [binary()] | boolean() | non_neg_integer() Value::atom() | [binary()] | boolean() | non_neg_integer()
}). }).
-type(nodeOptions() :: [NodeOption::mod_pubsub:nodeOption(),...]). -type(nodeOptions() :: [mod_pubsub:nodeOption(),...]).
%% @type nodeOption() = {Option, Value} %% @type nodeOption() = {Option, Value}
%% Option = atom() %% Option = atom()
@ -106,26 +91,9 @@
Value::binary() | [binary()] | boolean() Value::binary() | [binary()] | boolean()
}). }).
-type(subOptions() :: [SubOption::mod_pubsub:subOption(),...]). -type(subOptions() :: [mod_pubsub:subOption(),...]).
%% @type nodeType() = string().
%% <p>The <tt>nodeType</tt> is a string containing the name of the PubSub
%% plugin to use to manage a given node. For example, it can be
%% <tt>"flat"</tt>, <tt>"hometree"</tt> or <tt>"blog"</tt>.</p>
%% @type jid() = {jid, User, Server, Resource, LUser, LServer, LResource}
%% User = string()
%% Server = string()
%% Resource = string()
%% LUser = string()
%% LServer = string()
%% LResource = string().
%-type(ljid() :: {binary(), binary(), binary()}).
%% @type ljid() = {User, Server, Resource}
%% User = string()
%% Server = string()
%% Resource = string().
-type(affiliation() :: 'none' -type(affiliation() :: 'none'
| 'owner' | 'owner'
@ -151,16 +119,11 @@
). ).
%% @type accessModel() = 'open' | 'presence' | 'roster' | 'authorize' | 'whitelist'. %% @type accessModel() = 'open' | 'presence' | 'roster' | 'authorize' | 'whitelist'.
%% @type pubsubIndex() = {pubsub_index, Index, Last, Free}
%% Index = atom()
%% Last = integer()
%% Free = [integer()].
%% internal pubsub index table
-type(publishModel() :: 'publishers' -type(publishModel() :: 'publishers'
| 'subscribers' | 'subscribers'
| 'open' | 'open'
). ).
%% @type publishModel() = 'publishers' | 'subscribers' | 'open'
-record(pubsub_index, -record(pubsub_index,
{ {
@ -169,91 +132,42 @@
free :: [mod_pubsub:nodeIdx()] free :: [mod_pubsub:nodeIdx()]
}). }).
%% @type pubsubNode() = {pubsub_node, NodeId, Id, Parents, Type, Owners, Options}
%% NodeId = {host() | ljid(), nodeId()}
%% Id = nodeIdx()
%% Parents = [nodeId()]
%% Type = nodeType()
%% Owners = [ljid()]
%% Options = [nodeOption()].
%% <p>This is the format of the <tt>nodes</tt> table. The type of the table
%% is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
%% <p>The <tt>Parents</tt> and <tt>type</tt> fields are indexed.</p>
%% <tt>id</tt> can be anything you want.
-record(pubsub_node, -record(pubsub_node,
{ {
nodeid ,%:: {Host::mod_pubsub:host(), NodeId::mod_pubsub:nodeId()}, nodeid ,% :: {mod_pubsub:host(), mod_pubsub:nodeId()},
id ,% :: mod_pubsub:nodeIdx(), id ,% :: mod_pubsub:nodeIdx(),
parents = [] ,%:: [Parent_NodeId::mod_pubsub:nodeId()], parents = [] ,% :: [mod_pubsub:nodeId(),...],
type = <<"flat">>,% :: binary(), type = <<"flat">>,% :: binary(),
owners = [] ,%:: [Owner::ljid(),...], owners = [] ,% :: [jlib:ljid(),...],
options = [] % :: mod_pubsub:nodeOptions() options = [] % :: mod_pubsub:nodeOptions()
}). }).
%% @type pubsubState() = {pubsub_state, StateId, Items, Affiliation, Subscriptions}
%% StateId = {ljid(), nodeIdx()}
%% Items = [itemId()]
%% Affiliation = affiliation()
%% Subscriptions = [{subscription(), subId()}].
%% <p>This is the format of the <tt>affiliations</tt> table. The type of the
%% table is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
%-record(pubsub_state,
% {stateid, items = [], affiliation = none,
% subscriptions = []}).
-record(pubsub_state, -record(pubsub_state,
{ {
stateid ,%:: {Entity::ljid(), NodeIdx::mod_pubsub:nodeIdx()}, stateid ,% :: {jlib:ljid(), mod_pubsub:nodeIdx()},
items = [] ,%:: [ItemId::mod_pubsub:itemId()], items = [] ,% :: [mod_pubsub:itemId(),...],
affiliation = 'none',% :: mod_pubsub:affiliation(), affiliation = 'none',% :: mod_pubsub:affiliation(),
subscriptions = [] % :: [{mod_pubsub:subscription(), mod_pubsub:subId()}] subscriptions = [] % :: [{mod_pubsub:subscription(), mod_pubsub:subId()}]
}). }).
%% @type pubsubItem() = {pubsub_item, ItemId, Creation, Modification, Payload}
%% ItemId = {itemId(), nodeIdx()}
%% Creation = {now(), ljid()}
%% Modification = {now(), ljid()}
%% Payload = payload().
%% <p>This is the format of the <tt>published items</tt> table. The type of the
%% table is: <tt>set</tt>,<tt>disc</tt>,<tt>fragmented</tt>.</p>
%-record(pubsub_item,
% {itemid, creation = {unknown, unknown},
% modification = {unknown, unknown}, payload = []}).
-record(pubsub_item, -record(pubsub_item,
{ {
itemid ,% :: {mod_pubsub:itemId(), mod_pubsub:nodeIdx()}, itemid ,% :: {mod_pubsub:itemId(), mod_pubsub:nodeIdx()},
creation = {unknown, unknown} ,%:: {erlang:timestamp(), ljid()}, creation = {unknown, unknown},% :: {erlang:timestamp(), jlib:ljid()},
modification = {unknown, unknown} ,%:: {erlang:timestamp(), ljid()}, modification = {unknown, unknown},% :: {erlang:timestamp(), jlib:ljid()},
payload = [] % :: mod_pubsub:payload() payload = [] % :: mod_pubsub:payload()
}). }).
%% @type pubsubSubscription() = {pubsub_subscription, SubId, Options}
%% SubId = subId()
%% Options = [nodeOption()].
%% <p>This is the format of the <tt>subscriptions</tt> table. The type of the
%% table is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
%-record(pubsub_subscription, {subid, options}).
-record(pubsub_subscription, -record(pubsub_subscription,
{ {
subid ,% :: mod_pubsub:subId(), subid ,% :: mod_pubsub:subId(),
options %:: [] | mod_pubsub:subOptions() options = [] % :: mod_pubsub:subOptions()
}). }).
%% @type pubsubLastItem() = {pubsub_last_item, NodeId, ItemId, Creation, Payload}
%% NodeId = nodeIdx()
%% ItemId = itemId()
%% Creation = {now(),ljid()}
%% Payload = payload().
%% <p>This is the format of the <tt>last items</tt> table. it stores last item payload
%% for every node</p>
%-record(pubsub_last_item,
% {nodeid, itemid, creation, payload}).
-record(pubsub_last_item, -record(pubsub_last_item,
{ {
nodeid ,% :: mod_pubsub:nodeIdx(), nodeid ,% :: mod_pubsub:nodeIdx(),
itemid ,% :: mod_pubsub:itemId(), itemid ,% :: mod_pubsub:itemId(),
creation ,%:: {erlang:timestamp(), ljid()}, creation ,% :: {erlang:timestamp(), jlib:ljid()},
payload % :: mod_pubsub:payload() payload % :: mod_pubsub:payload()
}). }).

View File

@ -32,65 +32,20 @@
-include("jlib.hrl"). -include("jlib.hrl").
-type(host() :: mod_pubsub:host() -type(host() :: mod_pubsub:host()).
| mod_pubsub_odbc:host() -type(nodeId() :: mod_pubsub:nodeId()).
). -type(nodeIdx() :: mod_pubsub:nodeIdx()).
-type(itemId() :: mod_pubsub:itemId()).
-type(nodeId() :: mod_pubsub:nodeId() -type(pubsubNode() :: mod_pubsub:pubsubNode()).
| mod_pubsub_odbc:nodeId() -type(pubsubState() :: mod_pubsub:pubsubState()).
). -type(pubsubItem() :: mod_pubsub:pubsubItem()).
-type(subOptions() :: mod_pubsub:subOptions()).
-type(nodeIdx() :: mod_pubsub:nodeIdx() -type(affiliation() :: mod_pubsub:affiliation()).
| mod_pubsub_odbc:nodeIdx() -type(subscription() :: mod_pubsub:subscription()).
). -type(subId() :: mod_pubsub:subId()).
-type(accessModel() :: mod_pubsub:accessModel()).
-type(itemId() :: mod_pubsub:itemId() -type(publishModel() :: mod_pubsub:publishModel()).
| mod_pubsub_odbc:itemId() -type(payload() :: mod_pubsub:payload()).
).
-type(pubsubNode() :: mod_pubsub:pubsubNode()
| mod_pubsub_odbc:pubsubNode()
).
-type(pubsubState() :: mod_pubsub:pubsubState()
| mod_pubsub_odbc:pubsubState()
).
-type(pubsubItem() :: mod_pubsub:pubsubItem()
| mod_pubsub_odbc:pubsubItem()
).
-type(nodeOptions() :: mod_pubsub:nodeOptions()
| mod_pubsub_odbc:nodeOptions()
).
-type(subOptions() :: mod_pubsub:subOptions()
| mod_pubsub_odbc:subOptions()
).
-type(affiliation() :: mod_pubsub:affiliation()
| mod_pubsub_odbc:affiliation()
).
-type(subscription() :: mod_pubsub:subscription()
| mod_pubsub_odbc:subscription()
).
-type(subId() :: mod_pubsub:subId()
| mod_pubsub_odbc:subId()
).
-type(accessModel() :: mod_pubsub:accessModel()
| mod_pubsub_odbc:accessModel()
).
-type(publishModel() :: mod_pubsub:publishModel()
| mod_pubsub_odbc:publishModel()
).
-type(payload() :: mod_pubsub:payload()
| mod_pubsub_odbc:payload()
).
-callback init(Host :: binary(), -callback init(Host :: binary(),
ServerHost :: binary(), ServerHost :: binary(),
@ -136,7 +91,7 @@
-callback subscribe_node(NodeIdx :: nodeIdx(), -callback subscribe_node(NodeIdx :: nodeIdx(),
Sender :: jid(), Sender :: jid(),
Subscriber :: ljid(), Subscriber :: jid(),
AccessModel :: accessModel(), AccessModel :: accessModel(),
SendLast :: 'never' | 'on_sub' | 'on_sub_and_presence', SendLast :: 'never' | 'on_sub' | 'on_sub_and_presence',
PresenceSubscription :: boolean(), PresenceSubscription :: boolean(),
@ -149,7 +104,7 @@
-callback unsubscribe_node(NodeIdx :: nodeIdx(), -callback unsubscribe_node(NodeIdx :: nodeIdx(),
Sender :: jid(), Sender :: jid(),
Subscriber :: ljid(), Subscriber :: jid(),
SubId :: subId()) -> SubId :: subId()) ->
{result, default} | {result, default} |
{error, xmlel()}. {error, xmlel()}.
@ -188,7 +143,7 @@
{result, affiliation()}. {result, affiliation()}.
-callback set_affiliation(NodeIdx :: nodeIdx(), -callback set_affiliation(NodeIdx :: nodeIdx(),
Owner :: ljid(), Owner :: jid(),
Affiliation :: affiliation()) -> Affiliation :: affiliation()) ->
ok | ok |
{error, xmlel()}. {error, xmlel()}.
@ -200,12 +155,12 @@
}. }.
-callback get_entity_subscriptions(Host :: host(), -callback get_entity_subscriptions(Host :: host(),
Owner :: jid()) -> Key :: jid()) ->
{result, [{pubsubNode(), subscription(), subId(), ljid()}] {result, [{pubsubNode(), subscription(), subId(), ljid()}]
}. }.
-callback get_subscriptions(NodeIdx :: nodeIdx(), -callback get_subscriptions(NodeIdx :: nodeIdx(),
Owner :: ljid()) -> Owner :: jid()) ->
{result, [{subscription(), subId()}]}. {result, [{subscription(), subId()}]}.
-callback get_pending_nodes(Host :: host(), -callback get_pending_nodes(Host :: host(),
@ -216,7 +171,7 @@
{result, [pubsubState()]}. {result, [pubsubState()]}.
-callback get_state(NodeIdx :: nodeIdx(), -callback get_state(NodeIdx :: nodeIdx(),
JID :: ljid()) -> Key :: ljid()) ->
pubsubState(). pubsubState().
-callback set_state(State::pubsubState()) -> -callback set_state(State::pubsubState()) ->
@ -228,13 +183,15 @@
AccessModel :: accessModel(), AccessModel :: accessModel(),
Presence_Subscription :: boolean(), Presence_Subscription :: boolean(),
RosterGroup :: boolean(), RosterGroup :: boolean(),
SubId :: subId()) -> SubId :: subId(),
{result, [pubsubItem()]} | RSM :: none | rsm_in()) ->
{result, {[pubsubItem()], none | rsm_out()}} |
{error, xmlel()}. {error, xmlel()}.
-callback get_items(NodeIdx :: nodeIdx(), -callback get_items(NodeIdx :: nodeIdx(),
From :: jid()) -> From :: jid(),
{result, [pubsubItem()]}. RSM :: none | rsm_in()) ->
{result, {[pubsubItem()], none | rsm_out()}}.
-callback get_item(NodeIdx :: nodeIdx(), -callback get_item(NodeIdx :: nodeIdx(),
ItemId :: itemId(), ItemId :: itemId(),

View File

@ -32,29 +32,11 @@
-include("jlib.hrl"). -include("jlib.hrl").
-type(host() :: mod_pubsub:host() -type(host() :: mod_pubsub:host()).
| mod_pubsub_odbc:host() -type(nodeId() :: mod_pubsub:nodeId()).
). -type(nodeIdx() :: mod_pubsub:nodeIdx()).
-type(pubsubNode() :: mod_pubsub:pubsubNode()).
-type(nodeId() :: mod_pubsub:nodeId() -type(nodeOptions() :: mod_pubsub:nodeOptions()).
| mod_pubsub_odbc:nodeId()
).
-type(nodeIdx() :: mod_pubsub:nodeIdx()
| mod_pubsub_odbc:nodeIdx()
).
-type(itemId() :: mod_pubsub:itemId()
| mod_pubsub_odbc:itemId()
).
-type(pubsubNode() :: mod_pubsub:pubsubNode()
| mod_pubsub_odbc:pubsubNode()
).
-type(nodeOptions() :: mod_pubsub:nodeOptions()
| mod_pubsub_odbc:nodeOptions()
).
-callback init(Host :: host(), -callback init(Host :: host(),
ServerHost :: binary(), ServerHost :: binary(),
@ -65,7 +47,7 @@
-callback options() -> nodeOptions(). -callback options() -> nodeOptions().
-callback set_node(PubsubNode :: pubsubNode()) -> -callback set_node(PubsubNode :: pubsubNode()) ->
ok | {result, NodeIdx::mod_pubsub_odbc:nodeIdx()} | {error, xmlel()}. ok | {result, NodeIdx::nodeIdx()} | {error, xmlel()}.
-callback get_node(Host :: host(), -callback get_node(Host :: host(),
NodeId :: nodeId(), NodeId :: nodeId(),
@ -102,12 +84,12 @@
-callback get_subnodes(Host :: host(), -callback get_subnodes(Host :: host(),
NodeId :: nodeId(), NodeId :: nodeId(),
From :: ljid()) -> From :: jid()) ->
[pubsubNode()]. [pubsubNode()].
-callback get_subnodes_tree(Host :: host(), -callback get_subnodes_tree(Host :: host(),
NodeId :: nodeId(), NodeId :: nodeId(),
From :: ljid()) -> From :: jid()) ->
[pubsubNode()]. [pubsubNode()].
-callback create_node(Host :: host(), -callback create_node(Host :: host(),
@ -117,7 +99,8 @@
Options :: nodeOptions(), Options :: nodeOptions(),
Parents :: [nodeId()]) -> Parents :: [nodeId()]) ->
{ok, NodeIdx::nodeIdx()} | {ok, NodeIdx::nodeIdx()} |
{error, xmlel()}. {error, xmlel()} |
{error, {virtual, {host(), nodeId()}}}.
-callback delete_node(Host :: host(), -callback delete_node(Host :: host(),
NodeId :: nodeId()) -> NodeId :: nodeId()) ->

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,194 +0,0 @@
%%% ====================================================================
%%% ``The contents of this file are subject to the Erlang Public License,
%%% Version 1.1, (the "License"); you may not use this file except in
%%% compliance with the License. You should have received a copy of the
%%% Erlang Public License along with this software. If not, it can be
%%% retrieved via the world wide web at http://www.erlang.org/.
%%%
%%% Software distributed under the License is distributed on an "AS IS"
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%%% the License for the specific language governing rights and limitations
%%% under the License.
%%%
%%% The Initial Developer of the Original Code is ProcessOne.
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
%%% All Rights Reserved.''
%%% This software is copyright 2006-2015, ProcessOne.
%%%
%%% @copyright 2006-2015 ProcessOne
%%% @author Christophe romain <christophe.romain@process-one.net>
%%% [http://www.process-one.net/]
%%% @version {@vsn}, {@date} {@time}
%%% @end
%%% ====================================================================
-module(__TO_BE_DEFINED__).
-author(__TO_BE_DEFINED__).
-include("pubsub.hrl").
-include("jlib.hrl").
-behaviour(gen_pubsub_node).
%% Note on function definition
%% included is all defined plugin function
%% it's possible not to define some function at all
%% in that case, warning will be generated at compilation
%% and function call will fail,
%% then mod_pubsub will call function from node_hometree
%% (this makes code cleaner, but execution a little bit longer)
%% API definition
-export([init/3, terminate/2,
options/0, features/0,
create_node_permission/6,
create_node/2,
delete_node/1,
purge_node/2,
subscribe_node/8,
unsubscribe_node/4,
publish_item/6,
delete_item/4,
remove_extra_items/3,
get_entity_affiliations/2,
get_node_affiliations/1,
get_affiliation/2,
set_affiliation/3,
get_entity_subscriptions/2,
get_node_subscriptions/1,
get_subscriptions/2,
set_subscriptions/4,
get_pending_nodes/2,
get_states/1,
get_state/2,
set_state/1,
get_items/6,
get_items/2,
get_item/7,
get_item/2,
set_item/1,
get_item_name/3
]).
init(Host, ServerHost, Opts) ->
node_hometree:init(Host, ServerHost, Opts).
terminate(Host, ServerHost) ->
node_hometree:terminate(Host, ServerHost).
options() ->
[{deliver_payloads, true},
{notify_config, false},
{notify_delete, false},
{notify_retract, true},
{purge_offline, false},
{persist_items, true},
{max_items, ?MAXITEMS},
{subscribe, true},
{access_model, open},
{roster_groups_allowed, []},
{publish_model, publishers},
{notification_type, headline},
{max_payload_size, ?MAX_PAYLOAD_SIZE},
{send_last_published_item, on_sub_and_presence},
{deliver_notifications, true},
{presence_based_delivery, false}].
features() ->
["create-nodes",
"delete-nodes",
"delete-items",
"instant-nodes",
"outcast-affiliation",
"persistent-items",
"publish",
"purge-nodes",
"retract-items",
"retrieve-affiliations",
"retrieve-items",
"retrieve-subscriptions",
"subscribe",
"subscription-notifications"
].
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
create_node(NodeId, Owner) ->
node_hometree:create_node(NodeId, Owner).
delete_node(Removed) ->
node_hometree:delete_node(Removed).
subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options) ->
node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options).
unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
node_hometree:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
remove_extra_items(NodeId, MaxItems, ItemIds) ->
node_hometree:remove_extra_items(NodeId, MaxItems, ItemIds).
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
node_hometree:delete_item(NodeId, Publisher, PublishModel, ItemId).
purge_node(NodeId, Owner) ->
node_hometree:purge_node(NodeId, Owner).
get_entity_affiliations(Host, Owner) ->
node_hometree:get_entity_affiliations(Host, Owner).
get_node_affiliations(NodeId) ->
node_hometree:get_node_affiliations(NodeId).
get_affiliation(NodeId, Owner) ->
node_hometree:get_affiliation(NodeId, Owner).
set_affiliation(NodeId, Owner, Affiliation) ->
node_hometree:set_affiliation(NodeId, Owner, Affiliation).
get_entity_subscriptions(Host, Owner) ->
node_hometree:get_entity_subscriptions(Host, Owner).
get_node_subscriptions(NodeId) ->
node_hometree:get_node_subscriptions(NodeId).
get_subscriptions(NodeId, Owner) ->
node_hometree:get_subscriptions(NodeId, Owner).
set_subscriptions(NodeId, Owner, Subscription, SubId) ->
node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId).
get_pending_nodes(Host, Owner) ->
node_hometree:get_pending_nodes(Host, Owner).
get_states(NodeId) ->
node_hometree:get_states(NodeId).
get_state(NodeId, JID) ->
node_hometree:get_state(NodeId, JID).
set_state(State) ->
node_hometree:set_state(State).
get_items(NodeId, From) ->
node_hometree:get_items(NodeId, From).
get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
get_item(NodeId, ItemId) ->
node_hometree:get_item(NodeId, ItemId).
get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
set_item(Item) ->
node_hometree:set_item(Item).
get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id).

View File

@ -17,33 +17,20 @@
%%% All Rights Reserved.'' %%% All Rights Reserved.''
%%% This software is copyright 2006-2015, ProcessOne. %%% This software is copyright 2006-2015, ProcessOne.
%%% %%%
%%%
%%% @copyright 2006-2015 ProcessOne %%% @copyright 2006-2015 ProcessOne
%%% @author Christophe romain <christophe.romain@process-one.net> %%% @author Christophe Romain <christophe.romain@process-one.net>
%%% [http://www.process-one.net/] %%% [http://www.process-one.net/]
%%% @version {@vsn}, {@date} {@time} %%% @version {@vsn}, {@date} {@time}
%%% @end %%% @end
%%% ==================================================================== %%% ====================================================================
-module(node_buddy). -module(node_buddy).
-behaviour(gen_pubsub_node).
-author('christophe.romain@process-one.net'). -author('christophe.romain@process-one.net').
-include("pubsub.hrl"). -include("pubsub.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
-behaviour(gen_pubsub_node).
%% Note on function definition
%% included is all defined plugin function
%% it's possible not to define some function at all
%% in that case, warning will be generated at compilation
%% and function call will fail,
%% then mod_pubsub will call function from node_hometree
%% (this makes code cleaner, but execution a little bit longer)
%% API definition
-export([init/3, terminate/2, options/0, features/0, -export([init/3, terminate/2, options/0, features/0,
create_node_permission/6, create_node/2, delete_node/1, create_node_permission/6, create_node/2, delete_node/1,
purge_node/2, subscribe_node/8, unsubscribe_node/4, purge_node/2, subscribe_node/8, unsubscribe_node/4,
@ -53,7 +40,7 @@
get_entity_subscriptions/2, get_node_subscriptions/1, get_entity_subscriptions/2, get_node_subscriptions/1,
get_subscriptions/2, set_subscriptions/4, get_subscriptions/2, set_subscriptions/4,
get_pending_nodes/2, get_states/1, get_state/2, get_pending_nodes/2, get_states/1, get_state/2,
set_state/1, get_items/6, get_items/2, get_item/7, set_state/1, get_items/7, get_items/3, get_item/7,
get_item/2, set_item/1, get_item_name/3, node_to_path/1, get_item/2, set_item/1, get_item_name/3, node_to_path/1,
path_to_node/1]). path_to_node/1]).
@ -64,11 +51,16 @@ terminate(Host, ServerHost) ->
node_hometree:terminate(Host, ServerHost). node_hometree:terminate(Host, ServerHost).
options() -> options() ->
[{deliver_payloads, true}, {notify_config, false}, [{deliver_payloads, true},
{notify_delete, false}, {notify_retract, true}, {notify_config, false},
{purge_offline, false}, {persist_items, true}, {notify_delete, false},
{max_items, ?MAXITEMS}, {subscribe, true}, {notify_retract, true},
{access_model, presence}, {roster_groups_allowed, []}, {purge_offline, false},
{persist_items, true},
{max_items, ?MAXITEMS},
{subscribe, true},
{access_model, presence},
{roster_groups_allowed, []},
{publish_model, publishers}, {publish_model, publishers},
{notification_type, headline}, {notification_type, headline},
{max_payload_size, ?MAX_PAYLOAD_SIZE}, {max_payload_size, ?MAX_PAYLOAD_SIZE},
@ -77,108 +69,109 @@ options() ->
{presence_based_delivery, false}]. {presence_based_delivery, false}].
features() -> features() ->
[<<"create-nodes">>, <<"delete-nodes">>, [<<"create-nodes">>,
<<"delete-items">>, <<"instant-nodes">>, <<"item-ids">>, <<"delete-nodes">>,
<<"outcast-affiliation">>, <<"persistent-items">>, <<"delete-items">>,
<<"publish">>, <<"purge-nodes">>, <<"retract-items">>, <<"instant-nodes">>,
<<"retrieve-affiliations">>, <<"retrieve-items">>, <<"item-ids">>,
<<"retrieve-subscriptions">>, <<"subscribe">>, <<"outcast-affiliation">>,
<<"persistent-items">>,
<<"publish">>,
<<"purge-nodes">>,
<<"retract-items">>,
<<"retrieve-affiliations">>,
<<"retrieve-items">>,
<<"retrieve-subscriptions">>,
<<"subscribe">>,
<<"subscription-notifications">>]. <<"subscription-notifications">>].
create_node_permission(Host, ServerHost, Node, create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
ParentNode, Owner, Access) -> node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
node_hometree:create_node_permission(Host, ServerHost,
Node, ParentNode, Owner, Access).
create_node(NodeId, Owner) -> create_node(Nidx, Owner) ->
node_hometree:create_node(NodeId, Owner). node_hometree:create_node(Nidx, Owner).
delete_node(Removed) -> delete_node(Removed) ->
node_hometree:delete_node(Removed). node_hometree:delete_node(Removed).
subscribe_node(NodeId, Sender, Subscriber, AccessModel, subscribe_node(Nidx, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup, Options) -> SendLast, PresenceSubscription, RosterGroup, Options) ->
node_hometree:subscribe_node(NodeId, Sender, Subscriber, node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
AccessModel, SendLast, PresenceSubscription, PresenceSubscription, RosterGroup, Options).
RosterGroup, Options).
unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
node_hometree:unsubscribe_node(NodeId, Sender, node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
Subscriber, SubID).
publish_item(NodeId, Publisher, Model, MaxItems, ItemId, publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
Payload) -> node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
node_hometree:publish_item(NodeId, Publisher, Model,
MaxItems, ItemId, Payload).
remove_extra_items(NodeId, MaxItems, ItemIds) -> remove_extra_items(Nidx, MaxItems, ItemIds) ->
node_hometree:remove_extra_items(NodeId, MaxItems, node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
ItemIds).
delete_item(NodeId, Publisher, PublishModel, ItemId) -> delete_item(Nidx, Publisher, PublishModel, ItemId) ->
node_hometree:delete_item(NodeId, Publisher, node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
PublishModel, ItemId).
purge_node(NodeId, Owner) -> purge_node(Nidx, Owner) ->
node_hometree:purge_node(NodeId, Owner). node_hometree:purge_node(Nidx, Owner).
get_entity_affiliations(Host, Owner) -> get_entity_affiliations(Host, Owner) ->
node_hometree:get_entity_affiliations(Host, Owner). node_hometree:get_entity_affiliations(Host, Owner).
get_node_affiliations(NodeId) -> get_node_affiliations(Nidx) ->
node_hometree:get_node_affiliations(NodeId). node_hometree:get_node_affiliations(Nidx).
get_affiliation(NodeId, Owner) -> get_affiliation(Nidx, Owner) ->
node_hometree:get_affiliation(NodeId, Owner). node_hometree:get_affiliation(Nidx, Owner).
set_affiliation(NodeId, Owner, Affiliation) -> set_affiliation(Nidx, Owner, Affiliation) ->
node_hometree:set_affiliation(NodeId, Owner, node_hometree:set_affiliation(Nidx, Owner, Affiliation).
Affiliation).
get_entity_subscriptions(Host, Owner) -> get_entity_subscriptions(Host, Owner) ->
node_hometree:get_entity_subscriptions(Host, Owner). node_hometree:get_entity_subscriptions(Host, Owner).
get_node_subscriptions(NodeId) -> get_node_subscriptions(Nidx) ->
node_hometree:get_node_subscriptions(NodeId). node_hometree:get_node_subscriptions(Nidx).
get_subscriptions(NodeId, Owner) -> get_subscriptions(Nidx, Owner) ->
node_hometree:get_subscriptions(NodeId, Owner). node_hometree:get_subscriptions(Nidx, Owner).
set_subscriptions(NodeId, Owner, Subscription, SubId) -> set_subscriptions(Nidx, Owner, Subscription, SubId) ->
node_hometree:set_subscriptions(NodeId, Owner, node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
Subscription, SubId).
get_pending_nodes(Host, Owner) -> get_pending_nodes(Host, Owner) ->
node_hometree:get_pending_nodes(Host, Owner). node_hometree:get_pending_nodes(Host, Owner).
get_states(NodeId) -> node_hometree:get_states(NodeId). get_states(Nidx) ->
node_hometree:get_states(Nidx).
get_state(NodeId, JID) -> get_state(Nidx, JID) ->
node_hometree:get_state(NodeId, JID). node_hometree:get_state(Nidx, JID).
set_state(State) -> node_hometree:set_state(State). set_state(State) ->
node_hometree:set_state(State).
get_items(NodeId, From) -> get_items(Nidx, From, RSM) ->
node_hometree:get_items(NodeId, From). node_hometree:get_items(Nidx, From, RSM).
get_items(NodeId, JID, AccessModel, get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
PresenceSubscription, RosterGroup, SubId) -> node_hometree:get_items(Nidx, JID, AccessModel,
node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM).
get_item(Nidx, ItemId) ->
node_hometree:get_item(Nidx, ItemId).
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId). PresenceSubscription, RosterGroup, SubId).
get_item(NodeId, ItemId) -> set_item(Item) ->
node_hometree:get_item(NodeId, ItemId). node_hometree:set_item(Item).
get_item(NodeId, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId).
set_item(Item) -> node_hometree:set_item(Item).
get_item_name(Host, Node, Id) -> get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id). node_hometree:get_item_name(Host, Node, Id).
node_to_path(Node) -> node_flat:node_to_path(Node). node_to_path(Node) ->
node_flat:node_to_path(Node).
path_to_node(Path) -> node_flat:path_to_node(Path). path_to_node(Path) ->
node_flat:path_to_node(Path).

View File

@ -1,4 +1,4 @@
%%% ==================================================================== %% ====================================================================
%%% ``The contents of this file are subject to the Erlang Public License, %%% ``The contents of this file are subject to the Erlang Public License,
%%% Version 1.1, (the "License"); you may not use this file except in %%% Version 1.1, (the "License"); you may not use this file except in
%%% compliance with the License. You should have received a copy of the %%% compliance with the License. You should have received a copy of the
@ -17,33 +17,20 @@
%%% All Rights Reserved.'' %%% All Rights Reserved.''
%%% This software is copyright 2006-2015, ProcessOne. %%% This software is copyright 2006-2015, ProcessOne.
%%% %%%
%%%
%%% @copyright 2006-2015 ProcessOne %%% @copyright 2006-2015 ProcessOne
%%% @author Christophe romain <christophe.romain@process-one.net> %%% @author Christophe Romain <christophe.romain@process-one.net>
%%% [http://www.process-one.net/] %%% [http://www.process-one.net/]
%%% @version {@vsn}, {@date} {@time} %%% @version {@vsn}, {@date} {@time}
%%% @end %%% @end
%%% ==================================================================== %%% ====================================================================
-module(node_club). -module(node_club).
-behaviour(gen_pubsub_node).
-author('christophe.romain@process-one.net'). -author('christophe.romain@process-one.net').
-include("pubsub.hrl"). -include("pubsub.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
-behaviour(gen_pubsub_node).
%% Note on function definition
%% included is all defined plugin function
%% it's possible not to define some function at all
%% in that case, warning will be generated at compilation
%% and function call will fail,
%% then mod_pubsub will call function from node_hometree
%% (this makes code cleaner, but execution a little bit longer)
%% API definition
-export([init/3, terminate/2, options/0, features/0, -export([init/3, terminate/2, options/0, features/0,
create_node_permission/6, create_node/2, delete_node/1, create_node_permission/6, create_node/2, delete_node/1,
purge_node/2, subscribe_node/8, unsubscribe_node/4, purge_node/2, subscribe_node/8, unsubscribe_node/4,
@ -53,7 +40,7 @@
get_entity_subscriptions/2, get_node_subscriptions/1, get_entity_subscriptions/2, get_node_subscriptions/1,
get_subscriptions/2, set_subscriptions/4, get_subscriptions/2, set_subscriptions/4,
get_pending_nodes/2, get_states/1, get_state/2, get_pending_nodes/2, get_states/1, get_state/2,
set_state/1, get_items/6, get_items/2, get_item/7, set_state/1, get_items/7, get_items/3, get_item/7,
get_item/2, set_item/1, get_item_name/3, node_to_path/1, get_item/2, set_item/1, get_item_name/3, node_to_path/1,
path_to_node/1]). path_to_node/1]).
@ -64,11 +51,16 @@ terminate(Host, ServerHost) ->
node_hometree:terminate(Host, ServerHost). node_hometree:terminate(Host, ServerHost).
options() -> options() ->
[{deliver_payloads, true}, {notify_config, false}, [{deliver_payloads, true},
{notify_delete, false}, {notify_retract, true}, {notify_config, false},
{purge_offline, false}, {persist_items, true}, {notify_delete, false},
{max_items, ?MAXITEMS}, {subscribe, true}, {notify_retract, true},
{access_model, authorize}, {roster_groups_allowed, []}, {purge_offline, false},
{persist_items, true},
{max_items, ?MAXITEMS},
{subscribe, true},
{access_model, authorize},
{roster_groups_allowed, []},
{publish_model, publishers}, {publish_model, publishers},
{notification_type, headline}, {notification_type, headline},
{max_payload_size, ?MAX_PAYLOAD_SIZE}, {max_payload_size, ?MAX_PAYLOAD_SIZE},
@ -77,108 +69,108 @@ options() ->
{presence_based_delivery, false}]. {presence_based_delivery, false}].
features() -> features() ->
[<<"create-nodes">>, <<"delete-nodes">>, [<<"create-nodes">>,
<<"delete-items">>, <<"instant-nodes">>, <<"delete-nodes">>,
<<"outcast-affiliation">>, <<"persistent-items">>, <<"delete-items">>,
<<"publish">>, <<"purge-nodes">>, <<"retract-items">>, <<"instant-nodes">>,
<<"retrieve-affiliations">>, <<"retrieve-items">>, <<"outcast-affiliation">>,
<<"retrieve-subscriptions">>, <<"subscribe">>, <<"persistent-items">>,
<<"publish">>,
<<"purge-nodes">>,
<<"retract-items">>,
<<"retrieve-affiliations">>,
<<"retrieve-items">>,
<<"retrieve-subscriptions">>,
<<"subscribe">>,
<<"subscription-notifications">>]. <<"subscription-notifications">>].
create_node_permission(Host, ServerHost, Node, create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
ParentNode, Owner, Access) -> node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
node_hometree:create_node_permission(Host, ServerHost,
Node, ParentNode, Owner, Access).
create_node(NodeId, Owner) -> create_node(Nidx, Owner) ->
node_hometree:create_node(NodeId, Owner). node_hometree:create_node(Nidx, Owner).
delete_node(Removed) -> delete_node(Removed) ->
node_hometree:delete_node(Removed). node_hometree:delete_node(Removed).
subscribe_node(NodeId, Sender, Subscriber, AccessModel, subscribe_node(Nidx, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup, Options) -> SendLast, PresenceSubscription, RosterGroup, Options) ->
node_hometree:subscribe_node(NodeId, Sender, Subscriber, node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
AccessModel, SendLast, PresenceSubscription, PresenceSubscription, RosterGroup, Options).
RosterGroup, Options).
unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
node_hometree:unsubscribe_node(NodeId, Sender, node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
Subscriber, SubID).
publish_item(NodeId, Publisher, Model, MaxItems, ItemId, publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
Payload) -> node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
node_hometree:publish_item(NodeId, Publisher, Model,
MaxItems, ItemId, Payload).
remove_extra_items(NodeId, MaxItems, ItemIds) -> remove_extra_items(Nidx, MaxItems, ItemIds) ->
node_hometree:remove_extra_items(NodeId, MaxItems, node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
ItemIds).
delete_item(NodeId, Publisher, PublishModel, ItemId) -> delete_item(Nidx, Publisher, PublishModel, ItemId) ->
node_hometree:delete_item(NodeId, Publisher, node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
PublishModel, ItemId).
purge_node(NodeId, Owner) -> purge_node(Nidx, Owner) ->
node_hometree:purge_node(NodeId, Owner). node_hometree:purge_node(Nidx, Owner).
get_entity_affiliations(Host, Owner) -> get_entity_affiliations(Host, Owner) ->
node_hometree:get_entity_affiliations(Host, Owner). node_hometree:get_entity_affiliations(Host, Owner).
get_node_affiliations(NodeId) -> get_node_affiliations(Nidx) ->
node_hometree:get_node_affiliations(NodeId). node_hometree:get_node_affiliations(Nidx).
get_affiliation(NodeId, Owner) -> get_affiliation(Nidx, Owner) ->
node_hometree:get_affiliation(NodeId, Owner). node_hometree:get_affiliation(Nidx, Owner).
set_affiliation(NodeId, Owner, Affiliation) -> set_affiliation(Nidx, Owner, Affiliation) ->
node_hometree:set_affiliation(NodeId, Owner, node_hometree:set_affiliation(Nidx, Owner, Affiliation).
Affiliation).
get_entity_subscriptions(Host, Owner) -> get_entity_subscriptions(Host, Owner) ->
node_hometree:get_entity_subscriptions(Host, Owner). node_hometree:get_entity_subscriptions(Host, Owner).
get_node_subscriptions(NodeId) -> get_node_subscriptions(Nidx) ->
node_hometree:get_node_subscriptions(NodeId). node_hometree:get_node_subscriptions(Nidx).
get_subscriptions(NodeId, Owner) -> get_subscriptions(Nidx, Owner) ->
node_hometree:get_subscriptions(NodeId, Owner). node_hometree:get_subscriptions(Nidx, Owner).
set_subscriptions(NodeId, Owner, Subscription, SubId) -> set_subscriptions(Nidx, Owner, Subscription, SubId) ->
node_hometree:set_subscriptions(NodeId, Owner, node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
Subscription, SubId).
get_pending_nodes(Host, Owner) -> get_pending_nodes(Host, Owner) ->
node_hometree:get_pending_nodes(Host, Owner). node_hometree:get_pending_nodes(Host, Owner).
get_states(NodeId) -> node_hometree:get_states(NodeId). get_states(Nidx) ->
node_hometree:get_states(Nidx).
get_state(NodeId, JID) -> get_state(Nidx, JID) ->
node_hometree:get_state(NodeId, JID). node_hometree:get_state(Nidx, JID).
set_state(State) -> node_hometree:set_state(State). set_state(State) ->
node_hometree:set_state(State).
get_items(NodeId, From) -> get_items(Nidx, From, RSM) ->
node_hometree:get_items(NodeId, From). node_hometree:get_items(Nidx, From, RSM).
get_items(NodeId, JID, AccessModel, get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
PresenceSubscription, RosterGroup, SubId) -> node_hometree:get_items(Nidx, JID, AccessModel,
node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM).
get_item(Nidx, ItemId) ->
node_hometree:get_item(Nidx, ItemId).
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId). PresenceSubscription, RosterGroup, SubId).
get_item(NodeId, ItemId) -> set_item(Item) ->
node_hometree:get_item(NodeId, ItemId). node_hometree:set_item(Item).
get_item(NodeId, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId).
set_item(Item) -> node_hometree:set_item(Item).
get_item_name(Host, Node, Id) -> get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id). node_hometree:get_item_name(Host, Node, Id).
node_to_path(Node) -> node_flat:node_to_path(Node). node_to_path(Node) ->
node_flat:node_to_path(Node).
path_to_node(Path) -> node_flat:path_to_node(Path). path_to_node(Path) ->
node_flat:path_to_node(Path).

View File

@ -5,27 +5,25 @@
%%% Erlang Public License along with this software. If not, it can be %%% Erlang Public License along with this software. If not, it can be
%%% retrieved via the world wide web at http://www.erlang.org/. %%% retrieved via the world wide web at http://www.erlang.org/.
%%% %%%
%%%
%%% Software distributed under the License is distributed on an "AS IS" %%% Software distributed under the License is distributed on an "AS IS"
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%%% the License for the specific language governing rights and limitations %%% the License for the specific language governing rights and limitations
%%% under the License. %%% under the License.
%%% %%%
%%%
%%% @author Brian Cully <bjc@kublai.com> %%% @author Brian Cully <bjc@kublai.com>
%%% @version {@vsn}, {@date} {@time} %%% @version {@vsn}, {@date} {@time}
%%% @end %%% @end
%%% ==================================================================== %%% ====================================================================
-module(node_dag). -module(node_dag).
-behaviour(gen_pubsub_node).
-author('bjc@kublai.com'). -author('bjc@kublai.com').
-include("pubsub.hrl"). -include("pubsub.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
-behaviour(gen_pubsub_node).
%% API definition
-export([init/3, terminate/2, options/0, features/0, -export([init/3, terminate/2, options/0, features/0,
create_node_permission/6, create_node/2, delete_node/1, create_node_permission/6, create_node/2, delete_node/1,
purge_node/2, subscribe_node/8, unsubscribe_node/4, purge_node/2, subscribe_node/8, unsubscribe_node/4,
@ -35,7 +33,7 @@
get_entity_subscriptions/2, get_node_subscriptions/1, get_entity_subscriptions/2, get_node_subscriptions/1,
get_subscriptions/2, set_subscriptions/4, get_subscriptions/2, set_subscriptions/4,
get_pending_nodes/2, get_states/1, get_state/2, get_pending_nodes/2, get_states/1, get_state/2,
set_state/1, get_items/6, get_items/2, get_item/7, set_state/1, get_items/7, get_items/3, get_item/7,
get_item/2, set_item/1, get_item_name/3, node_to_path/1, get_item/2, set_item/1, get_item_name/3, node_to_path/1,
path_to_node/1]). path_to_node/1]).
@ -51,37 +49,33 @@ options() ->
features() -> features() ->
[<<"multi-collection">> | node_hometree:features()]. [<<"multi-collection">> | node_hometree:features()].
create_node_permission(_Host, _ServerHost, _Node, create_node_permission(_Host, _ServerHost, _Node, _ParentNode, _Owner, _Access) ->
_ParentNode, _Owner, _Access) ->
{result, true}. {result, true}.
create_node(NodeID, Owner) -> create_node(Nidx, Owner) ->
node_hometree:create_node(NodeID, Owner). node_hometree:create_node(Nidx, Owner).
delete_node(Removed) -> delete_node(Removed) ->
node_hometree:delete_node(Removed). node_hometree:delete_node(Removed).
subscribe_node(NodeID, Sender, Subscriber, AccessModel, subscribe_node(Nidx, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup, Options) -> SendLast, PresenceSubscription, RosterGroup, Options) ->
node_hometree:subscribe_node(NodeID, Sender, Subscriber, node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
AccessModel, SendLast, PresenceSubscription, PresenceSubscription, RosterGroup, Options).
RosterGroup, Options).
unsubscribe_node(NodeID, Sender, Subscriber, SubID) -> unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
node_hometree:unsubscribe_node(NodeID, Sender, node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
Subscriber, SubID).
publish_item(NodeID, Publisher, Model, MaxItems, ItemID, publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
Payload) -> case nodetree_dag:get_node(Nidx) of
case nodetree_dag:get_node(NodeID) of
#pubsub_node{options = Options} -> #pubsub_node{options = Options} ->
case find_opt(node_type, Options) of case find_opt(node_type, Options) of
collection -> collection ->
{error, {error,
?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"publish">>)}; ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"publish">>)};
_ -> _ ->
node_hometree:publish_item(NodeID, Publisher, Model, node_hometree:publish_item(Nidx, Publisher, Model,
MaxItems, ItemID, Payload) MaxItems, ItemId, Payload)
end; end;
Err -> Err Err -> Err
end. end.
@ -90,74 +84,73 @@ find_opt(_, []) -> false;
find_opt(Option, [{Option, Value} | _]) -> Value; find_opt(Option, [{Option, Value} | _]) -> Value;
find_opt(Option, [_ | T]) -> find_opt(Option, T). find_opt(Option, [_ | T]) -> find_opt(Option, T).
remove_extra_items(NodeID, MaxItems, ItemIDs) -> remove_extra_items(Nidx, MaxItems, ItemIds) ->
node_hometree:remove_extra_items(NodeID, MaxItems, node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
ItemIDs).
delete_item(NodeID, Publisher, PublishModel, ItemID) -> delete_item(Nidx, Publisher, PublishModel, ItemId) ->
node_hometree:delete_item(NodeID, Publisher, node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
PublishModel, ItemID).
purge_node(NodeID, Owner) -> purge_node(Nidx, Owner) ->
node_hometree:purge_node(NodeID, Owner). node_hometree:purge_node(Nidx, Owner).
get_entity_affiliations(Host, Owner) -> get_entity_affiliations(Host, Owner) ->
node_hometree:get_entity_affiliations(Host, Owner). node_hometree:get_entity_affiliations(Host, Owner).
get_node_affiliations(NodeID) -> get_node_affiliations(Nidx) ->
node_hometree:get_node_affiliations(NodeID). node_hometree:get_node_affiliations(Nidx).
get_affiliation(NodeID, Owner) -> get_affiliation(Nidx, Owner) ->
node_hometree:get_affiliation(NodeID, Owner). node_hometree:get_affiliation(Nidx, Owner).
set_affiliation(NodeID, Owner, Affiliation) -> set_affiliation(Nidx, Owner, Affiliation) ->
node_hometree:set_affiliation(NodeID, Owner, node_hometree:set_affiliation(Nidx, Owner, Affiliation).
Affiliation).
get_entity_subscriptions(Host, Owner) -> get_entity_subscriptions(Host, Owner) ->
node_hometree:get_entity_subscriptions(Host, Owner). node_hometree:get_entity_subscriptions(Host, Owner).
get_node_subscriptions(NodeID) -> get_node_subscriptions(Nidx) ->
node_hometree:get_node_subscriptions(NodeID). node_hometree:get_node_subscriptions(Nidx).
get_subscriptions(NodeID, Owner) -> get_subscriptions(Nidx, Owner) ->
node_hometree:get_subscriptions(NodeID, Owner). node_hometree:get_subscriptions(Nidx, Owner).
set_subscriptions(NodeID, Owner, Subscription, SubID) -> set_subscriptions(Nidx, Owner, Subscription, SubId) ->
node_hometree:set_subscriptions(NodeID, Owner, node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
Subscription, SubID).
get_pending_nodes(Host, Owner) -> get_pending_nodes(Host, Owner) ->
node_hometree:get_pending_nodes(Host, Owner). node_hometree:get_pending_nodes(Host, Owner).
get_states(NodeID) -> node_hometree:get_states(NodeID). get_states(Nidx) ->
node_hometree:get_states(Nidx).
get_state(NodeID, JID) -> get_state(Nidx, JID) ->
node_hometree:get_state(NodeID, JID). node_hometree:get_state(Nidx, JID).
set_state(State) -> node_hometree:set_state(State). set_state(State) ->
node_hometree:set_state(State).
get_items(NodeID, From) -> get_items(Nidx, From, RSM) ->
node_hometree:get_items(NodeID, From). node_hometree:get_items(Nidx, From, RSM).
get_items(NodeID, JID, AccessModel, get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
PresenceSubscription, RosterGroup, SubID) -> node_hometree:get_items(Nidx, JID, AccessModel,
node_hometree:get_items(NodeID, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM).
PresenceSubscription, RosterGroup, SubID).
get_item(NodeID, ItemID) -> get_item(Nidx, ItemId) ->
node_hometree:get_item(NodeID, ItemID). node_hometree:get_item(Nidx, ItemId).
get_item(NodeID, ItemID, JID, AccessModel, get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
PresenceSubscription, RosterGroup, SubID) -> node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
node_hometree:get_item(NodeID, ItemID, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
PresenceSubscription, RosterGroup, SubID).
set_item(Item) -> node_hometree:set_item(Item). set_item(Item) ->
node_hometree:set_item(Item).
get_item_name(Host, Node, ID) -> get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, ID). node_hometree:get_item_name(Host, Node, Id).
node_to_path(Node) -> node_hometree:node_to_path(Node). node_to_path(Node) ->
node_hometree:node_to_path(Node).
path_to_node(Path) -> node_hometree:path_to_node(Path). path_to_node(Path) ->
node_hometree:path_to_node(Path).

View File

@ -17,31 +17,26 @@
%%% All Rights Reserved.'' %%% All Rights Reserved.''
%%% This software is copyright 2006-2015, ProcessOne. %%% This software is copyright 2006-2015, ProcessOne.
%%% %%%
%%%
%%% @copyright 2006-2015 ProcessOne %%% @copyright 2006-2015 ProcessOne
%%% @author Christophe romain <christophe.romain@process-one.net> %%% @author Christophe Romain <christophe.romain@process-one.net>
%%% [http://www.process-one.net/] %%% [http://www.process-one.net/]
%%% @version {@vsn}, {@date} {@time} %%% @version {@vsn}, {@date} {@time}
%%% @end %%% @end
%%% ==================================================================== %%% ====================================================================
-module(node_dispatch). -module(node_dispatch).
-behaviour(gen_pubsub_node).
-author('christophe.romain@process-one.net'). -author('christophe.romain@process-one.net').
-include("pubsub.hrl"). -include("pubsub.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
-behaviour(gen_pubsub_node).
%%% @doc <p>The <strong>{@module}</strong> module is a PubSub plugin whose %%% @doc <p>The <strong>{@module}</strong> module is a PubSub plugin whose
%%% goal is to republished each published item to all its children.</p> %%% goal is to republished each published item to all its children.</p>
%%% <p>Users cannot subscribe to this node, but are supposed to subscribe to %%% <p>Users cannot subscribe to this node, but are supposed to subscribe to
%%% its children.</p> %%% its children.</p>
%%% This module can not work with virtual nodetree %%% This module can not work with virtual nodetree
%% API definition
-export([init/3, terminate/2, options/0, features/0, -export([init/3, terminate/2, options/0, features/0,
create_node_permission/6, create_node/2, delete_node/1, create_node_permission/6, create_node/2, delete_node/1,
purge_node/2, subscribe_node/8, unsubscribe_node/4, purge_node/2, subscribe_node/8, unsubscribe_node/4,
@ -51,7 +46,7 @@
get_entity_subscriptions/2, get_node_subscriptions/1, get_entity_subscriptions/2, get_node_subscriptions/1,
get_subscriptions/2, set_subscriptions/4, get_subscriptions/2, set_subscriptions/4,
get_pending_nodes/2, get_states/1, get_state/2, get_pending_nodes/2, get_states/1, get_state/2,
set_state/1, get_items/6, get_items/2, get_item/7, set_state/1, get_items/7, get_items/3, get_item/7,
get_item/2, set_item/1, get_item_name/3, node_to_path/1, get_item/2, set_item/1, get_item_name/3, node_to_path/1,
path_to_node/1]). path_to_node/1]).
@ -62,11 +57,16 @@ terminate(Host, ServerHost) ->
node_hometree:terminate(Host, ServerHost). node_hometree:terminate(Host, ServerHost).
options() -> options() ->
[{deliver_payloads, true}, {notify_config, false}, [{deliver_payloads, true},
{notify_delete, false}, {notify_retract, true}, {notify_config, false},
{purge_offline, false}, {persist_items, true}, {notify_delete, false},
{max_items, ?MAXITEMS}, {subscribe, true}, {notify_retract, true},
{access_model, open}, {roster_groups_allowed, []}, {purge_offline, false},
{persist_items, true},
{max_items, ?MAXITEMS},
{subscribe, true},
{access_model, presence},
{roster_groups_allowed, []},
{publish_model, publishers}, {publish_model, publishers},
{notification_type, headline}, {notification_type, headline},
{max_payload_size, ?MAX_PAYLOAD_SIZE}, {max_payload_size, ?MAX_PAYLOAD_SIZE},
@ -75,102 +75,111 @@ options() ->
{presence_based_delivery, false}]. {presence_based_delivery, false}].
features() -> features() ->
[<<"create-nodes">>, <<"delete-nodes">>, [<<"create-nodes">>,
<<"instant-nodes">>, <<"outcast-affiliation">>, <<"delete-nodes">>,
<<"persistent-items">>, <<"publish">>, <<"instant-nodes">>,
<<"outcast-affiliation">>,
<<"persistent-items">>,
<<"publish">>,
<<"retrieve-items">>]. <<"retrieve-items">>].
create_node_permission(Host, ServerHost, Node, create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
ParentNode, Owner, Access) -> node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
node_hometree:create_node_permission(Host, ServerHost,
Node, ParentNode, Owner, Access).
create_node(NodeId, Owner) -> create_node(Nidx, Owner) ->
node_hometree:create_node(NodeId, Owner). node_hometree:create_node(Nidx, Owner).
delete_node(Removed) -> delete_node(Nodes) ->
node_hometree:delete_node(Removed). node_hometree:delete_node(Nodes).
subscribe_node(_NodeId, _Sender, _Subscriber, subscribe_node(_Nidx, _Sender, _Subscriber, _AccessModel, _SendLast, _PresenceSubscription,
_AccessModel, _SendLast, _PresenceSubscription,
_RosterGroup, _Options) -> _RosterGroup, _Options) ->
{error, ?ERR_FORBIDDEN}. {error, ?ERR_FORBIDDEN}.
unsubscribe_node(_NodeId, _Sender, _Subscriber, unsubscribe_node(_Nidx, _Sender, _Subscriber, _SubId) ->
_SubID) ->
{error, ?ERR_FORBIDDEN}. {error, ?ERR_FORBIDDEN}.
publish_item(NodeId, Publisher, Model, MaxItems, ItemId, publish_item(Nidx, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
Payload) -> case nodetree_tree:get_node(Nidx) of
#pubsub_node{nodeid = {Host, Node}} ->
lists:foreach(fun (SubNode) -> lists:foreach(fun (SubNode) ->
node_hometree:publish_item(SubNode#pubsub_node.id, node_hometree:publish_item(SubNode#pubsub_node.id,
Publisher, Model, MaxItems, Publisher, PublishModel, MaxItems,
ItemId, Payload) ItemId, Payload)
end, end,
nodetree_tree:get_subnodes(NodeId, Publisher, nodetree_tree:get_subnodes(Host, Node, Publisher)),
Publisher)). {result, {default, broadcast, []}};
Error ->
Error
end.
remove_extra_items(_NodeId, _MaxItems, ItemIds) -> remove_extra_items(_Nidx, _MaxItems, ItemIds) ->
{result, {ItemIds, []}}. {result, {ItemIds, []}}.
delete_item(_NodeId, _Publisher, _PublishModel, delete_item(_Nidx, _Publisher, _PublishModel, _ItemId) ->
_ItemId) ->
{error, ?ERR_ITEM_NOT_FOUND}. {error, ?ERR_ITEM_NOT_FOUND}.
purge_node(_NodeId, _Owner) -> {error, ?ERR_FORBIDDEN}. purge_node(_Nidx, _Owner) ->
{error, ?ERR_FORBIDDEN}.
get_entity_affiliations(_Host, _Owner) -> {result, []}. get_entity_affiliations(_Host, _Owner) ->
{result, []}.
get_node_affiliations(_NodeId) -> {result, []}. get_node_affiliations(_Nidx) ->
{result, []}.
get_affiliation(_NodeId, _Owner) -> {result, []}. get_affiliation(_Nidx, _Owner) ->
{result, none}.
set_affiliation(NodeId, Owner, Affiliation) -> set_affiliation(Nidx, Owner, Affiliation) ->
node_hometree:set_affiliation(NodeId, Owner, node_hometree:set_affiliation(Nidx, Owner, Affiliation).
Affiliation).
get_entity_subscriptions(_Host, _Owner) -> {result, []}. get_entity_subscriptions(_Host, _Owner) ->
{result, []}.
get_node_subscriptions(NodeId) -> get_node_subscriptions(Nidx) ->
node_hometree:get_node_subscriptions(NodeId). node_hometree:get_node_subscriptions(Nidx).
get_subscriptions(_NodeId, _Owner) -> {result, []}. get_subscriptions(_Nidx, _Owner) ->
{result, []}.
set_subscriptions(NodeId, Owner, Subscription, SubId) -> set_subscriptions(Nidx, Owner, Subscription, SubId) ->
node_hometree:set_subscriptions(NodeId, Owner, node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
Subscription, SubId).
get_pending_nodes(Host, Owner) -> get_pending_nodes(Host, Owner) ->
node_hometree:get_pending_nodes(Host, Owner). node_hometree:get_pending_nodes(Host, Owner).
get_states(NodeId) -> node_hometree:get_states(NodeId). get_states(Nidx) ->
node_hometree:get_states(Nidx).
get_state(NodeId, JID) -> get_state(Nidx, JID) ->
node_hometree:get_state(NodeId, JID). node_hometree:get_state(Nidx, JID).
set_state(State) -> node_hometree:set_state(State). set_state(State) ->
node_hometree:set_state(State).
get_items(NodeId, From) -> get_items(Nidx, From, RSM) ->
node_hometree:get_items(NodeId, From). node_hometree:get_items(Nidx, From, RSM).
get_items(NodeId, JID, AccessModel, get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
PresenceSubscription, RosterGroup, SubId) -> node_hometree:get_items(Nidx, JID, AccessModel,
node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM).
get_item(Nidx, ItemId) ->
node_hometree:get_item(Nidx, ItemId).
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId). PresenceSubscription, RosterGroup, SubId).
get_item(NodeId, ItemId) -> set_item(Item) ->
node_hometree:get_item(NodeId, ItemId). node_hometree:set_item(Item).
get_item(NodeId, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId).
set_item(Item) -> node_hometree:set_item(Item).
get_item_name(Host, Node, Id) -> get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id). node_hometree:get_item_name(Host, Node, Id).
node_to_path(Node) -> node_flat:node_to_path(Node). node_to_path(Node) ->
node_flat:node_to_path(Node).
path_to_node(Path) -> node_flat:path_to_node(Path). path_to_node(Path) ->
node_flat:path_to_node(Path).

View File

@ -25,16 +25,12 @@
%%% ==================================================================== %%% ====================================================================
-module(node_flat). -module(node_flat).
-behaviour(gen_pubsub_node).
-author('christophe.romain@process-one.net'). -author('christophe.romain@process-one.net').
-include("pubsub.hrl"). -include("pubsub.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
-behaviour(gen_pubsub_node).
%% API definition
-export([init/3, terminate/2, options/0, features/0, -export([init/3, terminate/2, options/0, features/0,
create_node_permission/6, create_node/2, delete_node/1, create_node_permission/6, create_node/2, delete_node/1,
purge_node/2, subscribe_node/8, unsubscribe_node/4, purge_node/2, subscribe_node/8, unsubscribe_node/4,
@ -44,36 +40,39 @@
get_entity_subscriptions/2, get_node_subscriptions/1, get_entity_subscriptions/2, get_node_subscriptions/1,
get_subscriptions/2, set_subscriptions/4, get_subscriptions/2, set_subscriptions/4,
get_pending_nodes/2, get_states/1, get_state/2, get_pending_nodes/2, get_states/1, get_state/2,
set_state/1, get_items/6, get_items/2, get_item/7, set_state/1, get_items/7, get_items/3, get_item/7,
get_item/2, set_item/1, get_item_name/3, node_to_path/1, get_item/2, set_item/1, get_item_name/3, node_to_path/1,
path_to_node/1]). path_to_node/1]).
init(Host, ServerHost, Opts) -> init(_Host, _ServerHost, _Opts) ->
node_hometree:init(Host, ServerHost, Opts). pubsub_subscription:init(),
mnesia:create_table(pubsub_state,
[{disc_copies, [node()]},
{type, ordered_set},
{attributes, record_info(fields, pubsub_state)}]),
mnesia:create_table(pubsub_item,
[{disc_only_copies, [node()]},
{attributes, record_info(fields, pubsub_item)}]),
ItemsFields = record_info(fields, pubsub_item),
case mnesia:table_info(pubsub_item, attributes) of
ItemsFields -> ok;
_ -> mnesia:transform_table(pubsub_item, ignore, ItemsFields)
end,
ok.
terminate(Host, ServerHost) -> terminate(Host, ServerHost) ->
node_hometree:terminate(Host, ServerHost). node_hometree:terminate(Host, ServerHost).
options() -> options() ->
[{deliver_payloads, true}, {notify_config, false}, node_hometree:options().
{notify_delete, false}, {notify_retract, true},
{purge_offline, false}, {persist_items, true},
{max_items, ?MAXITEMS}, {subscribe, true},
{access_model, open}, {roster_groups_allowed, []},
{publish_model, publishers},
{notification_type, headline},
{max_payload_size, ?MAX_PAYLOAD_SIZE},
{send_last_published_item, on_sub_and_presence},
{deliver_notifications, true},
{presence_based_delivery, false}].
features() -> node_hometree:features(). features() ->
node_hometree:features().
%% use same code as node_hometree, but do not limite node to %% use same code as node_hometree, but do not limite node to
%% the home/localhost/user/... hierarchy %% the home/localhost/user/... hierarchy
%% any node is allowed %% any node is allowed
create_node_permission(Host, ServerHost, _Node, create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) ->
_ParentNode, Owner, Access) ->
LOwner = jlib:jid_tolower(Owner), LOwner = jlib:jid_tolower(Owner),
Allowed = case LOwner of Allowed = case LOwner of
{<<"">>, Host, <<"">>} -> {<<"">>, Host, <<"">>} ->
@ -83,96 +82,91 @@ create_node_permission(Host, ServerHost, _Node,
end, end,
{result, Allowed}. {result, Allowed}.
create_node(NodeId, Owner) -> create_node(Nidx, Owner) ->
node_hometree:create_node(NodeId, Owner). node_hometree:create_node(Nidx, Owner).
delete_node(Removed) -> delete_node(Removed) ->
node_hometree:delete_node(Removed). node_hometree:delete_node(Removed).
subscribe_node(NodeId, Sender, Subscriber, AccessModel, subscribe_node(Nidx, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup, Options) -> SendLast, PresenceSubscription, RosterGroup, Options) ->
node_hometree:subscribe_node(NodeId, Sender, Subscriber, node_hometree:subscribe_node(Nidx, Sender, Subscriber,
AccessModel, SendLast, PresenceSubscription, AccessModel, SendLast, PresenceSubscription,
RosterGroup, Options). RosterGroup, Options).
unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
node_hometree:unsubscribe_node(NodeId, Sender, node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
Subscriber, SubID).
publish_item(NodeId, Publisher, Model, MaxItems, ItemId, publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
Payload) -> node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
node_hometree:publish_item(NodeId, Publisher, Model,
MaxItems, ItemId, Payload).
remove_extra_items(NodeId, MaxItems, ItemIds) -> remove_extra_items(Nidx, MaxItems, ItemIds) ->
node_hometree:remove_extra_items(NodeId, MaxItems, node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
ItemIds).
delete_item(NodeId, Publisher, PublishModel, ItemId) -> delete_item(Nidx, Publisher, PublishModel, ItemId) ->
node_hometree:delete_item(NodeId, Publisher, node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
PublishModel, ItemId).
purge_node(NodeId, Owner) -> purge_node(Nidx, Owner) ->
node_hometree:purge_node(NodeId, Owner). node_hometree:purge_node(Nidx, Owner).
get_entity_affiliations(Host, Owner) -> get_entity_affiliations(Host, Owner) ->
node_hometree:get_entity_affiliations(Host, Owner). node_hometree:get_entity_affiliations(Host, Owner).
get_node_affiliations(NodeId) -> get_node_affiliations(Nidx) ->
node_hometree:get_node_affiliations(NodeId). node_hometree:get_node_affiliations(Nidx).
get_affiliation(NodeId, Owner) -> get_affiliation(Nidx, Owner) ->
node_hometree:get_affiliation(NodeId, Owner). node_hometree:get_affiliation(Nidx, Owner).
set_affiliation(NodeId, Owner, Affiliation) -> set_affiliation(Nidx, Owner, Affiliation) ->
node_hometree:set_affiliation(NodeId, Owner, node_hometree:set_affiliation(Nidx, Owner, Affiliation).
Affiliation).
get_entity_subscriptions(Host, Owner) -> get_entity_subscriptions(Host, Owner) ->
node_hometree:get_entity_subscriptions(Host, Owner). node_hometree:get_entity_subscriptions(Host, Owner).
get_node_subscriptions(NodeId) -> get_node_subscriptions(Nidx) ->
node_hometree:get_node_subscriptions(NodeId). node_hometree:get_node_subscriptions(Nidx).
get_subscriptions(NodeId, Owner) -> get_subscriptions(Nidx, Owner) ->
node_hometree:get_subscriptions(NodeId, Owner). node_hometree:get_subscriptions(Nidx, Owner).
set_subscriptions(NodeId, Owner, Subscription, SubId) -> set_subscriptions(Nidx, Owner, Subscription, SubId) ->
node_hometree:set_subscriptions(NodeId, Owner, node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
Subscription, SubId).
get_pending_nodes(Host, Owner) -> get_pending_nodes(Host, Owner) ->
node_hometree:get_pending_nodes(Host, Owner). node_hometree:get_pending_nodes(Host, Owner).
get_states(NodeId) -> node_hometree:get_states(NodeId). get_states(Nidx) ->
node_hometree:get_states(Nidx).
get_state(NodeId, JID) -> get_state(Nidx, JID) ->
node_hometree:get_state(NodeId, JID). node_hometree:get_state(Nidx, JID).
set_state(State) -> node_hometree:set_state(State). set_state(State) ->
node_hometree:set_state(State).
get_items(NodeId, From) -> get_items(Nidx, From, RSM) ->
node_hometree:get_items(NodeId, From). node_hometree:get_items(Nidx, From, RSM).
get_items(NodeId, JID, AccessModel, get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
PresenceSubscription, RosterGroup, SubId) -> node_hometree:get_items(Nidx, JID, AccessModel,
node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM).
get_item(Nidx, ItemId) ->
node_hometree:get_item(Nidx, ItemId).
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId). PresenceSubscription, RosterGroup, SubId).
get_item(NodeId, ItemId) -> set_item(Item) ->
node_hometree:get_item(NodeId, ItemId). node_hometree:set_item(Item).
get_item(NodeId, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId).
set_item(Item) -> node_hometree:set_item(Item).
get_item_name(Host, Node, Id) -> get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id). node_hometree:get_item_name(Host, Node, Id).
node_to_path(Node) -> [(Node)]. node_to_path(Node) ->
[(Node)].
path_to_node(Path) -> path_to_node(Path) ->
case Path of case Path of

View File

@ -25,30 +25,25 @@
%%% ==================================================================== %%% ====================================================================
-module(node_flat_odbc). -module(node_flat_odbc).
-behaviour(gen_pubsub_node).
-author('christophe.romain@process-one.net'). -author('christophe.romain@process-one.net').
-include("pubsub.hrl"). -include("pubsub.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
-behaviour(gen_pubsub_node).
%% API definition
-export([init/3, terminate/2, options/0, features/0, -export([init/3, terminate/2, options/0, features/0,
create_node_permission/6, create_node/2, delete_node/1, create_node_permission/6, create_node/2, delete_node/1,
purge_node/2, subscribe_node/8, unsubscribe_node/4, purge_node/2, subscribe_node/8, unsubscribe_node/4,
publish_item/6, delete_item/4, remove_extra_items/3, publish_item/6, delete_item/4, remove_extra_items/3,
get_entity_affiliations/2, get_node_affiliations/1, get_entity_affiliations/2, get_node_affiliations/1,
get_affiliation/2, set_affiliation/3, get_affiliation/2, set_affiliation/3,
get_entity_subscriptions/2, get_entity_subscriptions/2, get_node_subscriptions/1,
get_entity_subscriptions_for_send_last/2, get_subscriptions/2, set_subscriptions/4,
get_node_subscriptions/1, get_subscriptions/2, get_pending_nodes/2, get_states/1, get_state/2,
set_subscriptions/4, get_pending_nodes/2, get_states/1, set_state/1, get_items/7, get_items/3, get_item/7,
get_state/2, set_state/1, get_items/7, get_items/6, get_item/2, set_item/1, get_item_name/3, node_to_path/1,
get_items/3, get_items/2, get_item/7, get_item/2, path_to_node/1,
set_item/1, get_item_name/3, get_last_items/3, get_entity_subscriptions_for_send_last/2, get_last_items/3]).
node_to_path/1, path_to_node/1]).
init(Host, ServerHost, Opts) -> init(Host, ServerHost, Opts) ->
node_hometree_odbc:init(Host, ServerHost, Opts). node_hometree_odbc:init(Host, ServerHost, Opts).
@ -57,149 +52,107 @@ terminate(Host, ServerHost) ->
node_hometree_odbc:terminate(Host, ServerHost). node_hometree_odbc:terminate(Host, ServerHost).
options() -> options() ->
[{deliver_payloads, true}, [{odbc, true}, {rsm, true} | node_flat:options()].
{notify_config, false},
{notify_delete, false},
{notify_retract, true},
{purge_offline, false},
{persist_items, true},
{max_items, ?MAXITEMS},
{subscribe, true},
{access_model, open},
{roster_groups_allowed, []},
{publish_model, publishers},
{notification_type, headline},
{max_payload_size, ?MAX_PAYLOAD_SIZE},
{send_last_published_item, on_sub_and_presence},
{deliver_notifications, true},
{presence_based_delivery, false}, {odbc, true},
{rsm, true}].
features() -> node_hometree_odbc:features(). features() ->
[<<"rsm">> | node_flat:features()].
%% use same code as node_hometree_odbc, but do not limite node to %% use same code as node_hometree_odbc, but do not limite node to
%% the home/localhost/user/... hierarchy %% the home/localhost/user/... hierarchy
%% any node is allowed %% any node is allowed
create_node_permission(Host, ServerHost, _Node, create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
_ParentNode, Owner, Access) -> node_flat:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
LOwner = jlib:jid_tolower(Owner),
Allowed = case LOwner of
{<<"">>, Host, <<"">>} ->
true; % pubsub service always allowed
_ ->
acl:match_rule(ServerHost, Access, LOwner) =:= allow
end,
{result, Allowed}.
create_node(NodeId, Owner) -> create_node(Nidx, Owner) ->
node_hometree_odbc:create_node(NodeId, Owner). node_hometree_odbc:create_node(Nidx, Owner).
delete_node(Removed) -> delete_node(Removed) ->
node_hometree_odbc:delete_node(Removed). node_hometree_odbc:delete_node(Removed).
subscribe_node(NodeId, Sender, Subscriber, AccessModel, subscribe_node(Nidx, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup, Options) -> SendLast, PresenceSubscription, RosterGroup, Options) ->
node_hometree_odbc:subscribe_node(NodeId, Sender, node_hometree_odbc:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options).
PresenceSubscription, RosterGroup,
Options).
unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
node_hometree_odbc:unsubscribe_node(NodeId, Sender, node_hometree_odbc:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
Subscriber, SubID).
publish_item(NodeId, Publisher, Model, MaxItems, ItemId, publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
Payload) -> node_hometree_odbc:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
node_hometree_odbc:publish_item(NodeId, Publisher,
Model, MaxItems, ItemId, Payload).
remove_extra_items(NodeId, MaxItems, ItemIds) -> remove_extra_items(Nidx, MaxItems, ItemIds) ->
node_hometree_odbc:remove_extra_items(NodeId, MaxItems, node_hometree_odbc:remove_extra_items(Nidx, MaxItems, ItemIds).
ItemIds).
delete_item(NodeId, Publisher, PublishModel, ItemId) -> delete_item(Nidx, Publisher, PublishModel, ItemId) ->
node_hometree_odbc:delete_item(NodeId, Publisher, node_hometree_odbc:delete_item(Nidx, Publisher, PublishModel, ItemId).
PublishModel, ItemId).
purge_node(NodeId, Owner) -> purge_node(Nidx, Owner) ->
node_hometree_odbc:purge_node(NodeId, Owner). node_hometree_odbc:purge_node(Nidx, Owner).
get_entity_affiliations(Host, Owner) -> get_entity_affiliations(Host, Owner) ->
node_hometree_odbc:get_entity_affiliations(Host, Owner). node_hometree_odbc:get_entity_affiliations(Host, Owner).
get_node_affiliations(NodeId) -> get_node_affiliations(Nidx) ->
node_hometree_odbc:get_node_affiliations(NodeId). node_hometree_odbc:get_node_affiliations(Nidx).
get_affiliation(NodeId, Owner) -> get_affiliation(Nidx, Owner) ->
node_hometree_odbc:get_affiliation(NodeId, Owner). node_hometree_odbc:get_affiliation(Nidx, Owner).
set_affiliation(NodeId, Owner, Affiliation) -> set_affiliation(Nidx, Owner, Affiliation) ->
node_hometree_odbc:set_affiliation(NodeId, Owner, node_hometree_odbc:set_affiliation(Nidx, Owner, Affiliation).
Affiliation).
get_entity_subscriptions(Host, Owner) -> get_entity_subscriptions(Host, Owner) ->
node_hometree_odbc:get_entity_subscriptions(Host, node_hometree_odbc:get_entity_subscriptions(Host, Owner).
Owner).
get_entity_subscriptions_for_send_last(Host, Owner) -> get_entity_subscriptions_for_send_last(Host, Owner) ->
node_hometree_odbc:get_entity_subscriptions_for_send_last(Host, node_hometree_odbc:get_entity_subscriptions_for_send_last(Host, Owner).
Owner).
get_node_subscriptions(NodeId) -> get_node_subscriptions(Nidx) ->
node_hometree_odbc:get_node_subscriptions(NodeId). node_hometree_odbc:get_node_subscriptions(Nidx).
get_subscriptions(NodeId, Owner) -> get_subscriptions(Nidx, Owner) ->
node_hometree_odbc:get_subscriptions(NodeId, Owner). node_hometree_odbc:get_subscriptions(Nidx, Owner).
set_subscriptions(NodeId, Owner, Subscription, SubId) -> set_subscriptions(Nidx, Owner, Subscription, SubId) ->
node_hometree_odbc:set_subscriptions(NodeId, Owner, node_hometree_odbc:set_subscriptions(Nidx, Owner, Subscription, SubId).
Subscription, SubId).
get_pending_nodes(Host, Owner) -> get_pending_nodes(Host, Owner) ->
node_hometree_odbc:get_pending_nodes(Host, Owner). node_hometree_odbc:get_pending_nodes(Host, Owner).
get_states(NodeId) -> get_states(Nidx) ->
node_hometree_odbc:get_states(NodeId). node_hometree_odbc:get_states(Nidx).
get_state(NodeId, JID) -> get_state(Nidx, JID) ->
node_hometree_odbc:get_state(NodeId, JID). node_hometree_odbc:get_state(Nidx, JID).
set_state(State) -> node_hometree_odbc:set_state(State). set_state(State) ->
node_hometree_odbc:set_state(State).
get_items(NodeId, From) -> get_items(Nidx, From, RSM) ->
node_hometree_odbc:get_items(NodeId, From). node_hometree_odbc:get_items(Nidx, From, RSM).
get_items(NodeId, From, RSM) -> get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
node_hometree_odbc:get_items(NodeId, From, RSM). node_hometree_odbc:get_items(Nidx, JID, AccessModel,
get_items(NodeId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId) ->
get_items(NodeId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId, none).
get_items(NodeId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId, RSM) ->
node_hometree_odbc:get_items(NodeId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId, RSM). PresenceSubscription, RosterGroup, SubId, RSM).
get_item(NodeId, ItemId) -> get_item(Nidx, ItemId) ->
node_hometree_odbc:get_item(NodeId, ItemId). node_hometree_odbc:get_item(Nidx, ItemId).
get_item(NodeId, ItemId, JID, AccessModel, get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
PresenceSubscription, RosterGroup, SubId) -> node_hometree_odbc:get_item(Nidx, ItemId, JID,
node_hometree_odbc:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
AccessModel, PresenceSubscription, RosterGroup,
SubId).
set_item(Item) -> node_hometree_odbc:set_item(Item). set_item(Item) ->
node_hometree_odbc:set_item(Item).
get_item_name(Host, Node, Id) -> get_item_name(Host, Node, Id) ->
node_hometree_odbc:get_item_name(Host, Node, Id). node_hometree_odbc:get_item_name(Host, Node, Id).
get_last_items(NodeId, From, Count) -> get_last_items(Nidx, From, Count) ->
node_hometree_odbc:get_last_items(NodeId, From, Count). node_hometree_odbc:get_last_items(Nidx, From, Count).
node_to_path(Node) -> [(Node)]. node_to_path(Node) ->
[(Node)].
path_to_node(Path) -> path_to_node(Path) ->
case Path of case Path of

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -17,13 +17,19 @@
%%% All Rights Reserved.'' %%% All Rights Reserved.''
%%% This software is copyright 2006-2015, ProcessOne. %%% This software is copyright 2006-2015, ProcessOne.
%%% %%%
%%%
%%% @copyright 2006-2015 ProcessOne %%% @copyright 2006-2015 ProcessOne
%%% @author Eric Cestari <eric@ohmforce.com> %%% @author Eric Cestari <eric@ohmforce.com>
%%% @version {@vsn}, {@date} {@time} %%% @version {@vsn}, {@date} {@time}
%%% @end %%% @end
%%% ==================================================================== %%% ====================================================================
-module(node_mb).
-behaviour(gen_pubsub_node).
-author('eric@ohmforce.com').
-include("pubsub.hrl").
-include("jlib.hrl").
%%% @doc The module <strong>{@module}</strong> is the pep microblog PubSub plugin. %%% @doc The module <strong>{@module}</strong> is the pep microblog PubSub plugin.
%%% <p> To be used, mod_pubsub must be configured : %%% <p> To be used, mod_pubsub must be configured :
%%% {mod_pubsub, [ % requires mod_caps %%% {mod_pubsub, [ % requires mod_caps
@ -34,20 +40,6 @@
%%% </p> %%% </p>
%%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</p> %%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</p>
-module(node_mb).
-author('eric@ohmforce.com').
-include("ejabberd.hrl").
-include("logger.hrl").
-include("pubsub.hrl").
-include("jlib.hrl").
-behaviour(gen_pubsub_node).
%% API definition
-export([init/3, terminate/2, options/0, features/0, -export([init/3, terminate/2, options/0, features/0,
create_node_permission/6, create_node/2, delete_node/1, create_node_permission/6, create_node/2, delete_node/1,
purge_node/2, subscribe_node/8, unsubscribe_node/4, purge_node/2, subscribe_node/8, unsubscribe_node/4,
@ -57,7 +49,7 @@
get_entity_subscriptions/2, get_node_subscriptions/1, get_entity_subscriptions/2, get_node_subscriptions/1,
get_subscriptions/2, set_subscriptions/4, get_subscriptions/2, set_subscriptions/4,
get_pending_nodes/2, get_states/1, get_state/2, get_pending_nodes/2, get_states/1, get_state/2,
set_state/1, get_items/6, get_items/2, get_item/7, set_state/1, get_items/7, get_items/3, get_item/7,
get_item/2, set_item/1, get_item_name/3, node_to_path/1, get_item/2, set_item/1, get_item_name/3, node_to_path/1,
path_to_node/1]). path_to_node/1]).
@ -68,11 +60,16 @@ terminate(Host, ServerHost) ->
node_pep:terminate(Host, ServerHost), ok. node_pep:terminate(Host, ServerHost), ok.
options() -> options() ->
[{deliver_payloads, true}, {notify_config, false}, [{deliver_payloads, true},
{notify_delete, false}, {notify_retract, false}, {notify_config, false},
{purge_offline, false}, {persist_items, true}, {notify_delete, false},
{max_items, ?MAXITEMS}, {subscribe, true}, {notify_retract, false},
{access_model, presence}, {roster_groups_allowed, []}, {purge_offline, false},
{persist_items, true},
{max_items, ?MAXITEMS},
{subscribe, true},
{access_model, presence},
{roster_groups_allowed, []},
{publish_model, publishers}, {publish_model, publishers},
{notification_type, headline}, {notification_type, headline},
{max_payload_size, ?MAX_PAYLOAD_SIZE}, {max_payload_size, ?MAX_PAYLOAD_SIZE},
@ -81,111 +78,109 @@ options() ->
{presence_based_delivery, true}]. {presence_based_delivery, true}].
features() -> features() ->
[<<"create-nodes">>, %* [<<"create-nodes">>,
<<"auto-create">>, %* <<"auto-create">>,
<<"auto-subscribe">>, %* <<"auto-subscribe">>,
<<"delete-nodes">>, %* <<"delete-nodes">>,
<<"delete-items">>, %* <<"delete-items">>,
<<"filtered-notifications">>, %* <<"filtered-notifications">>,
<<"modify-affiliations">>, <<"outcast-affiliation">>, <<"modify-affiliations">>,
<<"outcast-affiliation">>,
<<"persistent-items">>, <<"persistent-items">>,
<<"publish">>, %* <<"publish">>,
<<"purge-nodes">>, <<"retract-items">>, <<"purge-nodes">>,
<<"retract-items">>,
<<"retrieve-affiliations">>, <<"retrieve-affiliations">>,
<<"retrieve-items">>, %* <<"retrieve-items">>,
<<"retrieve-subscriptions">>, <<"subscribe">>]. <<"retrieve-subscriptions">>,
<<"subscribe">>].
create_node_permission(Host, ServerHost, Node, create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
ParentNode, Owner, Access) -> node_pep:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
node_pep:create_node_permission(Host, ServerHost, Node,
ParentNode, Owner, Access).
create_node(NodeId, Owner) -> create_node(Nidx, Owner) ->
node_pep:create_node(NodeId, Owner). node_pep:create_node(Nidx, Owner).
delete_node(Removed) -> node_pep:delete_node(Removed). delete_node(Removed) ->
node_pep:delete_node(Removed).
subscribe_node(NodeId, Sender, Subscriber, AccessModel, subscribe_node(Nidx, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup, Options) -> SendLast, PresenceSubscription, RosterGroup, Options) ->
node_pep:subscribe_node(NodeId, Sender, Subscriber, node_pep:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
AccessModel, SendLast, PresenceSubscription, PresenceSubscription, RosterGroup, Options).
RosterGroup, Options).
unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
node_pep:unsubscribe_node(NodeId, Sender, Subscriber, node_pep:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
SubID).
publish_item(NodeId, Publisher, Model, MaxItems, ItemId, publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
Payload) -> node_pep:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
node_pep:publish_item(NodeId, Publisher, Model,
MaxItems, ItemId, Payload).
remove_extra_items(NodeId, MaxItems, ItemIds) -> remove_extra_items(Nidx, MaxItems, ItemIds) ->
node_pep:remove_extra_items(NodeId, MaxItems, ItemIds). node_pep:remove_extra_items(Nidx, MaxItems, ItemIds).
delete_item(NodeId, Publisher, PublishModel, ItemId) -> delete_item(Nidx, Publisher, PublishModel, ItemId) ->
node_pep:delete_item(NodeId, Publisher, PublishModel, node_pep:delete_item(Nidx, Publisher, PublishModel, ItemId).
ItemId).
purge_node(NodeId, Owner) -> purge_node(Nidx, Owner) ->
node_pep:purge_node(NodeId, Owner). node_pep:purge_node(Nidx, Owner).
get_entity_affiliations(Host, Owner) -> get_entity_affiliations(Host, Owner) ->
node_pep:get_entity_affiliations(Host, Owner). node_pep:get_entity_affiliations(Host, Owner).
get_node_affiliations(NodeId) -> get_node_affiliations(Nidx) ->
node_pep:get_node_affiliations(NodeId). node_pep:get_node_affiliations(Nidx).
get_affiliation(NodeId, Owner) -> get_affiliation(Nidx, Owner) ->
node_pep:get_affiliation(NodeId, Owner). node_pep:get_affiliation(Nidx, Owner).
set_affiliation(NodeId, Owner, Affiliation) -> set_affiliation(Nidx, Owner, Affiliation) ->
node_pep:set_affiliation(NodeId, Owner, Affiliation). node_pep:set_affiliation(Nidx, Owner, Affiliation).
get_entity_subscriptions(Host, Owner) -> get_entity_subscriptions(Host, Owner) ->
node_pep:get_entity_subscriptions(Host, Owner). node_pep:get_entity_subscriptions(Host, Owner).
get_node_subscriptions(NodeId) -> get_node_subscriptions(Nidx) ->
node_pep:get_node_subscriptions(NodeId). node_pep:get_node_subscriptions(Nidx).
get_subscriptions(NodeId, Owner) -> get_subscriptions(Nidx, Owner) ->
node_pep:get_subscriptions(NodeId, Owner). node_pep:get_subscriptions(Nidx, Owner).
set_subscriptions(NodeId, Owner, Subscription, SubId) -> set_subscriptions(Nidx, Owner, Subscription, SubId) ->
node_pep:set_subscriptions(NodeId, Owner, Subscription, node_pep:set_subscriptions(Nidx, Owner, Subscription, SubId).
SubId).
get_pending_nodes(Host, Owner) -> get_pending_nodes(Host, Owner) ->
node_hometree:get_pending_nodes(Host, Owner). node_hometree:get_pending_nodes(Host, Owner).
get_states(NodeId) -> node_pep:get_states(NodeId). get_states(Nidx) ->
node_pep:get_states(Nidx).
get_state(NodeId, JID) -> get_state(Nidx, JID) ->
node_pep:get_state(NodeId, JID). node_pep:get_state(Nidx, JID).
set_state(State) -> node_pep:set_state(State). set_state(State) ->
node_pep:set_state(State).
get_items(NodeId, From) -> get_items(Nidx, From, RSM) ->
node_pep:get_items(NodeId, From). node_pep:get_items(Nidx, From, RSM).
get_items(NodeId, JID, AccessModel, get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
PresenceSubscription, RosterGroup, SubId) -> node_pep:get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM).
node_pep:get_items(NodeId, JID, AccessModel,
get_item(Nidx, ItemId) ->
node_pep:get_item(Nidx, ItemId).
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_pep:get_item(Nidx, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId). PresenceSubscription, RosterGroup, SubId).
get_item(NodeId, ItemId) -> set_item(Item) ->
node_pep:get_item(NodeId, ItemId). node_pep:set_item(Item).
get_item(NodeId, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId) ->
node_pep:get_item(NodeId, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId).
set_item(Item) -> node_pep:set_item(Item).
get_item_name(Host, Node, Id) -> get_item_name(Host, Node, Id) ->
node_pep:get_item_name(Host, Node, Id). node_pep:get_item_name(Host, Node, Id).
node_to_path(Node) -> node_pep:node_to_path(Node). node_to_path(Node) ->
node_pep:node_to_path(Node).
path_to_node(Path) -> node_pep:path_to_node(Path). path_to_node(Path) ->
node_pep:path_to_node(Path).

View File

@ -17,7 +17,6 @@
%%% All Rights Reserved.'' %%% All Rights Reserved.''
%%% This software is copyright 2006-2015, ProcessOne. %%% This software is copyright 2006-2015, ProcessOne.
%%% %%%
%%%
%%% @copyright 2006-2015 ProcessOne %%% @copyright 2006-2015 ProcessOne
%%% @author Christophe Romain <christophe.romain@process-one.net> %%% @author Christophe Romain <christophe.romain@process-one.net>
%%% [http://www.process-one.net/] %%% [http://www.process-one.net/]
@ -25,23 +24,17 @@
%%% @end %%% @end
%%% ==================================================================== %%% ====================================================================
-module(node_pep).
-behaviour(gen_pubsub_node).
-author('christophe.romain@process-one.net').
-include("pubsub.hrl").
-include("jlib.hrl").
-include("logger.hrl").
%%% @doc The module <strong>{@module}</strong> is the pep PubSub plugin. %%% @doc The module <strong>{@module}</strong> is the pep PubSub plugin.
%%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</p> %%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</p>
-module(node_pep).
-author('christophe.romain@process-one.net').
-include("ejabberd.hrl").
-include("logger.hrl").
-include("pubsub.hrl").
-include("jlib.hrl").
-behaviour(gen_pubsub_node).
%% API definition
-export([init/3, terminate/2, options/0, features/0, -export([init/3, terminate/2, options/0, features/0,
create_node_permission/6, create_node/2, delete_node/1, create_node_permission/6, create_node/2, delete_node/1,
purge_node/2, subscribe_node/8, unsubscribe_node/4, purge_node/2, subscribe_node/8, unsubscribe_node/4,
@ -51,7 +44,7 @@
get_entity_subscriptions/2, get_node_subscriptions/1, get_entity_subscriptions/2, get_node_subscriptions/1,
get_subscriptions/2, set_subscriptions/4, get_subscriptions/2, set_subscriptions/4,
get_pending_nodes/2, get_states/1, get_state/2, get_pending_nodes/2, get_states/1, get_state/2,
set_state/1, get_items/6, get_items/2, get_item/7, set_state/1, get_items/7, get_items/3, get_item/7,
get_item/2, set_item/1, get_item_name/3, node_to_path/1, get_item/2, set_item/1, get_item_name/3, node_to_path/1,
path_to_node/1]). path_to_node/1]).
@ -63,13 +56,17 @@ init(Host, ServerHost, Opts) ->
terminate(Host, ServerHost) -> terminate(Host, ServerHost) ->
node_hometree:terminate(Host, ServerHost), ok. node_hometree:terminate(Host, ServerHost), ok.
-spec(options/0 :: () -> NodeOptions::mod_pubsub:nodeOptions()).
options() -> options() ->
[{deliver_payloads, true}, {notify_config, false}, [{deliver_payloads, true},
{notify_delete, false}, {notify_retract, false}, {notify_config, false},
{purge_offline, false}, {persist_items, true}, {notify_delete, false},
{max_items, 1}, {subscribe, true}, {notify_retract, false},
{access_model, presence}, {roster_groups_allowed, []}, {purge_offline, false},
{persist_items, false},
{max_items, 1},
{subscribe, true},
{access_model, presence},
{roster_groups_allowed, []},
{publish_model, publishers}, {publish_model, publishers},
{notification_type, headline}, {notification_type, headline},
{max_payload_size, ?MAX_PAYLOAD_SIZE}, {max_payload_size, ?MAX_PAYLOAD_SIZE},
@ -77,33 +74,23 @@ options() ->
{deliver_notifications, true}, {deliver_notifications, true},
{presence_based_delivery, true}]. {presence_based_delivery, true}].
-spec(features/0 :: () -> Features::[binary(),...]).
features() -> features() ->
[<<"create-nodes">>, %* [<<"create-nodes">>,
<<"auto-create">>, %* <<"auto-create">>,
<<"auto-subscribe">>, %* <<"auto-subscribe">>,
<<"delete-nodes">>, %* <<"delete-nodes">>,
<<"delete-items">>, %* <<"delete-items">>,
<<"filtered-notifications">>, %* <<"filtered-notifications">>,
<<"modify-affiliations">>, <<"outcast-affiliation">>, <<"modify-affiliations">>,
<<"outcast-affiliation">>,
<<"persistent-items">>, <<"persistent-items">>,
<<"publish">>, %* <<"publish">>,
<<"purge-nodes">>, <<"retract-items">>, <<"purge-nodes">>,
<<"retract-items">>,
<<"retrieve-affiliations">>, <<"retrieve-affiliations">>,
<<"retrieve-items">>, %* <<"retrieve-items">>,
<<"retrieve-subscriptions">>, <<"subscribe">>]. <<"retrieve-subscriptions">>,
<<"subscribe">>].
-spec(create_node_permission/6 ::
(
Host :: mod_pubsub:hostPEP(),
ServerHost :: binary(),
NodeId :: mod_pubsub:nodeId(),
_ParentNodeId :: mod_pubsub:nodeId(),
Owner :: jid(),
Access :: atom())
-> {result, boolean()}
).
create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) ->
LOwner = jlib:jid_tolower(Owner), LOwner = jlib:jid_tolower(Owner),
@ -118,152 +105,51 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) ->
{User, Server, _} -> true; {User, Server, _} -> true;
_ -> false _ -> false
end; end;
E -> ?DEBUG("Create not allowed : ~p~n", [E]), false _ ->
false
end end
end, end,
{result, Allowed}. {result, Allowed}.
-spec(create_node/2 :: create_node(Nidx, Owner) ->
( node_hometree:create_node(Nidx, Owner).
NodeIdx :: mod_pubsub:nodeIdx(),
Owner :: jid())
-> {result, {default, broadcast}}
).
create_node(NodeIdx, Owner) ->
node_hometree:create_node(NodeIdx, Owner).
-spec(delete_node/1 :: delete_node(Nodes) ->
( {result, {_, _, Result}} = node_hometree:delete_node(Nodes),
Nodes :: [mod_pubsub:pubsubNode(),...]) {result, {[], Result}}.
-> {result,
{[],
[{mod_pubsub:pubsubNode(),
[{ljid(), [{mod_pubsub:subscription(), mod_pubsub:subId()}]},...]},...]
}
}
).
delete_node(Removed) -> subscribe_node(Nidx, Sender, Subscriber, AccessModel,
case node_hometree:delete_node(Removed) of SendLast, PresenceSubscription, RosterGroup, Options) ->
{result, {_, _, Result}} -> {result, {[], Result}}; node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
Error -> Error PresenceSubscription, RosterGroup, Options).
end.
-spec(subscribe_node/8 :: unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
( case node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId) of
NodeIdx :: mod_pubsub:nodeIdx(),
Sender :: jid(),
Subscriber :: ljid(),
AccessModel :: mod_pubsub:accessModel(),
SendLast :: 'never' | 'on_sub' | 'on_sub_and_presence',
PresenceSubscription :: boolean(),
RosterGroup :: boolean(),
Options :: mod_pubsub:subOptions())
-> {result, {default, subscribed, mod_pubsub:subId()}}
| {result, {default, subscribed, mod_pubsub:subId(), send_last}}
| {result, {default, pending, mod_pubsub:subId()}}
%%%
| {error, xmlel()}
).
subscribe_node(NodeIdx, Sender, Subscriber, AccessModel, SendLast,
PresenceSubscription, RosterGroup, Options) ->
node_hometree:subscribe_node(NodeIdx, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup, Options).
-spec(unsubscribe_node/4 ::
(
NodeIdx :: mod_pubsub:nodeIdx(),
Sender :: jid(),
Subscriber :: ljid(),
SubId :: subId())
-> {result, default}
%
| {error, xmlel()}
).
unsubscribe_node(NodeIdx, Sender, Subscriber, SubID) ->
case node_hometree:unsubscribe_node(NodeIdx, Sender, Subscriber, SubID) of
{error, Error} -> {error, Error}; {error, Error} -> {error, Error};
{result, _} -> {result, []} {result, _} -> {result, []}
end. end.
-spec(publish_item/6 :: publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
( node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
NodeIdx :: mod_pubsub:nodeIdx(),
Publisher :: jid(),
PublishModel :: mod_pubsub:publishModel(),
Max_Items :: non_neg_integer(),
ItemId :: <<>> | mod_pubsub:itemId(),
Payload :: mod_pubsub:payload())
-> {result, {default, broadcast, [mod_pubsub:itemId()]}}
%%%
| {error, xmlel()}
).
publish_item(NodeIdx, Publisher, Model, MaxItems, ItemId, Payload) ->
node_hometree:publish_item(NodeIdx, Publisher, Model, MaxItems, ItemId, Payload).
-spec(remove_extra_items/3 :: remove_extra_items(Nidx, MaxItems, ItemIds) ->
( node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
NodeIdx :: mod_pubsub:nodeIdx(),
Max_Items :: unlimited | non_neg_integer(),
ItemIds :: [mod_pubsub:itemId()])
-> {result,
{NewItems::[mod_pubsub:itemId()],
OldItems::[mod_pubsub:itemId()]}
}
).
remove_extra_items(NodeId, MaxItems, ItemIds) ->
node_hometree:remove_extra_items(NodeId, MaxItems, ItemIds).
delete_item(Nidx, Publisher, PublishModel, ItemId) ->
node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
-spec(delete_item/4 :: purge_node(Nidx, Owner) ->
( node_hometree:purge_node(Nidx, Owner).
NodeIdx :: mod_pubsub:nodeIdx(),
Publisher :: jid(),
PublishModel :: mod_pubsub:publishModel(),
ItemId :: <<>> | mod_pubsub:itemId())
-> {result, {default, broadcast}}
%%%
| {error, xmlel()}
).
delete_item(NodeIdx, Publisher, PublishModel, ItemId) ->
node_hometree:delete_item(NodeIdx, Publisher, PublishModel, ItemId).
-spec(purge_node/2 :: get_entity_affiliations(Host, Owner) ->
(
NodeIdx :: mod_pubsub:nodeIdx(),
Owner :: jid())
-> {result, {default, broadcast}}
| {error, xmlel()}
).
purge_node(NodeIdx, Owner) ->
node_hometree:purge_node(NodeIdx, Owner).
-spec(get_entity_affiliations/2 ::
(
Host :: mod_pubsub:hostPEP(),
Owner :: jid())
-> {result, [{mod_pubsub:pubsubNode(), mod_pubsub:affiliation()}]}
).
get_entity_affiliations(_Host, Owner) ->
{_, D, _} = SubKey = jlib:jid_tolower(Owner), {_, D, _} = SubKey = jlib:jid_tolower(Owner),
SubKey = jlib:jid_tolower(Owner), SubKey = jlib:jid_tolower(Owner),
GenKey = jlib:jid_remove_resource(SubKey), GenKey = jlib:jid_remove_resource(SubKey),
States = mnesia:match_object(#pubsub_state{stateid = States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'}),
{GenKey, '_'}, NodeTree = mod_pubsub:tree(Host),
_ = '_'}), Reply = lists:foldl(fun (#pubsub_state{stateid = {_, N}, affiliation = A}, Acc) ->
NodeTree = case catch
ets:lookup(gen_mod:get_module_proc(D, config), nodetree)
of
[{nodetree, N}] -> N;
_ -> nodetree_tree
end,
Reply = lists:foldl(fun (#pubsub_state{stateid = {_, N},
affiliation = A},
Acc) ->
case NodeTree:get_node(N) of case NodeTree:get_node(N) of
#pubsub_node{nodeid = {{_, D, _}, _}} = #pubsub_node{nodeid = {{_, D, _}, _}} = Node -> [{Node, A} | Acc];
Node ->
[{Node, A} | Acc];
_ -> Acc _ -> Acc
end end
end, end,
@ -271,215 +157,92 @@ get_entity_affiliations(_Host, Owner) ->
{result, Reply}. {result, Reply}.
-spec(get_node_affiliations/1 :: get_node_affiliations(Nidx) ->
( node_hometree:get_node_affiliations(Nidx).
NodeIdx::mod_pubsub:nodeIdx())
-> {result, [{ljid(), mod_pubsub:affiliation()}]}
).
get_node_affiliations(NodeIdx) ->
node_hometree:get_node_affiliations(NodeIdx).
-spec(get_affiliation/2 :: get_affiliation(Nidx, Owner) ->
( node_hometree:get_affiliation(Nidx, Owner).
NodeIdx :: mod_pubsub:nodeIdx(),
Owner :: jid())
-> {result, mod_pubsub:affiliation()}
).
get_affiliation(NodeIdx, Owner) ->
node_hometree:get_affiliation(NodeIdx, Owner).
-spec(set_affiliation/3 :: set_affiliation(Nidx, Owner, Affiliation) ->
( node_hometree:set_affiliation(Nidx, Owner, Affiliation).
NodeIdx :: mod_pubsub:nodeIdx(),
Owner :: ljid(),
Affiliation :: mod_pubsub:affiliation())
-> ok
).
set_affiliation(NodeIdx, Owner, Affiliation) ->
node_hometree:set_affiliation(NodeIdx, Owner, Affiliation).
-spec(get_entity_subscriptions/2 :: get_entity_subscriptions(Host, Owner) ->
(
Host :: mod_pubsub:hostPEP(),
Owner :: jid())
-> {result,
[{mod_pubsub:pubsubNode(),
mod_pubsub:subscription(),
mod_pubsub:subId(),
ljid()}]
}
).
get_entity_subscriptions(_Host, Owner) ->
{U, D, _} = SubKey = jlib:jid_tolower(Owner), {U, D, _} = SubKey = jlib:jid_tolower(Owner),
GenKey = jlib:jid_remove_resource(SubKey), GenKey = jlib:jid_remove_resource(SubKey),
States = case SubKey of States = case SubKey of
GenKey -> GenKey ->
mnesia:match_object(#pubsub_state{stateid = mnesia:match_object(#pubsub_state{stateid = {{U, D, '_'}, '_'}, _ = '_'});
{{U, D, '_'}, '_'},
_ = '_'});
_ -> _ ->
mnesia:match_object(#pubsub_state{stateid = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'})
{GenKey, '_'},
_ = '_'})
++ ++
mnesia:match_object(#pubsub_state{stateid = mnesia:match_object(#pubsub_state{stateid = {SubKey, '_'}, _ = '_'})
{SubKey, '_'},
_ = '_'})
end, end,
NodeTree = case catch NodeTree = mod_pubsub:tree(Host),
ets:lookup(gen_mod:get_module_proc(D, config), nodetree) Reply = lists:foldl(fun (#pubsub_state{stateid = {J, N}, subscriptions = Ss}, Acc) ->
of
[{nodetree, N}] -> N;
_ -> nodetree_tree
end,
Reply = lists:foldl(fun (#pubsub_state{stateid = {J, N},
subscriptions = Ss},
Acc) ->
case NodeTree:get_node(N) of case NodeTree:get_node(N) of
#pubsub_node{nodeid = {{_, D, _}, _}} = Node -> #pubsub_node{nodeid = {{_, D, _}, _}} = Node ->
lists:foldl(fun lists:foldl(fun
({subscribed, SubID}, Acc2) -> ({subscribed, SubId}, Acc2) ->
[{Node, subscribed, SubID, J} | Acc2]; [{Node, subscribed, SubId, J} | Acc2];
({pending, _SubID}, Acc2) -> ({pending, _SubId}, Acc2) ->
[{Node, pending, J} | Acc2]; [{Node, pending, J} | Acc2];
(S, Acc2) -> (S, Acc2) ->
[{Node, S, J} | Acc2] [{Node, S, J} | Acc2]
end, Acc, Ss); end,
_ -> Acc Acc, Ss);
_ ->
Acc
end end
end, end,
[], States), [], States),
{result, Reply}. {result, Reply}.
-spec(get_node_subscriptions/1 :: get_node_subscriptions(Nidx) ->
( node_hometree:get_node_subscriptions(Nidx).
NodeIdx::mod_pubsub:nodeIdx())
-> {result,
[{ljid(), mod_pubsub:subscription(), mod_pubsub:subId()}] |
[{ljid(), none},...]
}
).
get_node_subscriptions(NodeIdx) ->
node_hometree:get_node_subscriptions(NodeIdx).
-spec(get_subscriptions/2 :: get_subscriptions(Nidx, Owner) ->
( node_hometree:get_subscriptions(Nidx, Owner).
NodeIdx :: mod_pubsub:nodeIdx(),
Owner :: ljid())
-> {result, [{mod_pubsub:subscription(), mod_pubsub:subId()}]}
).
get_subscriptions(NodeIdx, Owner) ->
node_hometree:get_subscriptions(NodeIdx, Owner).
-spec(set_subscriptions/4 :: set_subscriptions(Nidx, Owner, Subscription, SubId) ->
( node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
NodeIdx :: mod_pubsub:nodeIdx(),
Owner :: jid(),
Subscription :: mod_pubsub:subscription(),
SubId :: mod_pubsub:subId())
-> ok
%%%
| {error, xmlel()}
).
set_subscriptions(NodeIdx, Owner, Subscription, SubId) ->
node_hometree:set_subscriptions(NodeIdx, Owner, Subscription, SubId).
-spec(get_pending_nodes/2 ::
(
Host :: mod_pubsub:hostPubsub(),
Owner :: jid())
-> {result, [mod_pubsub:nodeId()]}
).
get_pending_nodes(Host, Owner) -> get_pending_nodes(Host, Owner) ->
node_hometree:get_pending_nodes(Host, Owner). node_hometree:get_pending_nodes(Host, Owner).
-spec(get_states/1 :: get_states(Nidx) ->
( node_hometree:get_states(Nidx).
NodeIdx::mod_pubsub:nodeIdx())
-> {result, [mod_pubsub:pubsubState()]}
).
get_states(NodeIdx) -> node_hometree:get_states(NodeIdx).
-spec(get_state/2 :: get_state(Nidx, JID) ->
( node_hometree:get_state(Nidx, JID).
NodeIdx :: mod_pubsub:nodeIdx(),
JID :: ljid())
-> mod_pubsub:pubsubState()
).
get_state(NodeIdx, JID) ->
node_hometree:get_state(NodeIdx, JID).
-spec(set_state/1 :: set_state(State) ->
( node_hometree:set_state(State).
State::mod_pubsub:pubsubState())
-> ok
).
set_state(State) -> node_hometree:set_state(State).
-spec(get_items/2 :: get_items(Nidx, From, RSM) ->
( node_hometree:get_items(Nidx, From, RSM).
NodeIdx :: mod_pubsub:nodeIdx(),
_From :: jid())
-> {result, [mod_pubsub:pubsubItem()]}
).
get_items(NodeIdx, From) ->
node_hometree:get_items(NodeIdx, From).
-spec(get_items/6 :: get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
( node_hometree:get_items(Nidx, JID, AccessModel,
NodeIdx :: mod_pubsub:nodeIdx(), PresenceSubscription, RosterGroup, SubId, RSM).
JID :: jid(),
AccessModel :: mod_pubsub:accessModel(),
Presence_Subscription :: boolean(),
RosterGroup :: boolean(),
_SubId :: mod_pubsub:subId())
-> {result, [mod_pubsub:pubsubItem()]}
%%%
| {error, xmlel()}
).
get_items(NodeIdx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_items(NodeIdx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
-spec(get_item/2 :: get_item(Nidx, ItemId) ->
( node_hometree:get_item(Nidx, ItemId).
NodeIdx :: mod_pubsub:nodeIdx(),
ItemId :: mod_pubsub:itemId())
-> {result, mod_pubsub:pubsubItem()}
| {error, xmlel()}
).
get_item(NodeIdx, ItemId) ->
node_hometree:get_item(NodeIdx, ItemId).
-spec(get_item/7 :: get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
( node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
NodeIdx :: mod_pubsub:nodeIdx(), PresenceSubscription, RosterGroup, SubId).
ItemId :: mod_pubsub:itemId(),
JID :: jid(),
AccessModel :: mod_pubsub:accessModel(),
PresenceSubscription :: boolean(),
RosterGroup :: boolean(),
SubId :: mod_pubsub:subId())
-> {result, mod_pubsub:pubsubItem()}
| {error, xmlel()}
).
get_item(NodeIdx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup,
SubId) ->
node_hometree:get_item(NodeIdx, ItemId, JID, AccessModel, PresenceSubscription,
RosterGroup, SubId).
-spec(set_item/1 :: set_item(Item) ->
( node_hometree:set_item(Item).
Item::mod_pubsub:pubsubItem())
-> ok
).
set_item(Item) -> node_hometree:set_item(Item).
get_item_name(Host, Node, Id) -> get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id). node_hometree:get_item_name(Host, Node, Id).
node_to_path(Node) -> node_flat:node_to_path(Node). node_to_path(Node) ->
node_flat:node_to_path(Node).
path_to_node(Path) -> node_flat:path_to_node(Path). path_to_node(Path) ->
node_flat:path_to_node(Path).
%%% %%%
%%% Internal %%% Internal

View File

@ -17,7 +17,6 @@
%%% All Rights Reserved.'' %%% All Rights Reserved.''
%%% This software is copyright 2006-2015, ProcessOne. %%% This software is copyright 2006-2015, ProcessOne.
%%% %%%
%%%
%%% @copyright 2006-2015 ProcessOne %%% @copyright 2006-2015 ProcessOne
%%% @author Christophe Romain <christophe.romain@process-one.net> %%% @author Christophe Romain <christophe.romain@process-one.net>
%%% [http://www.process-one.net/] %%% [http://www.process-one.net/]
@ -25,39 +24,30 @@
%%% @end %%% @end
%%% ==================================================================== %%% ====================================================================
-module(node_pep_odbc).
-behaviour(gen_pubsub_node).
-author('christophe.romain@process-one.net').
-include("pubsub.hrl").
-include("jlib.hrl").
-include("logger.hrl").
%%% @doc The module <strong>{@module}</strong> is the pep PubSub plugin. %%% @doc The module <strong>{@module}</strong> is the pep PubSub plugin.
%%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</p> %%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</p>
-module(node_pep_odbc).
-author('christophe.romain@process-one.net').
-include("ejabberd.hrl").
-include("logger.hrl").
-include("pubsub.hrl").
-include("jlib.hrl").
-define(PUBSUB, mod_pubsub_odbc).
-behaviour(gen_pubsub_node).
%% API definition
-export([init/3, terminate/2, options/0, features/0, -export([init/3, terminate/2, options/0, features/0,
create_node_permission/6, create_node/2, delete_node/1, create_node_permission/6, create_node/2, delete_node/1,
purge_node/2, subscribe_node/8, unsubscribe_node/4, purge_node/2, subscribe_node/8, unsubscribe_node/4,
publish_item/6, delete_item/4, remove_extra_items/3, publish_item/6, delete_item/4, remove_extra_items/3,
get_entity_affiliations/2, get_node_affiliations/1, get_entity_affiliations/2, get_node_affiliations/1,
get_affiliation/2, set_affiliation/3, get_affiliation/2, set_affiliation/3,
get_entity_subscriptions/2, get_entity_subscriptions/2, get_node_subscriptions/1,
get_entity_subscriptions_for_send_last/2, get_subscriptions/2, set_subscriptions/4,
get_node_subscriptions/1, get_subscriptions/2, get_pending_nodes/2, get_states/1, get_state/2,
set_subscriptions/4, get_pending_nodes/2, get_states/1, set_state/1, get_items/7, get_items/3, get_item/7,
get_state/2, set_state/1, get_items/7, get_items/6, get_item/2, set_item/1, get_item_name/3, node_to_path/1,
get_items/3, get_items/2, get_item/7, get_item/2, path_to_node/1,
set_item/1, get_item_name/3, get_last_items/3, get_entity_subscriptions_for_send_last/2, get_last_items/3]).
node_to_path/1, path_to_node/1]).
init(Host, ServerHost, Opts) -> init(Host, ServerHost, Opts) ->
node_hometree_odbc:init(Host, ServerHost, Opts), node_hometree_odbc:init(Host, ServerHost, Opts),
@ -67,362 +57,183 @@ init(Host, ServerHost, Opts) ->
terminate(Host, ServerHost) -> terminate(Host, ServerHost) ->
node_hometree_odbc:terminate(Host, ServerHost), ok. node_hometree_odbc:terminate(Host, ServerHost), ok.
-spec(options/0 :: () -> NodeOptions::mod_pubsub:nodeOptions()).
options() -> options() ->
[{odbc, true}, [{odbc, true}, {rsm, true} | node_pep:options()].
{deliver_payloads, true},
{notify_config, false},
{notify_delete, false},
{notify_retract, false},
{purge_offline, false},
{persist_items, true},
{max_items, 1},
{subscribe, true},
{access_model, presence},
{roster_groups_allowed, []},
{publish_model, publishers},
{notification_type, headline},
{max_payload_size, ?MAX_PAYLOAD_SIZE},
{send_last_published_item, on_sub_and_presence},
{deliver_notifications, true},
{presence_based_delivery, true}].
-spec(features/0 :: () -> Features::[binary(),...]).
features() -> features() ->
[<<"create-nodes">>, %* [<<"rsm">> | node_pep:features()].
<<"auto-create">>, %*
<<"auto-subscribe">>, %*
<<"delete-nodes">>, %*
<<"delete-items">>, %*
<<"filtered-notifications">>, %*
<<"modify-affiliations">>, <<"outcast-affiliation">>,
<<"persistent-items">>,
<<"publish">>, %*
<<"purge-nodes">>, <<"retract-items">>,
<<"retrieve-affiliations">>,
<<"retrieve-items">>, %*
<<"retrieve-subscriptions">>, <<"subscribe">>].
-spec(create_node_permission/6 :: create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
( node_pep:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
Host :: mod_pubsub:hostPEP(),
ServerHost :: binary(),
NodeId :: mod_pubsub:nodeId(),
_ParentNodeId :: mod_pubsub:nodeId(),
Owner :: jid(),
Access :: atom())
-> {result, boolean()}
).
create_node_permission(Host, ServerHost, _NodeId, _ParentNode, Owner, Access) -> create_node(Nidx, Owner) ->
LOwner = jlib:jid_tolower(Owner), node_hometree_odbc:create_node(Nidx, Owner),
{User, Server, _Resource} = LOwner, {result, {default, broadcast}}.
Allowed = case LOwner of
{<<"">>, Host, <<"">>} ->
true; % pubsub service always allowed
_ ->
case acl:match_rule(ServerHost, Access, LOwner) of
allow ->
case Host of
{User, Server, _} -> true;
_ -> false
end;
E -> ?DEBUG("Create not allowed : ~p~n", [E]), false
end
end,
{result, Allowed}.
-spec(create_node/2 :: delete_node(Nodes) ->
( {result, {_, _, Result}} = node_hometree_odbc:delete_node(Nodes),
NodeIdx :: mod_pubsub:nodeIdx(), {result, {[], Result}}.
Owner :: jid())
-> {result, []}
).
create_node(NodeIdx, Owner) ->
case node_hometree_odbc:create_node(NodeIdx, Owner) of
{result, _} -> {result, []};
Error -> Error
end.
-spec(delete_node/1 :: subscribe_node(Nidx, Sender, Subscriber, AccessModel,
(
Removed :: [mod_pubsub:pubsubNode(),...])
-> {result,
{[],
[{mod_pubsub:pubsubNode(),
[{ljid(), [{mod_pubsub:subscription(), mod_pubsub:subId()}]}]}]
}
}
).
delete_node(Removed) ->
case node_hometree_odbc:delete_node(Removed) of
{result, {_, _, Result}} -> {result, {[], Result}};
Error -> Error
end.
-spec(subscribe_node/8 ::
(
NodeIdx :: mod_pubsub:nodeIdx(),
Sender :: jid(),
Subscriber :: ljid(),
AccessModel :: mod_pubsub:accessModel(),
SendLast :: 'never' | 'on_sub' | 'on_sub_and_presence',
PresenceSubscription :: boolean(),
RosterGroup :: boolean(),
Options :: mod_pubsub:subOptions())
-> {result, {default, subscribed, mod_pubsub:subId()}}
| {result, {default, subscribed, mod_pubsub:subId(), send_last}}
| {result, {default, pending, mod_pubsub:subId()}}
%%%
| {error, _}
| {error, _, binary()}
).
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup, Options) -> SendLast, PresenceSubscription, RosterGroup, Options) ->
node_hometree_odbc:subscribe_node(NodeId, Sender, node_hometree_odbc:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options).
PresenceSubscription, RosterGroup,
Options).
-spec(unsubscribe_node/4 :: unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
( case node_hometree_odbc:unsubscribe_node(Nidx, Sender, Subscriber, SubId) of
NodeIdx :: mod_pubsub:nodeIdx(),
Sender :: jid(),
Subscriber :: jid(),
SubId :: subId())
-> {result, []}
%
| {error, _}
| {error, _, binary()}
).
unsubscribe_node(NodeIdx, Sender, Subscriber, SubID) ->
case node_hometree_odbc:unsubscribe_node(NodeIdx, Sender, Subscriber, SubID) of
{error, Error} -> {error, Error}; {error, Error} -> {error, Error};
{result, _} -> {result, []} {result, _} -> {result, []}
end. end.
-spec(publish_item/6 :: publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
( node_hometree_odbc:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
NodeIdx :: mod_pubsub:nodeIdx(),
Publisher :: jid(),
PublishModel :: mod_pubsub:publishModel(),
Max_Items :: non_neg_integer(),
ItemId :: <<>> | mod_pubsub:itemId(),
Payload :: mod_pubsub:payload())
-> {result, {default, broadcast, [mod_pubsub:itemId()]}}
%%%
| {error, _}
).
publish_item(NodeIdx, Publisher, Model, MaxItems, ItemId, Payload) ->
node_hometree_odbc:publish_item(NodeIdx, Publisher,
Model, MaxItems, ItemId, Payload).
remove_extra_items(NodeId, MaxItems, ItemIds) -> remove_extra_items(Nidx, MaxItems, ItemIds) ->
node_hometree_odbc:remove_extra_items(NodeId, MaxItems, node_hometree_odbc:remove_extra_items(Nidx, MaxItems, ItemIds).
ItemIds).
-spec(delete_item/4 :: delete_item(Nidx, Publisher, PublishModel, ItemId) ->
( node_hometree_odbc:delete_item(Nidx, Publisher, PublishModel, ItemId).
NodeIdx :: mod_pubsub:nodeIdx(),
Publisher :: jid(),
PublishModel :: mod_pubsub:publishModel(),
ItemId :: <<>> | mod_pubsub:itemId())
-> {result, {default, broadcast}}
%%%
| {error, _}
).
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
node_hometree_odbc:delete_item(NodeId, Publisher,
PublishModel, ItemId).
-spec(purge_node/2 :: purge_node(Nidx, Owner) ->
( node_hometree_odbc:purge_node(Nidx, Owner).
NodeIdx :: mod_pubsub:nodeIdx(),
Owner :: jid())
-> {result, {default, broadcast}}
| {error, _}
).
purge_node(NodeIdx, Owner) ->
node_hometree_odbc:purge_node(NodeIdx, Owner).
-spec(get_entity_affiliations/2 ::
(
Host :: mod_pubsub:hostPubsub(),
Owner :: jid())
-> {result, [{mod_pubsub:pubsubNode(), mod_pubsub:affiliation()}]}
).
get_entity_affiliations(_Host, Owner) -> get_entity_affiliations(_Host, Owner) ->
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
node_hometree_odbc:get_entity_affiliations(OwnerKey, Owner). node_hometree_odbc:get_entity_affiliations(OwnerKey, Owner).
-spec(get_node_affiliations/1 :: get_node_affiliations(Nidx) ->
( node_hometree_odbc:get_node_affiliations(Nidx).
NodeIdx::mod_pubsub:nodeIdx())
-> {result, [{ljid(), mod_pubsub:affiliation()}]}
).
get_node_affiliations(NodeIdx) ->
node_hometree_odbc:get_node_affiliations(NodeIdx).
-spec(get_affiliation/2 :: get_affiliation(Nidx, Owner) ->
( node_hometree_odbc:get_affiliation(Nidx, Owner).
NodeIdx :: mod_pubsub:nodeIdx(),
Owner :: ljid())
-> {result, mod_pubsub:affiliation()}
).
get_affiliation(NodeIdx, Owner) ->
node_hometree_odbc:get_affiliation(NodeIdx, Owner).
set_affiliation(NodeId, Owner, Affiliation) -> set_affiliation(Nidx, Owner, Affiliation) ->
node_hometree_odbc:set_affiliation(NodeId, Owner, Affiliation). node_hometree_odbc:set_affiliation(Nidx, Owner, Affiliation).
get_entity_subscriptions(_Host, Owner) -> get_entity_subscriptions(_Host, Owner) ->
SubKey = jlib:jid_tolower(Owner), SubKey = jlib:jid_tolower(Owner),
GenKey = jlib:jid_remove_resource(SubKey), GenKey = jlib:jid_remove_resource(SubKey),
Host = (?PUBSUB):escape(element(2, SubKey)), Host = node_hometree_odbc:encode_host(element(2, SubKey)),
SJ = node_hometree_odbc:encode_jid(SubKey), SJ = node_hometree_odbc:encode_jid(SubKey),
GJ = node_hometree_odbc:encode_jid(GenKey), GJ = node_hometree_odbc:encode_jid(GenKey),
Query = case SubKey of Query = case SubKey of
GenKey -> GenKey ->
[<<"select host, node, type, i.nodeid, jid, " [<<"select host, node, type, i.nodeid, jid, "
"subscriptions from pubsub_state i, pubsub_nod" "subscriptions from pubsub_state i, pubsub_node n "
"e n where i.nodeid = n.nodeid and jid " "where i.nodeid = n.nodeid and jid "
"like '">>, "like '">>, GJ, <<"%' and host like '%@">>, Host, <<"';">>];
GJ, <<"%' and host like '%@">>, Host, <<"';">>];
_ -> _ ->
[<<"select host, node, type, i.nodeid, jid, " [<<"select host, node, type, i.nodeid, jid, "
"subscriptions from pubsub_state i, pubsub_nod" "subscriptions from pubsub_state i, pubsub_node n "
"e n where i.nodeid = n.nodeid and jid " "where i.nodeid = n.nodeid and jid "
"in ('">>, "in ('">>, SJ, <<"', '">>, GJ, <<"') and host like '%@">>, Host, <<"';">>]
SJ, <<"', '">>, GJ, <<"') and host like '%@">>, Host,
<<"';">>]
end, end,
Reply = case catch ejabberd_odbc:sql_query_t(Query) of Reply = case catch ejabberd_odbc:sql_query_t(Query) of
{selected, {selected,
[<<"host">>, <<"node">>, <<"type">>, <<"nodeid">>, [<<"host">>, <<"node">>, <<"type">>, <<"nodeid">>, <<"jid">>, <<"subscriptions">>],
<<"jid">>, <<"subscriptions">>],
RItems} -> RItems} ->
lists:map(fun ([H, N, T, I, J, S]) -> lists:map(fun ([H, N, T, I, J, S]) ->
O = node_hometree_odbc:decode_jid(H), O = node_hometree_odbc:decode_jid(H),
Node = nodetree_tree_odbc:raw_to_node(O, Node = nodetree_tree_odbc:raw_to_node(O, [N, <<"">>, T, I]),
[N,
<<"">>,
T,
I]),
{Node, {Node,
node_hometree_odbc:decode_subscriptions(S), node_hometree_odbc:decode_subscriptions(S),
node_hometree_odbc:decode_jid(J)} node_hometree_odbc:decode_jid(J)}
end, end,
RItems); RItems);
_ -> [] _ ->
[]
end, end,
{result, Reply}. {result, Reply}.
get_entity_subscriptions_for_send_last(_Host, Owner) -> get_entity_subscriptions_for_send_last(_Host, Owner) ->
SubKey = jlib:jid_tolower(Owner), SubKey = jlib:jid_tolower(Owner),
GenKey = jlib:jid_remove_resource(SubKey), GenKey = jlib:jid_remove_resource(SubKey),
Host = (?PUBSUB):escape(element(2, SubKey)), Host = node_hometree_odbc:encode_host(element(2, SubKey)),
SJ = node_hometree_odbc:encode_jid(SubKey), SJ = node_hometree_odbc:encode_jid(SubKey),
GJ = node_hometree_odbc:encode_jid(GenKey), GJ = node_hometree_odbc:encode_jid(GenKey),
Query = case SubKey of Query = case SubKey of
GenKey -> GenKey ->
[<<"select host, node, type, i.nodeid, jid, " [<<"select host, node, type, i.nodeid, jid, "
"subscriptions from pubsub_state i, pubsub_nod" "subscriptions from pubsub_state i, pubsub_node n, "
"e n, pubsub_node_option o where i.nodeid " "pubsub_node_option o where i.nodeid = n.nodeid "
"= n.nodeid and n.nodeid = o.nodeid and " "and n.nodeid = o.nodeid and name='send_last_published_item' and "
"name='send_last_published_item' and " "val='on_sub_and_presence' and jid like '">>,
"val='on_sub_and_presence' and jid like "
"'">>,
GJ, <<"%' and host like '%@">>, Host, <<"';">>]; GJ, <<"%' and host like '%@">>, Host, <<"';">>];
_ -> _ ->
[<<"select host, node, type, i.nodeid, jid, " [<<"select host, node, type, i.nodeid, jid, "
"subscriptions from pubsub_state i, pubsub_nod" "subscriptions from pubsub_state i, pubsub_node n, "
"e n, pubsub_node_option o where i.nodeid " "pubsub_node_option o where i.nodeid = n.nodeid "
"= n.nodeid and n.nodeid = o.nodeid and " "and n.nodeid = o.nodeid and name='send_last_published_item' and "
"name='send_last_published_item' and " "val='on_sub_and_presence' and jid in ",
"val='on_sub_and_presence' and jid in " "('">>, SJ, <<"', '">>, GJ, <<"') and host like '%@">>, Host, <<"';">>]
"('">>,
SJ, <<"', '">>, GJ, <<"') and host like '%@">>, Host,
<<"';">>]
end, end,
Reply = case catch ejabberd_odbc:sql_query_t(Query) of Reply = case catch ejabberd_odbc:sql_query_t(Query) of
{selected, {selected,
[<<"host">>, <<"node">>, <<"type">>, <<"nodeid">>, [<<"host">>, <<"node">>, <<"type">>, <<"nodeid">>, <<"jid">>, <<"subscriptions">>],
<<"jid">>, <<"subscriptions">>],
RItems} -> RItems} ->
lists:map(fun ([H, N, T, I, J, S]) -> lists:map(fun ([H, N, T, I, J, S]) ->
O = node_hometree_odbc:decode_jid(H), O = node_hometree_odbc:decode_jid(H),
Node = nodetree_tree_odbc:raw_to_node(O, Node = nodetree_tree_odbc:raw_to_node(O, [N, <<"">>, T, I]),
[N,
<<"">>,
T,
I]),
{Node, {Node,
node_hometree_odbc:decode_subscriptions(S), node_hometree_odbc:decode_subscriptions(S),
node_hometree_odbc:decode_jid(J)} node_hometree_odbc:decode_jid(J)}
end, end,
RItems); RItems);
_ -> [] _ ->
[]
end, end,
{result, Reply}. {result, Reply}.
get_node_subscriptions(NodeId) -> get_node_subscriptions(Nidx) ->
node_hometree_odbc:get_node_subscriptions(NodeId). node_hometree_odbc:get_node_subscriptions(Nidx).
get_subscriptions(NodeId, Owner) -> get_subscriptions(Nidx, Owner) ->
node_hometree_odbc:get_subscriptions(NodeId, Owner). node_hometree_odbc:get_subscriptions(Nidx, Owner).
set_subscriptions(NodeId, Owner, Subscription, SubId) -> set_subscriptions(Nidx, Owner, Subscription, SubId) ->
node_hometree_odbc:set_subscriptions(NodeId, Owner, node_hometree_odbc:set_subscriptions(Nidx, Owner, Subscription, SubId).
Subscription, SubId).
get_pending_nodes(Host, Owner) -> get_pending_nodes(Host, Owner) ->
node_hometree_odbc:get_pending_nodes(Host, Owner). node_hometree_odbc:get_pending_nodes(Host, Owner).
get_states(NodeId) -> get_states(Nidx) ->
node_hometree_odbc:get_states(NodeId). node_hometree_odbc:get_states(Nidx).
get_state(NodeId, JID) -> get_state(Nidx, JID) ->
node_hometree_odbc:get_state(NodeId, JID). node_hometree_odbc:get_state(Nidx, JID).
set_state(State) -> node_hometree_odbc:set_state(State). set_state(State) ->
node_hometree_odbc:set_state(State).
get_items(NodeId, From) -> get_items(Nidx, From, RSM) ->
node_hometree_odbc:get_items(NodeId, From). node_hometree_odbc:get_items(Nidx, From, RSM).
get_items(NodeId, From, RSM) -> get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
node_hometree_odbc:get_items(NodeId, From, RSM). node_hometree_odbc:get_items(Nidx, JID, AccessModel,
get_items(NodeId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId) ->
get_items(NodeId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId, none).
get_items(NodeId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId, RSM) ->
node_hometree_odbc:get_items(NodeId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId, RSM). PresenceSubscription, RosterGroup, SubId, RSM).
get_last_items(NodeId, JID, Count) -> get_last_items(Nidx, JID, Count) ->
node_hometree_odbc:get_last_items(NodeId, JID, Count). node_hometree_odbc:get_last_items(Nidx, JID, Count).
get_item(NodeId, ItemId) -> get_item(Nidx, ItemId) ->
node_hometree_odbc:get_item(NodeId, ItemId). node_hometree_odbc:get_item(Nidx, ItemId).
get_item(NodeId, ItemId, JID, AccessModel, get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
PresenceSubscription, RosterGroup, SubId) -> node_hometree_odbc:get_item(Nidx, ItemId, JID, AccessModel,
node_hometree_odbc:get_item(NodeId, ItemId, JID, PresenceSubscription, RosterGroup, SubId).
AccessModel, PresenceSubscription, RosterGroup,
SubId).
set_item(Item) -> node_hometree_odbc:set_item(Item). set_item(Item) ->
node_hometree_odbc:set_item(Item).
get_item_name(Host, Node, Id) -> get_item_name(Host, Node, Id) ->
node_hometree_odbc:get_item_name(Host, Node, Id). node_hometree_odbc:get_item_name(Host, Node, Id).
node_to_path(Node) -> node_flat_odbc:node_to_path(Node). node_to_path(Node) ->
node_flat_odbc:node_to_path(Node).
path_to_node(Path) -> node_flat_odbc:path_to_node(Path). path_to_node(Path) ->
node_flat_odbc:path_to_node(Path).
%%% %%%
%%% Internal %%% Internal
@ -433,16 +244,11 @@ path_to_node(Path) -> node_flat_odbc:path_to_node(Path).
%% Check that the mod_caps module is enabled in that Jabber Host %% Check that the mod_caps module is enabled in that Jabber Host
%% If not, show a warning message in the ejabberd log file. %% If not, show a warning message in the ejabberd log file.
complain_if_modcaps_disabled(ServerHost) -> complain_if_modcaps_disabled(ServerHost) ->
Modules = ejabberd_config:get_option({modules, case gen_mod:is_loaded(ServerHost, mod_caps) of
ServerHost}, false ->
fun(Ms) when is_list(Ms) -> Ms end),
ModCaps = [mod_caps_enabled
|| {mod_caps, _Opts} <- Modules],
case ModCaps of
[] ->
?WARNING_MSG("The PEP plugin is enabled in mod_pubsub " ?WARNING_MSG("The PEP plugin is enabled in mod_pubsub "
"of host ~p. This plugin requires mod_caps " "of host ~p. This plugin requires mod_caps "
"to be enabled, but it isn't.", "to be enabled, but it isn't.",
[ServerHost]); [ServerHost]);
_ -> ok true -> ok
end. end.

View File

@ -17,33 +17,20 @@
%%% All Rights Reserved.'' %%% All Rights Reserved.''
%%% This software is copyright 2006-2015, ProcessOne. %%% This software is copyright 2006-2015, ProcessOne.
%%% %%%
%%%
%%% @copyright 2006-2015 ProcessOne %%% @copyright 2006-2015 ProcessOne
%%% @author Christophe romain <christophe.romain@process-one.net> %%% @author Christophe Romain <christophe.romain@process-one.net>
%%% [http://www.process-one.net/] %%% [http://www.process-one.net/]
%%% @version {@vsn}, {@date} {@time} %%% @version {@vsn}, {@date} {@time}
%%% @end %%% @end
%%% ==================================================================== %%% ====================================================================
-module(node_private). -module(node_private).
-behaviour(gen_pubsub_node).
-author('christophe.romain@process-one.net'). -author('christophe.romain@process-one.net').
-include("pubsub.hrl"). -include("pubsub.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
-behaviour(gen_pubsub_node).
%% Note on function definition
%% included is all defined plugin function
%% it's possible not to define some function at all
%% in that case, warning will be generated at compilation
%% and function call will fail,
%% then mod_pubsub will call function from node_hometree
%% (this makes code cleaner, but execution a little bit longer)
%% API definition
-export([init/3, terminate/2, options/0, features/0, -export([init/3, terminate/2, options/0, features/0,
create_node_permission/6, create_node/2, delete_node/1, create_node_permission/6, create_node/2, delete_node/1,
purge_node/2, subscribe_node/8, unsubscribe_node/4, purge_node/2, subscribe_node/8, unsubscribe_node/4,
@ -53,7 +40,7 @@
get_entity_subscriptions/2, get_node_subscriptions/1, get_entity_subscriptions/2, get_node_subscriptions/1,
get_subscriptions/2, set_subscriptions/4, get_subscriptions/2, set_subscriptions/4,
get_pending_nodes/2, get_states/1, get_state/2, get_pending_nodes/2, get_states/1, get_state/2,
set_state/1, get_items/6, get_items/2, get_item/7, set_state/1, get_items/7, get_items/3, get_item/7,
get_item/2, set_item/1, get_item_name/3, node_to_path/1, get_item/2, set_item/1, get_item_name/3, node_to_path/1,
path_to_node/1]). path_to_node/1]).
@ -64,11 +51,16 @@ terminate(Host, ServerHost) ->
node_hometree:terminate(Host, ServerHost). node_hometree:terminate(Host, ServerHost).
options() -> options() ->
[{deliver_payloads, true}, {notify_config, false}, [{deliver_payloads, true},
{notify_delete, false}, {notify_retract, true}, {notify_config, false},
{purge_offline, false}, {persist_items, true}, {notify_delete, false},
{max_items, ?MAXITEMS}, {subscribe, true}, {notify_retract, true},
{access_model, whitelist}, {roster_groups_allowed, []}, {purge_offline, false},
{persist_items, true},
{max_items, ?MAXITEMS},
{subscribe, true},
{access_model, whitelist},
{roster_groups_allowed, []},
{publish_model, publishers}, {publish_model, publishers},
{notification_type, headline}, {notification_type, headline},
{max_payload_size, ?MAX_PAYLOAD_SIZE}, {max_payload_size, ?MAX_PAYLOAD_SIZE},
@ -77,108 +69,108 @@ options() ->
{presence_based_delivery, false}]. {presence_based_delivery, false}].
features() -> features() ->
[<<"create-nodes">>, <<"delete-nodes">>, [<<"create-nodes">>,
<<"delete-items">>, <<"instant-nodes">>, <<"delete-nodes">>,
<<"outcast-affiliation">>, <<"persistent-items">>, <<"delete-items">>,
<<"publish">>, <<"purge-nodes">>, <<"retract-items">>, <<"instant-nodes">>,
<<"retrieve-affiliations">>, <<"retrieve-items">>, <<"outcast-affiliation">>,
<<"retrieve-subscriptions">>, <<"subscribe">>, <<"persistent-items">>,
<<"publish">>,
<<"purge-nodes">>,
<<"retract-items">>,
<<"retrieve-affiliations">>,
<<"retrieve-items">>,
<<"retrieve-subscriptions">>,
<<"subscribe">>,
<<"subscription-notifications">>]. <<"subscription-notifications">>].
create_node_permission(Host, ServerHost, Node, create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
ParentNode, Owner, Access) -> node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
node_hometree:create_node_permission(Host, ServerHost,
Node, ParentNode, Owner, Access).
create_node(NodeId, Owner) -> create_node(Nidx, Owner) ->
node_hometree:create_node(NodeId, Owner). node_hometree:create_node(Nidx, Owner).
delete_node(Removed) -> delete_node(Removed) ->
node_hometree:delete_node(Removed). node_hometree:delete_node(Removed).
subscribe_node(NodeId, Sender, Subscriber, AccessModel, subscribe_node(Nidx, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup, Options) -> SendLast, PresenceSubscription, RosterGroup, Options) ->
node_hometree:subscribe_node(NodeId, Sender, Subscriber, node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
AccessModel, SendLast, PresenceSubscription, PresenceSubscription, RosterGroup, Options).
RosterGroup, Options).
unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
node_hometree:unsubscribe_node(NodeId, Sender, node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
Subscriber, SubID).
publish_item(NodeId, Publisher, Model, MaxItems, ItemId, publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
Payload) -> node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
node_hometree:publish_item(NodeId, Publisher, Model,
MaxItems, ItemId, Payload).
remove_extra_items(NodeId, MaxItems, ItemIds) -> remove_extra_items(Nidx, MaxItems, ItemIds) ->
node_hometree:remove_extra_items(NodeId, MaxItems, node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
ItemIds).
delete_item(NodeId, Publisher, PublishModel, ItemId) -> delete_item(Nidx, Publisher, PublishModel, ItemId) ->
node_hometree:delete_item(NodeId, Publisher, node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
PublishModel, ItemId).
purge_node(NodeId, Owner) -> purge_node(Nidx, Owner) ->
node_hometree:purge_node(NodeId, Owner). node_hometree:purge_node(Nidx, Owner).
get_entity_affiliations(Host, Owner) -> get_entity_affiliations(Host, Owner) ->
node_hometree:get_entity_affiliations(Host, Owner). node_hometree:get_entity_affiliations(Host, Owner).
get_node_affiliations(NodeId) -> get_node_affiliations(Nidx) ->
node_hometree:get_node_affiliations(NodeId). node_hometree:get_node_affiliations(Nidx).
get_affiliation(NodeId, Owner) -> get_affiliation(Nidx, Owner) ->
node_hometree:get_affiliation(NodeId, Owner). node_hometree:get_affiliation(Nidx, Owner).
set_affiliation(NodeId, Owner, Affiliation) -> set_affiliation(Nidx, Owner, Affiliation) ->
node_hometree:set_affiliation(NodeId, Owner, node_hometree:set_affiliation(Nidx, Owner, Affiliation).
Affiliation).
get_entity_subscriptions(Host, Owner) -> get_entity_subscriptions(Host, Owner) ->
node_hometree:get_entity_subscriptions(Host, Owner). node_hometree:get_entity_subscriptions(Host, Owner).
get_node_subscriptions(NodeId) -> get_node_subscriptions(Nidx) ->
node_hometree:get_node_subscriptions(NodeId). node_hometree:get_node_subscriptions(Nidx).
get_subscriptions(NodeId, Owner) -> get_subscriptions(Nidx, Owner) ->
node_hometree:get_subscriptions(NodeId, Owner). node_hometree:get_subscriptions(Nidx, Owner).
set_subscriptions(NodeId, Owner, Subscription, SubId) -> set_subscriptions(Nidx, Owner, Subscription, SubId) ->
node_hometree:set_subscriptions(NodeId, Owner, node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
Subscription, SubId).
get_pending_nodes(Host, Owner) -> get_pending_nodes(Host, Owner) ->
node_hometree:get_pending_nodes(Host, Owner). node_hometree:get_pending_nodes(Host, Owner).
get_states(NodeId) -> node_hometree:get_states(NodeId). get_states(Nidx) ->
node_hometree:get_states(Nidx).
get_state(NodeId, JID) -> get_state(Nidx, JID) ->
node_hometree:get_state(NodeId, JID). node_hometree:get_state(Nidx, JID).
set_state(State) -> node_hometree:set_state(State). set_state(State) ->
node_hometree:set_state(State).
get_items(NodeId, From) -> get_items(Nidx, From, RSM) ->
node_hometree:get_items(NodeId, From). node_hometree:get_items(Nidx, From, RSM).
get_items(NodeId, JID, AccessModel, get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
PresenceSubscription, RosterGroup, SubId) -> node_hometree:get_items(Nidx, JID, AccessModel,
node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM).
get_item(Nidx, ItemId) ->
node_hometree:get_item(Nidx, ItemId).
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId). PresenceSubscription, RosterGroup, SubId).
get_item(NodeId, ItemId) -> set_item(Item) ->
node_hometree:get_item(NodeId, ItemId). node_hometree:set_item(Item).
get_item(NodeId, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId).
set_item(Item) -> node_hometree:set_item(Item).
get_item_name(Host, Node, Id) -> get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id). node_hometree:get_item_name(Host, Node, Id).
node_to_path(Node) -> node_flat:node_to_path(Node). node_to_path(Node) ->
node_flat:node_to_path(Node).
path_to_node(Path) -> node_flat:path_to_node(Path). path_to_node(Path) ->
node_flat:path_to_node(Path).

View File

@ -17,33 +17,20 @@
%%% All Rights Reserved.'' %%% All Rights Reserved.''
%%% This software is copyright 2006-2015, ProcessOne. %%% This software is copyright 2006-2015, ProcessOne.
%%% %%%
%%%
%%% @copyright 2006-2015 ProcessOne %%% @copyright 2006-2015 ProcessOne
%%% @author Christophe romain <christophe.romain@process-one.net> %%% @author Christophe Romain <christophe.romain@process-one.net>
%%% [http://www.process-one.net/] %%% [http://www.process-one.net/]
%%% @version {@vsn}, {@date} {@time} %%% @version {@vsn}, {@date} {@time}
%%% @end %%% @end
%%% ==================================================================== %%% ====================================================================
-module(node_public). -module(node_public).
-behaviour(gen_pubsub_node).
-author('christophe.romain@process-one.net'). -author('christophe.romain@process-one.net').
-include("pubsub.hrl"). -include("pubsub.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
-behaviour(gen_pubsub_node).
%% Note on function definition
%% included is all defined plugin function
%% it's possible not to define some function at all
%% in that case, warning will be generated at compilation
%% and function call will fail,
%% then mod_pubsub will call function from node_hometree
%% (this makes code cleaner, but execution a little bit longer)
%% API definition
-export([init/3, terminate/2, options/0, features/0, -export([init/3, terminate/2, options/0, features/0,
create_node_permission/6, create_node/2, delete_node/1, create_node_permission/6, create_node/2, delete_node/1,
purge_node/2, subscribe_node/8, unsubscribe_node/4, purge_node/2, subscribe_node/8, unsubscribe_node/4,
@ -53,7 +40,7 @@
get_entity_subscriptions/2, get_node_subscriptions/1, get_entity_subscriptions/2, get_node_subscriptions/1,
get_subscriptions/2, set_subscriptions/4, get_subscriptions/2, set_subscriptions/4,
get_pending_nodes/2, get_states/1, get_state/2, get_pending_nodes/2, get_states/1, get_state/2,
set_state/1, get_items/6, get_items/2, get_item/7, set_state/1, get_items/7, get_items/3, get_item/7,
get_item/2, set_item/1, get_item_name/3, node_to_path/1, get_item/2, set_item/1, get_item_name/3, node_to_path/1,
path_to_node/1]). path_to_node/1]).
@ -64,11 +51,16 @@ terminate(Host, ServerHost) ->
node_hometree:terminate(Host, ServerHost). node_hometree:terminate(Host, ServerHost).
options() -> options() ->
[{deliver_payloads, true}, {notify_config, false}, [{deliver_payloads, true},
{notify_delete, false}, {notify_retract, true}, {notify_config, false},
{purge_offline, false}, {persist_items, true}, {notify_delete, false},
{max_items, ?MAXITEMS}, {subscribe, true}, {notify_retract, true},
{access_model, open}, {roster_groups_allowed, []}, {purge_offline, false},
{persist_items, true},
{max_items, ?MAXITEMS},
{subscribe, true},
{access_model, open},
{roster_groups_allowed, []},
{publish_model, publishers}, {publish_model, publishers},
{notification_type, headline}, {notification_type, headline},
{max_payload_size, ?MAX_PAYLOAD_SIZE}, {max_payload_size, ?MAX_PAYLOAD_SIZE},
@ -77,110 +69,108 @@ options() ->
{presence_based_delivery, false}]. {presence_based_delivery, false}].
features() -> features() ->
[<<"create-nodes">>, <<"delete-nodes">>, [<<"create-nodes">>,
<<"delete-items">>, <<"instant-nodes">>, <<"delete-nodes">>,
<<"outcast-affiliation">>, <<"persistent-items">>, <<"delete-items">>,
<<"publish">>, <<"purge-nodes">>, <<"retract-items">>, <<"instant-nodes">>,
<<"retrieve-affiliations">>, <<"retrieve-items">>, <<"outcast-affiliation">>,
<<"retrieve-subscriptions">>, <<"subscribe">>, <<"persistent-items">>,
<<"publish">>,
<<"purge-nodes">>,
<<"retract-items">>,
<<"retrieve-affiliations">>,
<<"retrieve-items">>,
<<"retrieve-subscriptions">>,
<<"subscribe">>,
<<"subscription-notifications">>]. <<"subscription-notifications">>].
create_node_permission(Host, ServerHost, Node, create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
ParentNode, Owner, Access) -> node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
node_hometree:create_node_permission(Host, ServerHost,
Node, ParentNode, Owner, Access).
create_node(NodeId, Owner) -> create_node(Nidx, Owner) ->
node_hometree:create_node(NodeId, Owner). node_hometree:create_node(Nidx, Owner).
delete_node(Removed) -> delete_node(Removed) ->
node_hometree:delete_node(Removed). node_hometree:delete_node(Removed).
subscribe_node(NodeId, Sender, Subscriber, AccessModel, subscribe_node(Nidx, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup, Options) -> SendLast, PresenceSubscription, RosterGroup, Options) ->
node_hometree:subscribe_node(NodeId, Sender, Subscriber, node_hometree:subscribe_node(Nidx, Sender, Subscriber, AccessModel, SendLast,
AccessModel, SendLast, PresenceSubscription, PresenceSubscription, RosterGroup, Options).
RosterGroup, Options).
unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
node_hometree:unsubscribe_node(NodeId, Sender, node_hometree:unsubscribe_node(Nidx, Sender, Subscriber, SubId).
Subscriber, SubID).
publish_item(NodeId, Publisher, Model, MaxItems, ItemId, publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload) ->
Payload) -> node_hometree:publish_item(Nidx, Publisher, Model, MaxItems, ItemId, Payload).
node_hometree:publish_item(NodeId, Publisher, Model,
MaxItems, ItemId, Payload).
remove_extra_items(NodeId, MaxItems, ItemIds) -> remove_extra_items(Nidx, MaxItems, ItemIds) ->
node_hometree:remove_extra_items(NodeId, MaxItems, node_hometree:remove_extra_items(Nidx, MaxItems, ItemIds).
ItemIds).
delete_item(NodeId, Publisher, PublishModel, ItemId) -> delete_item(Nidx, Publisher, PublishModel, ItemId) ->
node_hometree:delete_item(NodeId, Publisher, node_hometree:delete_item(Nidx, Publisher, PublishModel, ItemId).
PublishModel, ItemId).
purge_node(NodeId, Owner) -> purge_node(Nidx, Owner) ->
node_hometree:purge_node(NodeId, Owner). node_hometree:purge_node(Nidx, Owner).
get_entity_affiliations(Host, Owner) -> get_entity_affiliations(Host, Owner) ->
node_hometree:get_entity_affiliations(Host, Owner). node_hometree:get_entity_affiliations(Host, Owner).
get_node_affiliations(NodeId) -> get_node_affiliations(Nidx) ->
node_hometree:get_node_affiliations(NodeId). node_hometree:get_node_affiliations(Nidx).
get_affiliation(NodeId, Owner) -> get_affiliation(Nidx, Owner) ->
node_hometree:get_affiliation(NodeId, Owner). node_hometree:get_affiliation(Nidx, Owner).
set_affiliation(NodeId, Owner, Affiliation) -> set_affiliation(Nidx, Owner, Affiliation) ->
node_hometree:set_affiliation(NodeId, Owner, node_hometree:set_affiliation(Nidx, Owner, Affiliation).
Affiliation).
get_entity_subscriptions(Host, Owner) -> get_entity_subscriptions(Host, Owner) ->
node_hometree:get_entity_subscriptions(Host, Owner). node_hometree:get_entity_subscriptions(Host, Owner).
get_node_subscriptions(NodeId) -> get_node_subscriptions(Nidx) ->
node_hometree:get_node_subscriptions(NodeId). node_hometree:get_node_subscriptions(Nidx).
get_subscriptions(NodeId, Owner) -> get_subscriptions(Nidx, Owner) ->
node_hometree:get_subscriptions(NodeId, Owner). node_hometree:get_subscriptions(Nidx, Owner).
set_subscriptions(NodeId, Owner, Subscription, SubId) -> set_subscriptions(Nidx, Owner, Subscription, SubId) ->
node_hometree:set_subscriptions(NodeId, Owner, node_hometree:set_subscriptions(Nidx, Owner, Subscription, SubId).
Subscription, SubId).
get_pending_nodes(Host, Owner) -> get_pending_nodes(Host, Owner) ->
node_hometree:get_pending_nodes(Host, Owner). node_hometree:get_pending_nodes(Host, Owner).
get_states(NodeId) -> node_hometree:get_states(NodeId). get_states(Nidx) ->
node_hometree:get_states(Nidx).
get_state(NodeId, JID) -> get_state(Nidx, JID) ->
node_hometree:get_state(NodeId, JID). node_hometree:get_state(Nidx, JID).
set_state(State) -> node_hometree:set_state(State). set_state(State) ->
node_hometree:set_state(State).
get_items(NodeId, From) -> get_items(Nidx, From, RSM) ->
node_hometree:get_items(NodeId, From). node_hometree:get_items(Nidx, From, RSM).
get_items(NodeId, JID, AccessModel, get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) ->
PresenceSubscription, RosterGroup, SubId) -> node_hometree:get_items(Nidx, JID, AccessModel,
node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM).
get_item(Nidx, ItemId) ->
node_hometree:get_item(Nidx, ItemId).
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_item(Nidx, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId). PresenceSubscription, RosterGroup, SubId).
get_item(NodeId, ItemId) -> set_item(Item) ->
node_hometree:get_item(NodeId, ItemId). node_hometree:set_item(Item).
get_item(NodeId, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId) ->
node_hometree:get_item(NodeId, ItemId, JID, AccessModel,
PresenceSubscription, RosterGroup, SubId).
set_item(Item) -> node_hometree:set_item(Item).
%% @doc <p>Return the name of the node if known: Default is to return
%% node id.</p>
get_item_name(Host, Node, Id) -> get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id). node_hometree:get_item_name(Host, Node, Id).
node_to_path(Node) -> node_flat:node_to_path(Node). node_to_path(Node) ->
node_flat:node_to_path(Node).
path_to_node(Path) -> node_flat:path_to_node(Path). path_to_node(Path) ->
node_flat:path_to_node(Path).

View File

@ -5,175 +5,111 @@
%%% Erlang Public License along with this software. If not, it can be %%% Erlang Public License along with this software. If not, it can be
%%% retrieved via the world wide web at http://www.erlang.org/. %%% retrieved via the world wide web at http://www.erlang.org/.
%%% %%%
%%%
%%% Software distributed under the License is distributed on an "AS IS" %%% Software distributed under the License is distributed on an "AS IS"
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%%% the License for the specific language governing rights and limitations %%% the License for the specific language governing rights and limitations
%%% under the License. %%% under the License.
%%% %%%
%%%
%%% @author Brian Cully <bjc@kublai.com> %%% @author Brian Cully <bjc@kublai.com>
%%% @version {@vsn}, {@date} {@time} %%% @version {@vsn}, {@date} {@time}
%%% @end %%% @end
%%% ==================================================================== %%% ====================================================================
-module(nodetree_dag). -module(nodetree_dag).
-behaviour(gen_pubsub_nodetree).
-author('bjc@kublai.com'). -author('bjc@kublai.com').
%% API -include_lib("stdlib/include/qlc.hrl").
-include("pubsub.hrl").
-include("jlib.hrl").
-export([init/3, terminate/2, options/0, set_node/1, -export([init/3, terminate/2, options/0, set_node/1,
get_node/3, get_node/2, get_node/1, get_nodes/2, get_node/3, get_node/2, get_node/1, get_nodes/2,
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3, get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
get_subnodes/3, get_subnodes_tree/3, create_node/6, get_subnodes/3, get_subnodes_tree/3, create_node/6,
delete_node/2]). delete_node/2]).
-include_lib("stdlib/include/qlc.hrl").
-include("ejabberd.hrl").
-include("logger.hrl").
-include("pubsub.hrl").
-include("jlib.hrl").
-behaviour(gen_pubsub_nodetree).
-define(DEFAULT_NODETYPE, leaf). -define(DEFAULT_NODETYPE, leaf).
-define(DEFAULT_PARENTS, []). -define(DEFAULT_PARENTS, []).
-define(DEFAULT_CHILDREN, []). -define(DEFAULT_CHILDREN, []).
-compile(export_all).
%%====================================================================
%% API
%%====================================================================
init(Host, ServerHost, Opts) -> init(Host, ServerHost, Opts) ->
nodetree_tree:init(Host, ServerHost, Opts). nodetree_tree:init(Host, ServerHost, Opts).
terminate(Host, ServerHost) -> terminate(Host, ServerHost) ->
nodetree_tree:terminate(Host, ServerHost). nodetree_tree:terminate(Host, ServerHost).
-spec(create_node/6 :: set_node(#pubsub_node{nodeid = {Key, _}, owners = Owners, options = Options} = Node) ->
( Parents = find_opt(collection, ?DEFAULT_PARENTS, Options),
Key :: mod_pubsub:hostPubsub(), case validate_parentage(Key, Owners, Parents) of
NodeID :: mod_pubsub:nodeId(), true -> mnesia:write(Node#pubsub_node{parents = Parents});
Type :: binary(), Other -> Other
Owner :: jid(), end.
Options :: mod_pubsub:nodeOptions(),
Parents :: [mod_pubsub:nodeId()]) create_node(Key, Node, Type, Owner, Options, Parents) ->
-> {ok, NodeIdx::mod_pubsub:nodeIdx()}
| {error, xmlel()}
).
create_node(Key, NodeID, Type, Owner, Options, Parents) ->
OwnerJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), OwnerJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
case find_node(Key, NodeID) of case find_node(Key, Node) of
false -> false ->
NodeIdx = pubsub_index:new(node), Nidx = pubsub_index:new(node),
N = #pubsub_node{nodeid = oid(Key, NodeID), id = NodeIdx, N = #pubsub_node{nodeid = oid(Key, Node), id = Nidx,
type = Type, parents = Parents, owners = [OwnerJID], type = Type, parents = Parents, owners = [OwnerJID],
options = Options}, options = Options},
case set_node(N) of case set_node(N) of
ok -> {ok, NodeIdx}; ok -> {ok, Nidx};
Other -> Other Other -> Other
end; end;
_ -> {error, ?ERR_CONFLICT} _ ->
{error, ?ERR_CONFLICT}
end. end.
-spec(set_node/1 :: delete_node(Key, Node) ->
( case find_node(Key, Node) of
PubsubNode::mod_pubsub:pubsubNode()) false ->
-> ok {error, ?ERR_ITEM_NOT_FOUND};
%%% Record ->
| {error, xmlel()} lists:foreach(fun (#pubsub_node{options = Opts} = Child) ->
). NewOpts = remove_config_parent(Node, Opts),
set_node(#pubsub_node{nodeid = {Key, _}, owners = Owners, options = Options} = Parents = find_opt(collection, ?DEFAULT_PARENTS, NewOpts),
Node) ->
Parents = find_opt(collection, ?DEFAULT_PARENTS, Options),
case validate_parentage(Key, Owners, Parents) of
true ->
mnesia:write(Node#pubsub_node{parents = Parents});
Other -> Other
end.
-spec(delete_node/2 ::
(
Key :: mod_pubsub:hostPubsub(),
NodeID :: mod_pubsub:nodeId())
-> [mod_pubsub:pubsubNode(),...]
%%%
| {error, xmlel()}
).
delete_node(Key, NodeID) ->
case find_node(Key, NodeID) of
false -> {error, ?ERR_ITEM_NOT_FOUND};
Node ->
lists:foreach(fun (#pubsub_node{options = Opts} =
Child) ->
NewOpts = remove_config_parent(NodeID, Opts),
Parents = find_opt(collection, ?DEFAULT_PARENTS,
NewOpts),
ok = mnesia:write(pubsub_node, ok = mnesia:write(pubsub_node,
Child#pubsub_node{parents = Child#pubsub_node{parents = Parents,
Parents, options = NewOpts},
options =
NewOpts},
write) write)
end, end,
get_subnodes(Key, NodeID)), get_subnodes(Key, Node)),
pubsub_index:free(node, Node#pubsub_node.id), pubsub_index:free(node, Record#pubsub_node.id),
mnesia:delete_object(pubsub_node, Node, write), mnesia:delete_object(pubsub_node, Record, write),
[Node] [Record]
end. end.
options() -> nodetree_tree:options(). options() ->
nodetree_tree:options().
get_node(Host, NodeID, _From) -> get_node(Host, NodeID). get_node(Host, Node, _From) ->
get_node(Host, Node).
-spec(get_node/2 :: get_node(Host, Node) ->
( case find_node(Host, Node) of
Host :: mod_pubsub:hostPubsub(),
NodeID :: mod_pubsub:nodeId())
-> mod_pubsub:pubsubNode()
%%%
| {error, xmlel}
).
get_node(Host, NodeID) ->
case find_node(Host, NodeID) of
false -> {error, ?ERR_ITEM_NOT_FOUND}; false -> {error, ?ERR_ITEM_NOT_FOUND};
Node -> Node Record -> Record
end. end.
-spec(get_node/1 :: get_node(Node) ->
( nodetree_tree:get_node(Node).
NodeIdx::mod_pubsub:nodeIdx())
-> mod_pubsub:pubsubNode()
| {error, xmlel()}
).
get_node(NodeId) -> nodetree_tree:get_node(NodeId).
get_nodes(Key, From) -> get_nodes(Key, From) ->
nodetree_tree:get_nodes(Key, From). nodetree_tree:get_nodes(Key, From).
-spec(get_nodes/1 :: get_nodes(Key) ->
( nodetree_tree:get_nodes(Key).
Host::mod_pubsub:host())
-> [mod_pubsub:pubsubNode()]
).
get_nodes(Key) -> nodetree_tree:get_nodes(Key).
-spec(get_parentnodes/3 :: get_parentnodes(Host, Node, _From) ->
( case find_node(Host, Node) of
Host :: mod_pubsub:hostPubsub(), false ->
NodeID :: mod_pubsub:nodeId(), {error, ?ERR_ITEM_NOT_FOUND};
_From :: _)
-> [mod_pubsub:pubsubNode()]
%%%
| {error, xmlel()}
).
get_parentnodes(Host, NodeID, _From) ->
case find_node(Host, NodeID) of
false -> {error, ?ERR_ITEM_NOT_FOUND};
#pubsub_node{parents = Parents} -> #pubsub_node{parents = Parents} ->
Q = qlc:q([N Q = qlc:q([N
|| #pubsub_node{nodeid = {NHost, NNode}} = N || #pubsub_node{nodeid = {NHost, NNode}} = N
@ -182,53 +118,41 @@ get_parentnodes(Host, NodeID, _From) ->
qlc:e(Q) qlc:e(Q)
end. end.
get_parentnodes_tree(Host, NodeID, _From) -> get_parentnodes_tree(Host, Node, _From) ->
Pred = fun (NID, #pubsub_node{nodeid = {_, NNodeID}}) -> Pred = fun (NID, #pubsub_node{nodeid = {_, NNode}}) ->
NID == NNodeID NID == NNode
end, end,
Tr = fun (#pubsub_node{parents = Parents}) -> Parents Tr = fun (#pubsub_node{parents = Parents}) -> Parents
end, end,
traversal_helper(Pred, Tr, Host, [NodeID]). traversal_helper(Pred, Tr, Host, [Node]).
get_subnodes(Host, NodeID, _From) -> get_subnodes(Host, Node, _From) ->
get_subnodes(Host, NodeID). get_subnodes(Host, Node).
-spec(get_subnodes/2 ::
(
Host :: mod_pubsub:hostPubsub(),
NodeId :: mod_pubsub:nodeId())
-> [mod_pubsub:pubsubNode()]
).
get_subnodes(Host, <<>>) -> get_subnodes(Host, <<>>) ->
get_subnodes_helper(Host, <<>>); get_subnodes_helper(Host, <<>>);
get_subnodes(Host, NodeID) -> get_subnodes(Host, Node) ->
case find_node(Host, NodeID) of case find_node(Host, Node) of
false -> {error, ?ERR_ITEM_NOT_FOUND}; false -> {error, ?ERR_ITEM_NOT_FOUND};
_ -> get_subnodes_helper(Host, NodeID) _ -> get_subnodes_helper(Host, Node)
end. end.
-spec(get_subnodes_helper/2 :: get_subnodes_helper(Host, Node) ->
( Q = qlc:q([N
Host :: mod_pubsub:hostPubsub(),
NodeID :: mod_pubsub:nodeId())
-> [mod_pubsub:pubsubNode()]
).
get_subnodes_helper(Host, NodeID) ->
Q = qlc:q([Node
|| #pubsub_node{nodeid = {NHost, _}, || #pubsub_node{nodeid = {NHost, _},
parents = Parents} = parents = Parents} =
Node N
<- mnesia:table(pubsub_node), <- mnesia:table(pubsub_node),
Host == NHost, lists:member(NodeID, Parents)]), Host == NHost, lists:member(Node, Parents)]),
qlc:e(Q). qlc:e(Q).
get_subnodes_tree(Host, NodeID, From) -> get_subnodes_tree(Host, Node, From) ->
Pred = fun (NID, #pubsub_node{parents = Parents}) -> Pred = fun (NID, #pubsub_node{parents = Parents}) ->
lists:member(NID, Parents) lists:member(NID, Parents)
end, end,
Tr = fun (#pubsub_node{nodeid = {_, N}}) -> [N] end, Tr = fun (#pubsub_node{nodeid = {_, N}}) -> [N] end,
traversal_helper(Pred, Tr, 1, Host, [NodeID], traversal_helper(Pred, Tr, 1, Host, [Node],
[{0, [get_node(Host, NodeID, From)]}]). [{0, [get_node(Host, Node, From)]}]).
%%==================================================================== %%====================================================================
%% Internal functions %% Internal functions
@ -236,15 +160,15 @@ get_subnodes_tree(Host, NodeID, From) ->
oid(Key, Name) -> {Key, Name}. oid(Key, Name) -> {Key, Name}.
%% Key = jlib:jid() | host() %% Key = jlib:jid() | host()
%% NodeID = string() %% Node = string()
-spec(find_node/2 :: -spec(find_node/2 ::
( (
Key :: mod_pubsub:hostPubsub(), Key :: mod_pubsub:hostPubsub(),
NodeID :: mod_pubsub:nodeId()) Node :: mod_pubsub:nodeId())
-> mod_pubsub:pubsubNode() | false -> mod_pubsub:pubsubNode() | false
). ).
find_node(Key, NodeID) -> find_node(Key, Node) ->
case mnesia:read(pubsub_node, oid(Key, NodeID), read) of case mnesia:read(pubsub_node, oid(Key, Node), read) of
[] -> false; [] -> false;
[Node] -> Node [Node] -> Node
end. end.
@ -263,53 +187,52 @@ find_opt(Key, Default, Options) ->
Pred :: fun(), Pred :: fun(),
Tr :: fun(), Tr :: fun(),
Host :: mod_pubsub:hostPubsub(), Host :: mod_pubsub:hostPubsub(),
NodeId :: [mod_pubsub:pubsubNode(),...]) Nodes :: [mod_pubsub:nodeId(),...])
-> [{Depth::non_neg_integer(), Nodes::[mod_pubsub:pubsubNode(),...]}] -> [{Depth::non_neg_integer(), Nodes::[mod_pubsub:pubsubNode(),...]}]
). ).
traversal_helper(Pred, Tr, Host, Nodes) ->
traversal_helper(Pred, Tr, Host, NodeIDs) -> traversal_helper(Pred, Tr, 0, Host, Nodes, []).
traversal_helper(Pred, Tr, 0, Host, NodeIDs, []).
traversal_helper(_Pred, _Tr, _Depth, _Host, [], Acc) -> traversal_helper(_Pred, _Tr, _Depth, _Host, [], Acc) ->
Acc; Acc;
traversal_helper(Pred, Tr, Depth, Host, NodeIDs, Acc) -> traversal_helper(Pred, Tr, Depth, Host, Nodes, Acc) ->
Q = qlc:q([Node Q = qlc:q([N
|| #pubsub_node{nodeid = {NHost, _}} = Node || #pubsub_node{nodeid = {NHost, _}} = N
<- mnesia:table(pubsub_node), <- mnesia:table(pubsub_node),
NodeID <- NodeIDs, Host == NHost, Pred(NodeID, Node)]), Node <- Nodes, Host == NHost, Pred(Node, N)]),
Nodes = qlc:e(Q), Nodes = qlc:e(Q),
IDs = lists:flatmap(Tr, Nodes), IDs = lists:flatmap(Tr, Nodes),
traversal_helper(Pred, Tr, Depth + 1, Host, IDs, traversal_helper(Pred, Tr, Depth + 1, Host, IDs, [{Depth, Nodes} | Acc]).
[{Depth, Nodes} | Acc]).
remove_config_parent(NodeID, Options) -> remove_config_parent(Node, Options) ->
remove_config_parent(NodeID, Options, []). remove_config_parent(Node, Options, []).
remove_config_parent(_NodeID, [], Acc) -> remove_config_parent(_Node, [], Acc) ->
lists:reverse(Acc); lists:reverse(Acc);
remove_config_parent(NodeID, [{collection, Parents} | T], Acc) -> remove_config_parent(Node, [{collection, Parents} | T], Acc) ->
remove_config_parent(NodeID, T, remove_config_parent(Node, T, [{collection, lists:delete(Node, Parents)} | Acc]);
[{collection, lists:delete(NodeID, Parents)} | Acc]); remove_config_parent(Node, [H | T], Acc) ->
remove_config_parent(NodeID, [H | T], Acc) -> remove_config_parent(Node, T, [H | Acc]).
remove_config_parent(NodeID, T, [H | Acc]).
-spec(validate_parentage/3 :: -spec(validate_parentage/3 ::
( (
Key :: mod_pubsub:hostPubsub(), Key :: mod_pubsub:hostPubsub(),
Owners :: [ljid(),...], Owners :: [ljid(),...],
Parent_NodeIds :: [mod_pubsub:nodeId()]) Parent_Nodes :: [mod_pubsub:nodeId()])
-> true -> true
%%% %%%
| {error, xmlel()} | {error, xmlel()}
). ).
validate_parentage(_Key, _Owners, []) -> true; validate_parentage(_Key, _Owners, []) ->
true;
validate_parentage(Key, Owners, [[] | T]) -> validate_parentage(Key, Owners, [[] | T]) ->
validate_parentage(Key, Owners, T); validate_parentage(Key, Owners, T);
validate_parentage(Key, Owners, [<<>> | T]) -> validate_parentage(Key, Owners, [<<>> | T]) ->
validate_parentage(Key, Owners, T); validate_parentage(Key, Owners, T);
validate_parentage(Key, Owners, [ParentID | T]) -> validate_parentage(Key, Owners, [ParentID | T]) ->
case find_node(Key, ParentID) of case find_node(Key, ParentID) of
false -> {error, ?ERR_ITEM_NOT_FOUND}; false ->
{error, ?ERR_ITEM_NOT_FOUND};
#pubsub_node{owners = POwners, options = POptions} -> #pubsub_node{owners = POwners, options = POptions} ->
NodeType = find_opt(node_type, ?DEFAULT_NODETYPE, POptions), NodeType = find_opt(node_type, ?DEFAULT_NODETYPE, POptions),
MutualOwners = [O || O <- Owners, PO <- POwners, O == PO], MutualOwners = [O || O <- Owners, PO <- POwners, O == PO],
@ -319,12 +242,3 @@ validate_parentage(Key, Owners, [ParentID | T]) ->
{_, _} -> {error, ?ERR_NOT_ALLOWED} {_, _} -> {error, ?ERR_NOT_ALLOWED}
end end
end. end.
%% @spec (Host) -> jid()
%% Host = host()
%% @doc <p>Generate pubsub service JID.</p>
service_jid(Host) ->
case Host of
{U, S, _} -> jlib:make_jid(U, S, <<>>);
_ -> jlib:make_jid(<<>>, Host, <<>>)
end.

View File

@ -36,36 +36,20 @@
%%% improvements.</p> %%% improvements.</p>
-module(nodetree_tree). -module(nodetree_tree).
-behaviour(gen_pubsub_nodetree).
-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("pubsub.hrl"). -include("pubsub.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
-behaviour(gen_pubsub_nodetree).
-export([init/3, terminate/2, options/0, set_node/1, -export([init/3, terminate/2, options/0, set_node/1,
get_node/3, get_node/2, get_node/1, get_nodes/2, get_node/3, get_node/2, get_node/1, get_nodes/2,
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3, get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
get_subnodes/3, get_subnodes_tree/3, create_node/6, get_subnodes/3, get_subnodes_tree/3, create_node/6,
delete_node/2]). delete_node/2]).
%% ================
%% API definition
%% ================
%% @spec (Host, ServerHost, Options) -> ok
%% Host = string()
%% ServerHost = string()
%% Options = [{atom(), term()}]
%% @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>
init(_Host, _ServerHost, _Options) -> init(_Host, _ServerHost, _Options) ->
mnesia:create_table(pubsub_node, mnesia:create_table(pubsub_node,
[{disc_copies, [node()]}, [{disc_copies, [node()]},
@ -78,119 +62,51 @@ init(_Host, _ServerHost, _Options) ->
end, end,
%% mnesia:transform_table(pubsub_state, ignore, StatesFields) %% mnesia:transform_table(pubsub_state, ignore, StatesFields)
ok. ok.
%% @spec (Host, ServerHost) -> ok
%% Host = string()
%% ServerHost = string()
%% @spec () -> Options terminate(_Host, _ServerHost) ->
%% Options = [mod_pubsub:nodeOption()] ok.
%% @doc Returns the default pubsub node tree options.
terminate(_Host, _ServerHost) -> ok.
options() -> [{virtual_tree, false}]. options() ->
[{virtual_tree, false}].
%% @spec (Node) -> ok | {error, Reason}
%% Node = mod_pubsub:pubsubNode()
%% Reason = mod_pubsub:stanzaError()
-spec(set_node/1 ::
(
Node::mod_pubsub:pubsubNode())
-> ok
).
set_node(Node) when is_record(Node, pubsub_node) -> set_node(Node) when is_record(Node, pubsub_node) ->
mnesia:write(Node). mnesia:write(Node).
%set_node(_) -> {error, ?ERR_INTERNAL_SERVER_ERROR}.
get_node(Host, Node, _From) -> get_node(Host, Node). get_node(Host, Node, _From) ->
get_node(Host, Node).
%% @spec (Host, NodeId) -> Node | {error, Reason} get_node(Host, Node) ->
%% Host = mod_pubsub:host() case catch mnesia:read({pubsub_node, {Host, Node}}) of
%% NodeId = mod_pubsub:nodeId()
%% Node = mod_pubsub:pubsubNode()
%% Reason = mod_pubsub:stanzaError()
-spec(get_node/2 ::
(
Host :: mod_pubsub:host(),
NodeId :: mod_pubsub:nodeId())
-> mod_pubsub:pubsubNode()
| {error, xmlel()}
).
get_node(Host, NodeId) ->
case catch mnesia:read({pubsub_node, {Host, NodeId}}) of
[Record] when is_record(Record, pubsub_node) -> Record; [Record] when is_record(Record, pubsub_node) -> Record;
[] -> {error, ?ERR_ITEM_NOT_FOUND} _ -> {error, ?ERR_ITEM_NOT_FOUND}
% Error -> Error
end. end.
-spec(get_node/1 :: get_node(Nidx) ->
( case catch mnesia:index_read(pubsub_node, Nidx, #pubsub_node.id) of
NodeIdx::mod_pubsub:nodeIdx())
-> mod_pubsub:pubsubNode()
| {error, xmlel()}
).
get_node(NodeIdx) ->
case catch mnesia:index_read(pubsub_node, NodeIdx, #pubsub_node.id) of
[Record] when is_record(Record, pubsub_node) -> Record; [Record] when is_record(Record, pubsub_node) -> Record;
[] -> {error, ?ERR_ITEM_NOT_FOUND} _ -> {error, ?ERR_ITEM_NOT_FOUND}
% Error -> Error
end. end.
get_nodes(Host, _From) -> get_nodes(Host). get_nodes(Host, _From) ->
get_nodes(Host).
%% @spec (Host) -> Nodes | {error, Reason}
%% Host = mod_pubsub:host()
%% Nodes = [mod_pubsub:pubsubNode()]
%% Reason = {aborted, atom()}
-spec(get_nodes/1 ::
(
Host::mod_pubsub:host())
-> [mod_pubsub:pubsubNode()]
).
get_nodes(Host) -> get_nodes(Host) ->
mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, _ = '_'}). mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, _ = '_'}).
%% @spec (Host, Node, From) -> [] get_parentnodes(_Host, _Node, _From) ->
%% Host = mod_pubsub:host() [].
%% NodeId = mod_pubsub:nodeId()
%% From = mod_pubsub:jid()
%% @doc <p>Default node tree does not handle parents, return empty list.</p>
get_parentnodes(_Host, _NodeId, _From) -> [].
%% @spec (Host, NodeId, From) -> [{Depth, Node}] | []
%% Host = mod_pubsub:host()
%% NodeId = mod_pubsub:nodeId()
%% From = mod_pubsub:jid()
%% Depth = integer()
%% Node = mod_pubsub:pubsubNode()
%% @doc <p>Default node tree does not handle parents, return a list %% @doc <p>Default node tree does not handle parents, return a list
%% containing just this node.</p> %% containing just this node.</p>
-spec(get_parentnodes_tree/3 :: get_parentnodes_tree(Host, Node, _From) ->
( case catch mnesia:read({pubsub_node, {Host, Node}}) of
Host :: mod_pubsub:host(), [Record] when is_record(Record, pubsub_node) -> [{0, [Record]}];
NodeId :: mod_pubsub:nodeId(), _ -> []
From :: jid())
-> [{0, [mod_pubsub:pubsubNode(),...]}]
).
get_parentnodes_tree(Host, NodeId, From) ->
case get_node(Host, NodeId, From) of
Node when is_record(Node, pubsub_node) -> [{0, [Node]}];
_Error -> []
end. end.
%% @spec (Host, NodeId, From) -> Nodes get_subnodes(Host, Node, _From) ->
%% Host = mod_pubsub:host() get_subnodes(Host, Node).
%% NodeId = mod_pubsub:nodeId()
%% From = mod_pubsub:jid()
%% Nodes = [mod_pubsub:pubsubNode()]
get_subnodes(Host, NodeId, _From) ->
get_subnodes(Host, NodeId).
-spec(get_subnodes/2 ::
(
Host :: mod_pubsub:host(),
NodeId :: mod_pubsub:nodeId())
-> [mod_pubsub:pubsubNode()]
).
get_subnodes(Host, <<>>) -> get_subnodes(Host, <<>>) ->
Q = qlc:q([N Q = qlc:q([N
|| #pubsub_node{nodeid = {NHost, _}, || #pubsub_node{nodeid = {NHost, _},
@ -211,25 +127,15 @@ get_subnodes(Host, Node) ->
get_subnodes_tree(Host, Node, _From) -> get_subnodes_tree(Host, Node, _From) ->
get_subnodes_tree(Host, Node). get_subnodes_tree(Host, Node).
%% @spec (Host, NodeId) -> Nodes get_subnodes_tree(Host, Node) ->
%% Host = mod_pubsub:host() case get_node(Host, Node) of
%% NodeId = mod_pubsub:nodeId() {error, _} ->
%% Nodes = [] | [mod_pubsub:pubsubNode()] [];
-spec(get_subnodes_tree/2 ::
(
Host :: mod_pubsub:host(),
NodeId :: mod_pubsub:nodeId())
-> [mod_pubsub:pubsubNode()]
).
get_subnodes_tree(Host, NodeId) ->
case get_node(Host, NodeId) of
{error, _} -> [];
Rec -> Rec ->
BasePlugin = jlib:binary_to_atom(<<"node_", BasePlugin = jlib:binary_to_atom(<<"node_",
(Rec#pubsub_node.type)/binary>>), (Rec#pubsub_node.type)/binary>>),
BasePath = BasePlugin:node_to_path(NodeId), BasePath = BasePlugin:node_to_path(Node),
mnesia:foldl(fun (#pubsub_node{nodeid = {H, N}} = R, mnesia:foldl(fun (#pubsub_node{nodeid = {H, N}} = R, Acc) ->
Acc) ->
Plugin = jlib:binary_to_atom(<<"node_", Plugin = jlib:binary_to_atom(<<"node_",
(R#pubsub_node.type)/binary>>), (R#pubsub_node.type)/binary>>),
Path = Plugin:node_to_path(N), Path = Plugin:node_to_path(N),
@ -241,31 +147,9 @@ get_subnodes_tree(Host, NodeId) ->
[], pubsub_node) [], pubsub_node)
end. end.
%% @spec (Host, NodeId, Type, Owner, Options, Parents) -> create_node(Host, Node, Type, Owner, Options, Parents) ->
%% {ok, NodeIdx} | {error, Reason}
%% Host = mod_pubsub:host()
%% NodeId = mod_pubsub:nodeId()
%% Type = mod_pubsub:nodeType()
%% Owner = mod_pubsub:jid()
%% Options = [mod_pubsub:nodeOption()]
%% Parents = [] | [mod_pubsub:nodeId()]
%% NodeIdx = mod_pubsub:nodeIdx()
%% Reason = mod_pubsub:stanzaError()
-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, xmlel()}
).
create_node(Host, NodeId, Type, Owner, Options, Parents) ->
BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
case catch mnesia:read({pubsub_node, {Host, NodeId}}) of case catch mnesia:read({pubsub_node, {Host, Node}}) of
[] -> [] ->
ParentExists = case Host of ParentExists = case Host of
{_U, _S, _R} -> {_U, _S, _R} ->
@ -274,49 +158,41 @@ create_node(Host, NodeId, Type, Owner, Options, Parents) ->
true; true;
_ -> _ ->
case Parents of case Parents of
[] -> true; [] ->
true;
[Parent | _] -> [Parent | _] ->
case catch mnesia:read({pubsub_node, case catch mnesia:read({pubsub_node, {Host, Parent}}) of
{Host, Parent}}) [#pubsub_node{owners = [{[], Host, []}]}] ->
of
[#pubsub_node{owners =
[{[], Host, []}]}] ->
true; true;
[#pubsub_node{owners = Owners}] -> [#pubsub_node{owners = Owners}] ->
lists:member(BJID, Owners); lists:member(BJID, Owners);
_ -> false _ ->
false
end; end;
_ -> false _ ->
false
end end
end, end,
case ParentExists of case ParentExists of
true -> true ->
NodeIdx = pubsub_index:new(node), Nidx = pubsub_index:new(node),
mnesia:write(#pubsub_node{nodeid = {Host, NodeId}, mnesia:write(#pubsub_node{nodeid = {Host, Node},
id = NodeIdx, parents = Parents, id = Nidx, parents = Parents,
type = Type, owners = [BJID], type = Type, owners = [BJID],
options = Options}), options = Options}),
{ok, NodeIdx}; {ok, Nidx};
false -> {error, ?ERR_FORBIDDEN} false ->
{error, ?ERR_FORBIDDEN}
end; end;
_ -> {error, ?ERR_CONFLICT} _ ->
{error, ?ERR_CONFLICT}
end. end.
%% @spec (Host, NodeId) -> Removed delete_node(Host, Node) ->
%% Host = mod_pubsub:host() Removed = get_subnodes_tree(Host, Node),
%% NodeId = mod_pubsub:nodeId() lists:foreach(fun (#pubsub_node{nodeid = {_, SubNode}, id = SubNidx}) ->
%% Removed = [mod_pubsub:pubsubNode()] pubsub_index:free(node, SubNidx),
-spec(delete_node/2 :: mnesia:delete({pubsub_node, {Host, SubNode}})
(
Host :: mod_pubsub:host(),
NodeId :: mod_pubsub:nodeId())
-> [mod_pubsub:pubsubNode(),...]
).
delete_node(Host, NodeId) ->
Removed = get_subnodes_tree(Host, NodeId),
lists:foreach(fun (#pubsub_node{nodeid = {_, SubNodeId}, id = SubNodeIdx}) ->
pubsub_index:free(node, SubNodeIdx),
mnesia:delete({pubsub_node, {Host, SubNodeId}})
end, end,
Removed), Removed),
Removed. Removed.

View File

@ -36,20 +36,12 @@
%%% improvements.</p> %%% improvements.</p>
-module(nodetree_tree_odbc). -module(nodetree_tree_odbc).
-behaviour(gen_pubsub_nodetree).
-author('christophe.romain@process-one.net'). -author('christophe.romain@process-one.net').
-include("pubsub.hrl"). -include("pubsub.hrl").
-include("jlib.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, -export([init/3, terminate/2, options/0, set_node/1,
get_node/3, get_node/2, get_node/1, get_nodes/2, get_node/3, get_node/2, get_node/1, get_nodes/2,
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3, get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
@ -58,214 +50,169 @@
-export([raw_to_node/2]). -export([raw_to_node/2]).
%% ================ init(_Host, _ServerHost, _Opts) ->
%% API definition ok.
%% ================
%% @spec (Host, ServerHost, Opts) -> any() terminate(_Host, _ServerHost) ->
%% Host = mod_pubsub:host() ok.
%% 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. 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) -> get_node(Host, Node) ->
H = (?PUBSUB):escape(Host), H = node_hometree_odbc:encode_host(Host),
N = (?PUBSUB):escape(Node), N = ejabberd_odbc:escape(Node),
case catch case catch
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from " ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
"pubsub_node where host='">>, "pubsub_node where host='">>,
H, <<"' and node='">>, N, <<"';">>]) H, <<"' and node='">>, N, <<"';">>])
of of
{selected, {selected,
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], [<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], [RItem]} ->
[RItem]} ->
raw_to_node(Host, RItem); raw_to_node(Host, RItem);
{'EXIT', _Reason} -> {'EXIT', _Reason} ->
{error, ?ERR_INTERNAL_SERVER_ERROR}; {error, ?ERR_INTERNAL_SERVER_ERROR};
_ -> {error, ?ERR_ITEM_NOT_FOUND} _ ->
{error, ?ERR_ITEM_NOT_FOUND}
end. end.
-spec(get_node/1 :: get_node(Nidx) ->
(
NodeIdx::mod_pubsub:nodeIdx())
-> mod_pubsub:pubsubNode()
| {error, _}
).
get_node(NodeIdx) ->
case catch case catch
ejabberd_odbc:sql_query_t([<<"select host, node, parent, type from " ejabberd_odbc:sql_query_t([<<"select host, node, parent, type from "
"pubsub_node where nodeid='">>, "pubsub_node where nodeid='">>,
NodeIdx, <<"';">>]) Nidx, <<"';">>])
of of
{selected, {selected,
[<<"host">>, <<"node">>, <<"parent">>, <<"type">>], [<<"host">>, <<"node">>, <<"parent">>, <<"type">>], [[Host, Node, Parent, Type]]} ->
[[Host, Node, Parent, Type]]} -> raw_to_node(Host, [Node, Parent, Type, Nidx]);
raw_to_node(Host, [Node, Parent, Type, NodeIdx]);
{'EXIT', _Reason} -> {'EXIT', _Reason} ->
{error, ?ERR_INTERNAL_SERVER_ERROR}; {error, ?ERR_INTERNAL_SERVER_ERROR};
_ -> {error, ?ERR_ITEM_NOT_FOUND} _ ->
{error, ?ERR_ITEM_NOT_FOUND}
end. end.
%% @spec (Host, From) -> [pubsubNode()] | {error, Reason} get_nodes(Host, _From) ->
%% Host = mod_pubsub:host() | mod_pubsub:jid() get_nodes(Host).
get_nodes(Host, _From) -> get_nodes(Host).
-spec(get_nodes/1 ::
(
Host::mod_pubsub:host())
-> [mod_pubsub:pubsubNode()]
).
get_nodes(Host) -> get_nodes(Host) ->
H = (?PUBSUB):escape(Host), H = node_hometree_odbc:encode_host(Host),
case catch case catch
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from " ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
"pubsub_node where host='">>, "pubsub_node where host='">>, H, <<"';">>])
H, <<"';">>])
of of
{selected, {selected,
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], [<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], RItems} ->
RItems} -> [raw_to_node(Host, Item) || Item <- RItems];
lists:map(fun (Item) -> raw_to_node(Host, Item) end, _ ->
RItems); []
_ -> []
end. end.
%% @spec (Host, Node, From) -> [{Depth, Record}] | {error, Reason} get_parentnodes(_Host, _Node, _From) ->
%% 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()
%% @doc <p>Default node tree does not handle parents, return a list %% @doc <p>Default node tree does not handle parents, return a list
%% containing just this node.</p> %% 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) -> get_parentnodes_tree(Host, Node, From) ->
case get_node(Host, Node, From) of case get_node(Host, Node, From) of
N when is_record(N, pubsub_node) -> [{0, [N]}]; {error, _} -> [];
_Error -> [] Record -> [{0, [Record]}]
end. end.
get_subnodes(Host, Node, _From) -> get_subnodes(Host, Node, _From) ->
get_subnodes(Host, Node). 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) -> get_subnodes(Host, Node) ->
H = (?PUBSUB):escape(Host), H = node_hometree_odbc:encode_host(Host),
N = (?PUBSUB):escape(Node), N = ejabberd_odbc:escape(Node),
case catch case catch
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from " ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
"pubsub_node where host='">>, "pubsub_node where host='">>,
H, <<"' and parent='">>, N, <<"';">>]) H, <<"' and parent='">>, N, <<"';">>])
of of
{selected, {selected,
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], [<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], RItems} ->
RItems} -> [raw_to_node(Host, Item) || Item <- RItems];
lists:map(fun (Item) -> raw_to_node(Host, Item) end, _ ->
RItems); []
_ -> []
end. end.
get_subnodes_tree(Host, Node, _From) -> get_subnodes_tree(Host, Node, _From) ->
get_subnodes_tree(Host, Node). 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) -> get_subnodes_tree(Host, Node) ->
H = (?PUBSUB):escape(Host), H = node_hometree_odbc:encode_host(Host),
N = (?PUBSUB):escape(Node), N = ejabberd_odbc:escape(Node),
case catch case catch
ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from " ejabberd_odbc:sql_query_t([<<"select node, parent, type, nodeid from "
"pubsub_node where host='">>, "pubsub_node where host='">>,
H, <<"' and node like '">>, N, <<"%';">>]) H, <<"' and node like '">>, N, <<"%';">>])
of of
{selected, {selected,
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], [<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], RItems} ->
RItems} -> [raw_to_node(Host, Item) || Item <- RItems];
lists:map(fun (Item) -> raw_to_node(Host, Item) end, _ ->
RItems); []
_ -> []
end. 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) -> create_node(Host, Node, Type, Owner, Options, Parents) ->
BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
case nodeid(Host, Node) of case nodeidx(Host, Node) of
{error, ?ERR_ITEM_NOT_FOUND} -> {error, ?ERR_ITEM_NOT_FOUND} ->
ParentExists = case Host of ParentExists = case Host of
{_U, _S, _R} -> {_U, _S, _R} ->
@ -274,18 +221,20 @@ create_node(Host, Node, Type, Owner, Options, Parents) ->
true; true;
_ -> _ ->
case Parents of case Parents of
[] -> true; [] ->
true;
[Parent | _] -> [Parent | _] ->
case nodeid(Host, Parent) of case nodeidx(Host, Parent) of
{result, PNodeId} -> {result, PNode} ->
case nodeowners(PNodeId) of case nodeowners(PNode) of
[{<<>>, Host, <<>>}] -> true; [{<<>>, Host, <<>>}] -> true;
Owners -> Owners -> lists:member(BJID, Owners)
lists:member(BJID, Owners)
end; end;
_ -> false _ ->
false
end; end;
_ -> false _ ->
false
end end
end, end,
case ParentExists of case ParentExists of
@ -294,179 +243,73 @@ create_node(Host, Node, Type, Owner, Options, Parents) ->
parents = Parents, type = Type, parents = Parents, type = Type,
options = Options}) options = Options})
of of
{result, NodeId} -> {ok, NodeId}; {result, Nidx} -> {ok, Nidx};
Other -> Other Other -> Other
end; end;
false -> {error, ?ERR_FORBIDDEN} false ->
{error, ?ERR_FORBIDDEN}
end; end;
{result, _} -> {error, ?ERR_CONFLICT}; {result, _} ->
Error -> Error {error, ?ERR_CONFLICT};
Error ->
Error
end. 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) -> delete_node(Host, Node) ->
H = (?PUBSUB):escape(Host), H = node_hometree_odbc:encode_host(Host),
N = (?PUBSUB):escape(Node), N = ejabberd_odbc:escape(Node),
Removed = get_subnodes_tree(Host, Node), Removed = get_subnodes_tree(Host, Node),
catch catch ejabberd_odbc:sql_query_t([<<"delete from pubsub_node where host='">>,
ejabberd_odbc:sql_query_t([<<"delete from pubsub_node where host='">>,
H, <<"' and node like '">>, N, <<"%';">>]), H, <<"' and node like '">>, N, <<"%';">>]),
Removed. Removed.
%% helpers %% helpers
-spec(raw_to_node/2 :: raw_to_node(Host, [Node, Parent, Type, Nidx]) ->
(
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]) ->
Options = case catch Options = case catch
ejabberd_odbc:sql_query_t([<<"select name,val from pubsub_node_option " ejabberd_odbc:sql_query_t([<<"select name,val from pubsub_node_option "
"where nodeid='">>, "where nodeid='">>, Nidx, <<"';">>])
NodeIdx, <<"';">>])
of of
{selected, [<<"name">>, <<"val">>], ROptions} -> {selected, [<<"name">>, <<"val">>], ROptions} ->
DbOpts = lists:map(fun ([Key, Value]) -> DbOpts = lists:map(fun ([Key, Value]) ->
RKey = RKey = jlib:binary_to_atom(Key),
jlib:binary_to_atom(Key), Tokens = element(2, erl_scan:string(binary_to_list(<<Value/binary, ".">>))),
Tokens = element(2, RValue = element(2, erl_parse:parse_term(Tokens)),
erl_scan:string(
binary_to_list(<<Value/binary, ".">>))),
RValue = element(2,
erl_parse:parse_term(Tokens)),
{RKey, RValue} {RKey, RValue}
end, end,
ROptions), ROptions),
Module = Module = jlib:binary_to_atom(<<"node_", Type/binary, "_odbc">>),
jlib:binary_to_atom(<<(?PLUGIN_PREFIX)/binary,
Type/binary,
(?ODBC_SUFFIX)/binary>>),
StdOpts = Module:options(), StdOpts = Module:options(),
lists:foldl(fun ({Key, Value}, Acc) -> lists:foldl(fun ({Key, Value}, Acc) ->
lists:keyreplace(Key, 1, Acc, lists:keyreplace(Key, 1, Acc, {Key, Value})
{Key, Value})
end, end,
StdOpts, DbOpts); StdOpts, DbOpts);
_ -> [] _ ->
[]
end, end,
Parents = case Parent of Parents = case Parent of
<<>> -> []; <<>> -> [];
_ -> [Parent] _ -> [Parent]
end, end,
#pubsub_node{nodeid = #pubsub_node{nodeid = {Host, Node},
{Host, Node},
parents = Parents, parents = Parents,
id = NodeIdx, type = Type, options = Options}. id = Nidx, type = Type, options = Options}.
% @spec (NodeRecord) -> ok | {error, Reason} nodeidx(Host, Node) ->
%% Record = mod_pubsub:pubsub_node() H = node_hometree_odbc:encode_host(Host),
-spec(set_node/1 :: N = ejabberd_odbc:escape(Node),
(
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),
case catch case catch
ejabberd_odbc:sql_query_t([<<"select nodeid from pubsub_node where " ejabberd_odbc:sql_query_t([<<"select nodeid from pubsub_node where "
"host='">>, "host='">>,
H, <<"' and node='">>, N, <<"';">>]) H, <<"' and node='">>, N, <<"';">>])
of of
{selected, [<<"nodeid">>], [[NodeIdx]]} -> {selected, [<<"nodeid">>], [[Nidx]]} ->
{result, NodeIdx}; {result, Nidx};
{'EXIT', _Reason} -> {'EXIT', _Reason} ->
{error, ?ERR_INTERNAL_SERVER_ERROR}; {error, ?ERR_INTERNAL_SERVER_ERROR};
_ -> {error, ?ERR_ITEM_NOT_FOUND} _ ->
{error, ?ERR_ITEM_NOT_FOUND}
end. end.
-spec(nodeowners/1 :: nodeowners(Nidx) ->
( {result, Res} = node_hometree_odbc:get_node_affiliations(Nidx),
NodeIdx::mod_pubsub:nodeIdx()) [LJID || {LJID, Aff} <- Res, Aff =:= owner].
-> 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).

View File

@ -26,143 +26,84 @@
%%% ==================================================================== %%% ====================================================================
%%% @doc The module <strong>{@module}</strong> is the PubSub node tree plugin that %%% @doc The module <strong>{@module}</strong> is the PubSub node tree plugin that
%%% allow virtual nodes handling. %%% allow virtual nodes handling. This prevent storage of nodes.
%%% <p>PubSub node tree plugins are using the {@link gen_nodetree} behaviour.</p> %%% <p>PubSub node tree plugins are using the {@link gen_nodetree} behaviour.</p>
%%% <p>This plugin development is still a work in progress. Due to optimizations in %%% <p>This plugin development is still a work in progress. Due to optimizations in
%%% mod_pubsub, this plugin can not work anymore without altering functioning. %%% mod_pubsub, this plugin can not work anymore without altering functioning.
%%% Please, send us comments, feedback and improvements.</p> %%% Please, send us comments, feedback and improvements.</p>
-module(nodetree_virtual). -module(nodetree_virtual).
-behaviour(gen_pubsub_nodetree).
-author('christophe.romain@process-one.net'). -author('christophe.romain@process-one.net').
-include("pubsub.hrl"). -include("pubsub.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
-behaviour(gen_pubsub_nodetree).
-export([init/3, terminate/2, options/0, set_node/1, -export([init/3, terminate/2, options/0, set_node/1,
get_node/3, get_node/2, get_node/1, get_nodes/2, get_node/3, get_node/2, get_node/1, get_nodes/2,
get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3, get_nodes/1, get_parentnodes/3, get_parentnodes_tree/3,
get_subnodes/3, get_subnodes_tree/3, create_node/6, get_subnodes/3, get_subnodes_tree/3, create_node/6,
delete_node/2]). delete_node/2]).
%% ================ init(_Host, _ServerHost, _Opts) ->
%% API definition ok.
%% ================
%% @spec (Host, ServerHost, Opts) -> any() terminate(_Host, _ServerHost) ->
%% Host = mod_pubsub:host() ok.
%% 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 <p>Returns the default pubsub node tree options.</p>
%% @spec (NodeRecord) -> ok | {error, Reason}
%% NodeRecord = mod_pubsub:pubsub_node()
%% @doc <p>No node record is stored on database. Just do nothing.</p>
%% @spec (Host, Node, From) -> pubsubNode()
%% Host = mod_pubsub:host()
%% Node = mod_pubsub:pubsubNode()
%% From = mod_pubsub:jid()
%% @doc <p>Virtual node tree does not handle a node database. Any node is considered
%% as existing. Node record contains default values.</p>
init(_Host, _ServerHost, _Opts) -> ok.
terminate(_Host, _ServerHost) -> ok. options() ->
[{virtual_tree, true}].
options() -> [{virtual_tree, true}]. set_node(_Node) ->
ok.
set_node(_NodeRecord) -> ok. get_node(Host, Node, _From) ->
get_node(Host, Node).
get_node(Host, Node, _From) -> get_node(Host, Node). get_node(Host, Node) ->
get_node(nodeidx(Host, Node)).
get_node(Host, Node) -> get_node({Host, Node}). get_node(Nidx) ->
{Host, Node} = nodeid(Nidx),
Record = #pubsub_node{nodeid = Node, id = Nidx},
Module = jlib:binary_to_atom(<<"node_", (Record#pubsub_node.type)/binary>>),
Record#pubsub_node{owners = [{<<"">>, Host, <<"">>}],
options = Module:options()}.
get_node({Host, _} = NodeId) -> get_nodes(Host, _From) ->
Record = #pubsub_node{nodeid = NodeId, id = NodeId}, get_nodes(Host).
Module = jlib:binary_to_atom(<<"node_",
(Record#pubsub_node.type)/binary>>),
Options = Module:options(),
Owners = [{<<"">>, Host, <<"">>}],
Record#pubsub_node{owners = Owners, options = Options}.
%% @spec (Host, From) -> [pubsubNode()] get_nodes(_Host) ->
%% Host = mod_pubsub:host() | mod_pubsub:jid() [].
%% From = mod_pubsub:jid()
%% @doc <p>Virtual node tree does not handle a node database. Any node is considered
%% as existing. Nodes list can not be determined.</p>
%% @spec (Host, Node, From) -> [pubsubNode()]
%% Host = mod_pubsub:host()
%% Node = mod_pubsub:pubsubNode()
%% From = mod_pubsub:jid()
%% @doc <p>Virtual node tree does not handle parent/child. Child list is empty.</p>
%% @spec (Host, Node, From) -> [pubsubNode()]
%% Host = mod_pubsub:host()
%% Node = mod_pubsub:pubsubNode()
%% From = mod_pubsub:jid()
%% @doc <p>Virtual node tree does not handle parent/child. Child list is empty.</p>
%% @spec (Host, Node, From) -> [pubsubNode()]
%% Host = mod_pubsub:host()
%% Node = mod_pubsub:pubsubNode()
%% From = mod_pubsub:jid()
%% @doc <p>Virtual node tree does not handle parent/child. Child list is empty.</p>
get_nodes(Host, _From) -> get_nodes(Host).
get_nodes(_Host) -> []. get_parentnodes(_Host, _Node, _From) ->
[].
get_parentnodes(_Host, _Node, _From) -> []. get_parentnodes_tree(Host, Node, From) ->
case get_node(Host, Node, From) of
-spec(get_parentnodes_tree/3 ::
(
Host :: mod_pubsub:host(),
NodeId :: mod_pubsub:nodeId(),
From :: jid())
-> [{0, [mod_pubsub:pubsubNode(),...]}]
).
get_parentnodes_tree(Host, NodeId, From) ->
case get_node(Host, NodeId, From) of
Node when is_record(Node, pubsub_node) -> [{0, [Node]}]; Node when is_record(Node, pubsub_node) -> [{0, [Node]}];
_Error -> [] _Error -> []
end. end.
get_subnodes(Host, Node, _From) -> get_subnodes(Host, Node, _From) ->
get_subnodes(Host, Node). get_subnodes(Host, Node).
%% @spec (Host, Node, From) -> [pubsubNode()]
%% Host = mod_pubsub:host()
%% Node = mod_pubsub:pubsubNode()
%% From = mod_pubsub:jid()
%% @doc <p>Virtual node tree does not handle parent/child. Child list is empty.</p>
get_subnodes(_Host, _Node) -> []. get_subnodes(_Host, _Node) ->
[].
get_subnodes_tree(Host, Node, _From) -> get_subnodes_tree(Host, Node, _From) ->
get_subnodes_tree(Host, Node). get_subnodes_tree(Host, Node).
%% @spec (Host, Node, Type, Owner, Options, Parents) -> ok
%% Host = mod_pubsub:host()
%% Node = mod_pubsub:pubsubNode()
%% Type = mod_pubsub:nodeType()
%% Owner = mod_pubsub:jid()
%% Options = list()
%% @doc <p>No node record is stored on database. Any valid node
%% is considered as already created.</p>
%% <p>default allowed nodes: /home/host/user/any/node/name</p>
%% @spec (Host, Node) -> [mod_pubsub:node()]
%% Host = mod_pubsub:host()
%% Node = mod_pubsub:pubsubNode()
%% @doc <p>Virtual node tree does not handle parent/child.
%% node deletion just affects the corresponding node.</p>
get_subnodes_tree(_Host, _Node) -> []. get_subnodes_tree(_Host, _Node) ->
[].
create_node(Host, Node, _Type, _Owner, _Options, create_node(Host, Node, _Type, _Owner, _Options, _Parents) ->
_Parents) ->
{error, {virtual, {Host, Node}}}. {error, {virtual, {Host, Node}}}.
delete_node(Host, Node) -> [get_node(Host, Node)]. delete_node(Host, Node) ->
[get_node(Host, Node)].
%% internal helper
nodeidx(Host, Node) -> term_to_binary({Host, Node}).
nodeid(Nidx) -> binary_to_term(Nidx).

View File

@ -39,13 +39,10 @@ read_subscription(SubID) ->
of of
{selected, [<<"opt_name">>, <<"opt_value">>], []} -> {selected, [<<"opt_name">>, <<"opt_value">>], []} ->
notfound; notfound;
{selected, [<<"opt_name">>, <<"opt_value">>], {selected, [<<"opt_name">>, <<"opt_value">>], Options} ->
Options} ->
{ok, {ok,
#pubsub_subscription{subid = SubID, #pubsub_subscription{subid = SubID,
options = options = lists:map(fun subscription_opt_from_odbc/1, Options)}}
lists:map(fun subscription_opt_from_odbc/1,
Options)}}
end. end.
%% -spec delete_subscription(SubID :: string()) -> ok. %% -spec delete_subscription(SubID :: string()) -> ok.
@ -58,17 +55,13 @@ delete_subscription(SubID) ->
ejabberd_odbc:escape(SubID), <<"'">>]), ejabberd_odbc:escape(SubID), <<"'">>]),
ok. ok.
update_subscription(#pubsub_subscription{subid = update_subscription(#pubsub_subscription{subid = SubId} = Sub) ->
SubId} =
Sub) ->
delete_subscription(SubId), add_subscription(Sub). delete_subscription(SubId), add_subscription(Sub).
add_subscription(#pubsub_subscription{subid = SubId, add_subscription(#pubsub_subscription{subid = SubId, options = Opts}) ->
options = Opts}) ->
EscapedSubId = ejabberd_odbc:escape(SubId), EscapedSubId = ejabberd_odbc:escape(SubId),
lists:foreach(fun (Opt) -> lists:foreach(fun (Opt) ->
{OdbcOptName, OdbcOptValue} = {OdbcOptName, OdbcOptValue} = subscription_opt_to_odbc(Opt),
subscription_opt_to_odbc(Opt),
ejabberd_odbc:sql_query_t([<<"insert into pubsub_subscription_opt(subid, " ejabberd_odbc:sql_query_t([<<"insert into pubsub_subscription_opt(subid, "
"opt_name, opt_value)values ('">>, "opt_name, opt_value)values ('">>,
EscapedSubId, <<"','">>, EscapedSubId, <<"','">>,
@ -82,28 +75,23 @@ subscription_opt_from_odbc({<<"DELIVER">>, Value}) ->
{deliver, odbc_to_boolean(Value)}; {deliver, odbc_to_boolean(Value)};
subscription_opt_from_odbc({<<"DIGEST">>, Value}) -> subscription_opt_from_odbc({<<"DIGEST">>, Value}) ->
{digest, odbc_to_boolean(Value)}; {digest, odbc_to_boolean(Value)};
subscription_opt_from_odbc({<<"DIGEST_FREQUENCY">>, subscription_opt_from_odbc({<<"DIGEST_FREQUENCY">>, Value}) ->
Value}) ->
{digest_frequency, odbc_to_integer(Value)}; {digest_frequency, odbc_to_integer(Value)};
subscription_opt_from_odbc({<<"EXPIRE">>, Value}) -> subscription_opt_from_odbc({<<"EXPIRE">>, Value}) ->
{expire, odbc_to_timestamp(Value)}; {expire, odbc_to_timestamp(Value)};
subscription_opt_from_odbc({<<"INCLUDE_BODY">>, subscription_opt_from_odbc({<<"INCLUDE_BODY">>, Value}) ->
Value}) ->
{include_body, odbc_to_boolean(Value)}; {include_body, odbc_to_boolean(Value)};
%%TODO: might be > than 1 show_values value??. %%TODO: might be > than 1 show_values value??.
%% need to use compact all in only 1 opt. %% need to use compact all in only 1 opt.
subscription_opt_from_odbc({<<"SHOW_VALUES">>, subscription_opt_from_odbc({<<"SHOW_VALUES">>, Value}) ->
Value}) ->
{show_values, Value}; {show_values, Value};
subscription_opt_from_odbc({<<"SUBSCRIPTION_TYPE">>, subscription_opt_from_odbc({<<"SUBSCRIPTION_TYPE">>, Value}) ->
Value}) ->
{subscription_type, {subscription_type,
case Value of case Value of
<<"items">> -> items; <<"items">> -> items;
<<"nodes">> -> nodes <<"nodes">> -> nodes
end}; end};
subscription_opt_from_odbc({<<"SUBSCRIPTION_DEPTH">>, subscription_opt_from_odbc({<<"SUBSCRIPTION_DEPTH">>, Value}) ->
Value}) ->
{subscription_depth, {subscription_depth,
case Value of case Value of
<<"all">> -> all; <<"all">> -> all;
@ -135,8 +123,7 @@ subscription_opt_to_odbc({subscription_depth, Depth}) ->
N -> integer_to_odbc(N) N -> integer_to_odbc(N)
end}. end}.
integer_to_odbc(N) -> integer_to_odbc(N) -> iolist_to_binary(integer_to_list(N)).
iolist_to_binary(integer_to_list(N)).
boolean_to_odbc(true) -> <<"1">>; boolean_to_odbc(true) -> <<"1">>;
boolean_to_odbc(false) -> <<"0">>. boolean_to_odbc(false) -> <<"0">>.
@ -147,5 +134,4 @@ odbc_to_integer(N) -> jlib:binary_to_integer(N).
odbc_to_boolean(B) -> B == <<"1">>. odbc_to_boolean(B) -> B == <<"1">>.
odbc_to_timestamp(T) -> odbc_to_timestamp(T) -> jlib:datetime_string_to_timestamp(T).
jlib:datetime_string_to_timestamp(T).

View File

@ -29,7 +29,6 @@
%% new/1 and free/2 MUST be called inside a transaction bloc %% new/1 and free/2 MUST be called inside a transaction bloc
-module(pubsub_index). -module(pubsub_index).
-author('christophe.romain@process-one.net'). -author('christophe.romain@process-one.net').
-include("pubsub.hrl"). -include("pubsub.hrl").
@ -53,8 +52,7 @@ new(Index) ->
mnesia:write(I#pubsub_index{free = Free}), Id mnesia:write(I#pubsub_index{free = Free}), Id
end; end;
_ -> _ ->
mnesia:write(#pubsub_index{index = Index, last = 1, mnesia:write(#pubsub_index{index = Index, last = 1, free = []}),
free = []}),
1 1
end. end.
@ -63,5 +61,6 @@ free(Index, Id) ->
[I] -> [I] ->
Free = I#pubsub_index.free, Free = I#pubsub_index.free,
mnesia:write(I#pubsub_index{free = [Id | Free]}); mnesia:write(I#pubsub_index{free = [Id | Free]});
_ -> ok _ ->
ok
end. end.

422
src/pubsub_migrate.erl Normal file
View File

@ -0,0 +1,422 @@
%%%----------------------------------------------------------------------
%%% File : pubsub_migrate.erl
%%% Author : Christophe Romain <christophe.romain@process-one.net>
%%% Purpose : Migration/Upgrade code put out of mod_pubsub
%%% Created : 26 Jul 2014 by Christophe Romain <christophe.romain@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2015 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%%% 02111-1307 USA
%%%
%%%----------------------------------------------------------------------
-module(pubsub_migrate).
-include("pubsub.hrl").
-include("logger.hrl").
-export([update_node_database/2, update_state_database/2, update_lastitem_database/2]).
update_item_database_binary() ->
F = fun () ->
case catch mnesia:read({pubsub_last_item, mnesia:first(pubsub_last_item)}) of
[First] when is_list(First#pubsub_last_item.itemid) ->
?INFO_MSG("Binarization of pubsub items table...", []),
lists:foreach(fun (Id) ->
[Node] = mnesia:read({pubsub_last_item, Id}),
ItemId = iolist_to_binary(Node#pubsub_last_item.itemid),
ok = mnesia:delete({pubsub_last_item, Id}),
ok = mnesia:write(Node#pubsub_last_item{itemid=ItemId})
end,
mnesia:all_keys(pubsub_last_item));
_-> no_need
end
end,
case mnesia:transaction(F) of
{aborted, Reason} ->
?ERROR_MSG("Failed to binarize pubsub items table: ~p", [Reason]);
{atomic, no_need} ->
ok;
{atomic, Result} ->
?INFO_MSG("Pubsub items table has been binarized: ~p", [Result])
end.
update_node_database_binary() ->
F = fun () ->
case catch mnesia:read({pubsub_node, mnesia:first(pubsub_node)}) of
[First] when is_list(First#pubsub_node.type) ->
?INFO_MSG("Binarization of pubsub nodes table...", []),
lists:foreach(fun ({H, N}) ->
[Node] = mnesia:read({pubsub_node, {H, N}}),
Type = iolist_to_binary(Node#pubsub_node.type),
BN = case N of
Binary when is_binary(Binary) ->
N;
_ ->
{result, BN1} = mod_pubsub:node_call(H, Type, path_to_node, [N]),
BN1
end,
BP = case [case P of
Binary2 when is_binary(Binary2) -> P;
_ -> element(2, mod_pubsub:node_call(H, Type, path_to_node, [P]))
end
|| P <- Node#pubsub_node.parents] of
[<<>>] -> [];
Parents -> Parents
end,
BH = case H of
{U, S, R} -> {iolist_to_binary(U), iolist_to_binary(S), iolist_to_binary(R)};
String -> iolist_to_binary(String)
end,
Owners = [{iolist_to_binary(U), iolist_to_binary(S), iolist_to_binary(R)} ||
{U, S, R} <- Node#pubsub_node.owners],
ok = mnesia:delete({pubsub_node, {H, N}}),
ok = mnesia:write(Node#pubsub_node{nodeid = {BH, BN},
parents = BP,
type = Type,
owners = Owners});
(_) -> ok
end,
mnesia:all_keys(pubsub_node));
_-> no_need
end
end,
case mnesia:transaction(F) of
{aborted, Reason} ->
?ERROR_MSG("Failed to binarize pubsub node table: ~p", [Reason]);
{atomic, no_need} ->
ok;
{atomic, Result} ->
?INFO_MSG("Pubsub nodes table has been binarized: ~p", [Result])
end.
update_node_database(Host, ServerHost) ->
mnesia:del_table_index(pubsub_node, type),
mnesia:del_table_index(pubsub_node, parentid),
case catch mnesia:table_info(pubsub_node, attributes) of
[host_node, host_parent, info] ->
?INFO_MSG("Upgrading pubsub nodes table...", []),
F = fun () ->
{Result, LastIdx} = lists:foldl(fun ({pubsub_node,
NodeId, ParentId,
{nodeinfo, Items,
Options,
Entities}},
{RecList,
NodeIdx}) ->
ItemsList =
lists:foldl(fun
({item,
IID,
Publisher,
Payload},
Acc) ->
C =
{unknown,
Publisher},
M =
{now(),
Publisher},
mnesia:write(#pubsub_item{itemid
=
{IID,
NodeIdx},
creation
=
C,
modification
=
M,
payload
=
Payload}),
[{Publisher,
IID}
| Acc]
end,
[],
Items),
Owners =
dict:fold(fun
(JID,
{entity,
Aff,
Sub},
Acc) ->
UsrItems =
lists:foldl(fun
({P,
I},
IAcc) ->
case
P
of
JID ->
[I
| IAcc];
_ ->
IAcc
end
end,
[],
ItemsList),
mnesia:write({pubsub_state,
{JID,
NodeIdx},
UsrItems,
Aff,
Sub}),
case
Aff
of
owner ->
[JID
| Acc];
_ ->
Acc
end
end,
[],
Entities),
mnesia:delete({pubsub_node,
NodeId}),
{[#pubsub_node{nodeid
=
NodeId,
id
=
NodeIdx,
parents
=
[element(2,
ParentId)],
owners
=
Owners,
options
=
Options}
| RecList],
NodeIdx + 1}
end,
{[], 1},
mnesia:match_object({pubsub_node,
{Host,
'_'},
'_',
'_'})),
mnesia:write(#pubsub_index{index = node, last = LastIdx,
free = []}),
Result
end,
{atomic, NewRecords} = mnesia:transaction(F),
{atomic, ok} = mnesia:delete_table(pubsub_node),
{atomic, ok} = mnesia:create_table(pubsub_node,
[{disc_copies, [node()]},
{attributes,
record_info(fields,
pubsub_node)}]),
FNew = fun () ->
lists:foreach(fun (Record) -> mnesia:write(Record) end,
NewRecords)
end,
case mnesia:transaction(FNew) of
{atomic, Result} ->
?INFO_MSG("Pubsub nodes table upgraded: ~p",
[Result]);
{aborted, Reason} ->
?ERROR_MSG("Problem upgrading Pubsub nodes table:~n~p",
[Reason])
end;
[nodeid, parentid, type, owners, options] ->
F = fun ({pubsub_node, NodeId, {_, Parent}, Type,
Owners, Options}) ->
#pubsub_node{nodeid = NodeId, id = 0,
parents = [Parent], type = Type,
owners = Owners, options = Options}
end,
mnesia:transform_table(pubsub_node, F,
[nodeid, id, parents, type, owners, options]),
FNew = fun () ->
LastIdx = lists:foldl(fun (#pubsub_node{nodeid =
NodeId} =
PubsubNode,
NodeIdx) ->
mnesia:write(PubsubNode#pubsub_node{id
=
NodeIdx}),
lists:foreach(fun
(#pubsub_state{stateid
=
StateId} =
State) ->
{JID,
_} =
StateId,
mnesia:delete({pubsub_state,
StateId}),
mnesia:write(State#pubsub_state{stateid
=
{JID,
NodeIdx}})
end,
mnesia:match_object(#pubsub_state{stateid
=
{'_',
NodeId},
_
=
'_'})),
lists:foreach(fun
(#pubsub_item{itemid
=
ItemId} =
Item) ->
{IID,
_} =
ItemId,
{M1,
M2} =
Item#pubsub_item.modification,
{C1,
C2} =
Item#pubsub_item.creation,
mnesia:delete({pubsub_item,
ItemId}),
mnesia:write(Item#pubsub_item{itemid
=
{IID,
NodeIdx},
modification
=
{M2,
M1},
creation
=
{C2,
C1}})
end,
mnesia:match_object(#pubsub_item{itemid
=
{'_',
NodeId},
_
=
'_'})),
NodeIdx + 1
end,
1,
mnesia:match_object({pubsub_node,
{Host, '_'},
'_', '_',
'_', '_',
'_'})
++
mnesia:match_object({pubsub_node,
{{'_',
ServerHost,
'_'},
'_'},
'_', '_',
'_', '_',
'_'})),
mnesia:write(#pubsub_index{index = node,
last = LastIdx, free = []})
end,
case mnesia:transaction(FNew) of
{atomic, Result} ->
rename_default_nodeplugin(),
?INFO_MSG("Pubsub nodes table upgraded: ~p",
[Result]);
{aborted, Reason} ->
?ERROR_MSG("Problem upgrading Pubsub nodes table:~n~p",
[Reason])
end;
[nodeid, id, parent, type, owners, options] ->
F = fun ({pubsub_node, NodeId, Id, Parent, Type, Owners,
Options}) ->
#pubsub_node{nodeid = NodeId, id = Id,
parents = [Parent], type = Type,
owners = Owners, options = Options}
end,
mnesia:transform_table(pubsub_node, F,
[nodeid, id, parents, type, owners, options]),
rename_default_nodeplugin();
_ -> ok
end,
update_node_database_binary().
rename_default_nodeplugin() ->
lists:foreach(fun (Node) ->
mnesia:dirty_write(Node#pubsub_node{type =
<<"hometree">>})
end,
mnesia:dirty_match_object(#pubsub_node{type =
<<"default">>,
_ = '_'})).
update_state_database(_Host, _ServerHost) ->
case catch mnesia:table_info(pubsub_state, attributes) of
[stateid, nodeidx, items, affiliation, subscriptions] ->
?INFO_MSG("Upgrading pubsub states table...", []),
F = fun ({pubsub_state, {{U,S,R}, NodeID}, _NodeIdx, Items, Aff, Sub}, Acc) ->
JID = {iolist_to_binary(U), iolist_to_binary(S), iolist_to_binary(R)},
Subs = case Sub of
none ->
[];
[] ->
[];
_ ->
{result, SubID} = pubsub_subscription:subscribe_node(JID, NodeID, []),
[{Sub, SubID}]
end,
NewState = #pubsub_state{stateid = {JID, NodeID},
items = Items,
affiliation = Aff,
subscriptions = Subs},
[NewState | Acc]
end,
{atomic, NewRecs} = mnesia:transaction(fun mnesia:foldl/3,
[F, [], pubsub_state]),
{atomic, ok} = mnesia:delete_table(pubsub_state),
{atomic, ok} = mnesia:create_table(pubsub_state,
[{disc_copies, [node()]},
{attributes, record_info(fields, pubsub_state)}]),
FNew = fun () ->
lists:foreach(fun mnesia:write/1, NewRecs)
end,
case mnesia:transaction(FNew) of
{atomic, Result} ->
?INFO_MSG("Pubsub states table upgraded: ~p",
[Result]);
{aborted, Reason} ->
?ERROR_MSG("Problem upgrading Pubsub states table:~n~p",
[Reason])
end;
_ ->
ok
end.
update_lastitem_database(_Host, _ServerHost) ->
update_item_database_binary().

View File

@ -38,121 +38,65 @@
-include("jlib.hrl"). -include("jlib.hrl").
-define(PUBSUB_DELIVER, <<"pubsub#deliver">>). -define(PUBSUB_DELIVER, <<"pubsub#deliver">>).
-define(PUBSUB_DIGEST, <<"pubsub#digest">>). -define(PUBSUB_DIGEST, <<"pubsub#digest">>).
-define(PUBSUB_DIGEST_FREQUENCY, <<"pubsub#digest_frequency">>).
-define(PUBSUB_DIGEST_FREQUENCY,
<<"pubsub#digest_frequency">>).
-define(PUBSUB_EXPIRE, <<"pubsub#expire">>). -define(PUBSUB_EXPIRE, <<"pubsub#expire">>).
-define(PUBSUB_INCLUDE_BODY, <<"pubsub#include_body">>). -define(PUBSUB_INCLUDE_BODY, <<"pubsub#include_body">>).
-define(PUBSUB_SHOW_VALUES, <<"pubsub#show-values">>). -define(PUBSUB_SHOW_VALUES, <<"pubsub#show-values">>).
-define(PUBSUB_SUBSCRIPTION_TYPE, <<"pubsub#subscription_type">>).
-define(PUBSUB_SUBSCRIPTION_TYPE, -define(PUBSUB_SUBSCRIPTION_DEPTH, <<"pubsub#subscription_depth">>).
<<"pubsub#subscription_type">>). -define(DELIVER_LABEL, <<"Whether an entity wants to receive or disable notifications">>).
-define(DIGEST_LABEL, <<"Whether an entity wants to receive digests "
-define(PUBSUB_SUBSCRIPTION_DEPTH, "(aggregations) of notifications or all notifications individually">>).
<<"pubsub#subscription_depth">>). -define(DIGEST_FREQUENCY_LABEL, <<"The minimum number of milliseconds between "
-define(DELIVER_LABEL,
<<"Whether an entity wants to receive or "
"disable notifications">>).
-define(DIGEST_LABEL,
<<"Whether an entity wants to receive digests "
"(aggregations) of notifications or all "
"notifications individually">>).
-define(DIGEST_FREQUENCY_LABEL,
<<"The minimum number of milliseconds between "
"sending any two notification digests">>). "sending any two notification digests">>).
-define(EXPIRE_LABEL, <<"The DateTime at which a leased subscription will end or has ended">>).
-define(EXPIRE_LABEL, -define(INCLUDE_BODY_LABEL, <<"Whether an entity wants to receive an "
<<"The DateTime at which a leased subscription " "XMPP message body in addition to the payload format">>).
"will end or has ended">>). -define(SHOW_VALUES_LABEL, <<"The presence states for which an entity wants to receive notifications">>).
-define(SUBSCRIPTION_TYPE_LABEL, <<"Type of notification to receive">>).
-define(INCLUDE_BODY_LABEL, -define(SUBSCRIPTION_DEPTH_LABEL, <<"Depth from subscription for which to receive notifications">>).
<<"Whether an entity wants to receive an " -define(SHOW_VALUE_AWAY_LABEL, <<"XMPP Show Value of Away">>).
"XMPP message body in addition to the " -define(SHOW_VALUE_CHAT_LABEL, <<"XMPP Show Value of Chat">>).
"payload format">>). -define(SHOW_VALUE_DND_LABEL, <<"XMPP Show Value of DND (Do Not Disturb)">>).
-define(SHOW_VALUE_ONLINE_LABEL, <<"Mere Availability in XMPP (No Show Value)">>).
-define(SHOW_VALUES_LABEL, -define(SHOW_VALUE_XA_LABEL, <<"XMPP Show Value of XA (Extended Away)">>).
<<"The presence states for which an entity " -define(SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL, <<"Receive notification of new items only">>).
"wants to receive notifications">>). -define(SUBSCRIPTION_TYPE_VALUE_NODES_LABEL, <<"Receive notification of new nodes only">>).
-define(SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL, <<"Receive notification from direct child nodes only">>).
-define(SUBSCRIPTION_TYPE_LABEL, -define(SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL, <<"Receive notification from all descendent nodes">>).
<<"Type of notification to receive">>).
-define(SUBSCRIPTION_DEPTH_LABEL,
<<"Depth from subscription for which to "
"receive notifications">>).
-define(SHOW_VALUE_AWAY_LABEL,
<<"XMPP Show Value of Away">>).
-define(SHOW_VALUE_CHAT_LABEL,
<<"XMPP Show Value of Chat">>).
-define(SHOW_VALUE_DND_LABEL,
<<"XMPP Show Value of DND (Do Not Disturb)">>).
-define(SHOW_VALUE_ONLINE_LABEL,
<<"Mere Availability in XMPP (No Show Value)">>).
-define(SHOW_VALUE_XA_LABEL,
<<"XMPP Show Value of XA (Extended Away)">>).
-define(SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL,
<<"Receive notification of new items only">>).
-define(SUBSCRIPTION_TYPE_VALUE_NODES_LABEL,
<<"Receive notification of new nodes only">>).
-define(SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL,
<<"Receive notification from direct child "
"nodes only">>).
-define(SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL,
<<"Receive notification from all descendent "
"nodes">>).
%%==================================================================== %%====================================================================
%% API %% API
%%==================================================================== %%====================================================================
init() -> ok = create_table(). init() -> ok = create_table().
subscribe_node(JID, NodeID, Options) -> subscribe_node(JID, NodeId, Options) ->
case catch mnesia:sync_dirty(fun add_subscription/3, case catch mnesia:sync_dirty(fun add_subscription/3, [JID, NodeId, Options])
[JID, NodeID, Options])
of of
{'EXIT', {aborted, Error}} -> Error; {'EXIT', {aborted, Error}} -> Error;
{error, Error} -> {error, Error}; {error, Error} -> {error, Error};
Result -> {result, Result} Result -> {result, Result}
end. end.
unsubscribe_node(JID, NodeID, SubID) -> unsubscribe_node(JID, NodeId, SubID) ->
case catch mnesia:sync_dirty(fun delete_subscription/3, case catch mnesia:sync_dirty(fun delete_subscription/3, [JID, NodeId, SubID])
[JID, NodeID, SubID])
of of
{'EXIT', {aborted, Error}} -> Error; {'EXIT', {aborted, Error}} -> Error;
{error, Error} -> {error, Error}; {error, Error} -> {error, Error};
Result -> {result, Result} Result -> {result, Result}
end. end.
get_subscription(JID, NodeID, SubID) -> get_subscription(JID, NodeId, SubID) ->
case catch mnesia:sync_dirty(fun read_subscription/3, case catch mnesia:sync_dirty(fun read_subscription/3, [JID, NodeId, SubID])
[JID, NodeID, SubID])
of of
{'EXIT', {aborted, Error}} -> Error; {'EXIT', {aborted, Error}} -> Error;
{error, Error} -> {error, Error}; {error, Error} -> {error, Error};
Result -> {result, Result} Result -> {result, Result}
end. end.
set_subscription(JID, NodeID, SubID, Options) -> set_subscription(JID, NodeId, SubID, Options) ->
case catch mnesia:sync_dirty(fun write_subscription/4, case catch mnesia:sync_dirty(fun write_subscription/4, [JID, NodeId, SubID, Options])
[JID, NodeID, SubID, Options])
of of
{'EXIT', {aborted, Error}} -> Error; {'EXIT', {aborted, Error}} -> Error;
{error, Error} -> {error, Error}; {error, Error} -> {error, Error};
@ -161,10 +105,8 @@ set_subscription(JID, NodeID, SubID, Options) ->
get_options_xform(Lang, Options) -> get_options_xform(Lang, Options) ->
Keys = [deliver, show_values, subscription_type, Keys = [deliver, show_values, subscription_type, subscription_depth],
subscription_depth], XFields = [get_option_xfield(Lang, Key, Options) || Key <- Keys],
XFields = [get_option_xfield(Lang, Key, Options)
|| Key <- Keys],
{result, {result,
#xmlel{name = <<"x">>, #xmlel{name = <<"x">>,
attrs = [{<<"xmlns">>, ?NS_XDATA}], attrs = [{<<"xmlns">>, ?NS_XDATA}],
@ -209,39 +151,38 @@ create_table() ->
-spec(add_subscription/3 :: -spec(add_subscription/3 ::
( (
_JID :: ljid(), _JID :: ljid(),
_NodeID :: mod_pubsub:nodeIdx(), _NodeId :: mod_pubsub:nodeIdx(),
Options :: [] | mod_pubsub:subOptions()) Options :: [] | mod_pubsub:subOptions())
-> SubId :: mod_pubsub:subId() -> SubId :: mod_pubsub:subId()
). ).
add_subscription(_JID, _NodeID, []) -> make_subid(); add_subscription(_JID, _NodeId, []) -> make_subid();
add_subscription(_JID, _NodeID, Options) -> add_subscription(_JID, _NodeId, Options) ->
SubID = make_subid(), SubID = make_subid(),
mnesia:write(#pubsub_subscription{subid = SubID, mnesia:write(#pubsub_subscription{subid = SubID, options = Options}),
options = Options}),
SubID. SubID.
-spec(delete_subscription/3 :: -spec(delete_subscription/3 ::
( (
_JID :: _, _JID :: _,
_NodeID :: _, _NodeId :: _,
SubId :: mod_pubsub:subId()) SubId :: mod_pubsub:subId())
-> ok -> ok
). ).
delete_subscription(_JID, _NodeID, SubID) -> delete_subscription(_JID, _NodeId, SubID) ->
mnesia:delete({pubsub_subscription, SubID}). mnesia:delete({pubsub_subscription, SubID}).
-spec(read_subscription/3 :: -spec(read_subscription/3 ::
( (
_JID :: ljid(), _JID :: ljid(),
_NodeID :: _, _NodeId :: _,
SubID :: mod_pubsub:subId()) SubID :: mod_pubsub:subId())
-> mod_pubsub:pubsubSubscription() -> mod_pubsub:pubsubSubscription()
| {error, notfound} | {error, notfound}
). ).
read_subscription(_JID, _NodeID, SubID) -> read_subscription(_JID, _NodeId, SubID) ->
case mnesia:read({pubsub_subscription, SubID}) of case mnesia:read({pubsub_subscription, SubID}) of
[Sub] -> Sub; [Sub] -> Sub;
_ -> {error, notfound} _ -> {error, notfound}
@ -250,15 +191,14 @@ read_subscription(_JID, _NodeID, SubID) ->
-spec(write_subscription/4 :: -spec(write_subscription/4 ::
( (
_JID :: ljid(), _JID :: ljid(),
_NodeID :: _, _NodeId :: _,
SubID :: mod_pubsub:subId(), SubID :: mod_pubsub:subId(),
Options :: mod_pubsub:subOptions()) Options :: mod_pubsub:subOptions())
-> ok -> ok
). ).
write_subscription(_JID, _NodeID, SubID, Options) -> write_subscription(_JID, _NodeId, SubID, Options) ->
mnesia:write(#pubsub_subscription{subid = SubID, mnesia:write(#pubsub_subscription{subid = SubID, options = Options}).
options = Options}).
-spec(make_subid/0 :: () -> SubId::mod_pubsub:subId()). -spec(make_subid/0 :: () -> SubId::mod_pubsub:subId()).
make_subid() -> make_subid() ->
@ -285,24 +225,23 @@ set_xoption([{Var, Value} | T], Opts) ->
%% Convert Values for option list's Key. %% Convert Values for option list's Key.
var_xfield(?PUBSUB_DELIVER) -> deliver; var_xfield(?PUBSUB_DELIVER) -> deliver;
var_xfield(?PUBSUB_DIGEST) -> digest; var_xfield(?PUBSUB_DIGEST) -> digest;
var_xfield(?PUBSUB_DIGEST_FREQUENCY) -> var_xfield(?PUBSUB_DIGEST_FREQUENCY) -> digest_frequency;
digest_frequency;
var_xfield(?PUBSUB_EXPIRE) -> expire; var_xfield(?PUBSUB_EXPIRE) -> expire;
var_xfield(?PUBSUB_INCLUDE_BODY) -> include_body; var_xfield(?PUBSUB_INCLUDE_BODY) -> include_body;
var_xfield(?PUBSUB_SHOW_VALUES) -> show_values; var_xfield(?PUBSUB_SHOW_VALUES) -> show_values;
var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) -> var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) -> subscription_type;
subscription_type; var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) -> subscription_depth;
var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) ->
subscription_depth;
var_xfield(_) -> {error, badarg}. var_xfield(_) -> {error, badarg}.
val_xfield(deliver, [Val]) -> xopt_to_bool(Val); val_xfield(deliver, [Val]) -> xopt_to_bool(Val);
%val_xfield(digest, [Val]) -> xopt_to_bool(Val); val_xfield(digest, [Val]) -> xopt_to_bool(Val);
%val_xfield(digest_frequency, [Val]) -> val_xfield(digest_frequency, [Val]) ->
% jlib:binary_to_integer(Val); case catch jlib:binary_to_integer(Val) of
%val_xfield(expire, [Val]) -> N when is_integer(N) -> N;
% jlib:datetime_string_to_timestamp(Val); _ -> {error, ?ERR_NOT_ACCEPTABLE}
%val_xfield(include_body, [Val]) -> xopt_to_bool(Val); end;
val_xfield(expire, [Val]) -> jlib:datetime_string_to_timestamp(Val);
val_xfield(include_body, [Val]) -> xopt_to_bool(Val);
val_xfield(show_values, Vals) -> Vals; val_xfield(show_values, Vals) -> Vals;
val_xfield(subscription_type, [<<"items">>]) -> items; val_xfield(subscription_type, [<<"items">>]) -> items;
val_xfield(subscription_type, [<<"nodes">>]) -> nodes; val_xfield(subscription_type, [<<"nodes">>]) -> nodes;
@ -333,8 +272,7 @@ xopt_to_bool(_) -> {error, ?ERR_NOT_ACCEPTABLE}.
get_option_xfield(Lang, Key, Options) -> get_option_xfield(Lang, Key, Options) ->
Var = xfield_var(Key), Var = xfield_var(Key),
Label = xfield_label(Key), Label = xfield_label(Key),
{Type, OptEls} = type_and_options(xfield_type(Key), {Type, OptEls} = type_and_options(xfield_type(Key), Lang),
Lang),
Vals = case lists:keysearch(Key, 1, Options) of Vals = case lists:keysearch(Key, 1, Options) of
{value, {_, Val}} -> {value, {_, Val}} ->
[tr_xfield_values(Vals) [tr_xfield_values(Vals)
@ -365,30 +303,14 @@ tr_xfield_values(Value) ->
#xmlel{name = <<"value">>, attrs = [], #xmlel{name = <<"value">>, attrs = [],
children = [{xmlcdata, Value}]}. children = [{xmlcdata, Value}]}.
-spec(xfield_var/1 ::
(
Var :: 'deliver'
% | 'digest'
% | 'digest_frequency'
% | 'expire'
% | 'include_body'
| 'show_values'
| 'subscription_type'
| 'subscription_depth')
-> binary()
).
xfield_var(deliver) -> ?PUBSUB_DELIVER; xfield_var(deliver) -> ?PUBSUB_DELIVER;
%xfield_var(digest) -> ?PUBSUB_DIGEST; %xfield_var(digest) -> ?PUBSUB_DIGEST;
%xfield_var(digest_frequency) -> %xfield_var(digest_frequency) -> ?PUBSUB_DIGEST_FREQUENCY;
% ?PUBSUB_DIGEST_FREQUENCY;
%xfield_var(expire) -> ?PUBSUB_EXPIRE; %xfield_var(expire) -> ?PUBSUB_EXPIRE;
%xfield_var(include_body) -> ?PUBSUB_INCLUDE_BODY; %xfield_var(include_body) -> ?PUBSUB_INCLUDE_BODY;
xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES; xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES;
xfield_var(subscription_type) -> xfield_var(subscription_type) -> ?PUBSUB_SUBSCRIPTION_TYPE;
?PUBSUB_SUBSCRIPTION_TYPE; xfield_var(subscription_depth) -> ?PUBSUB_SUBSCRIPTION_DEPTH.
xfield_var(subscription_depth) ->
?PUBSUB_SUBSCRIPTION_DEPTH.
xfield_type(deliver) -> <<"boolean">>; xfield_type(deliver) -> <<"boolean">>;
%xfield_type(digest) -> <<"boolean">>; %xfield_type(digest) -> <<"boolean">>;
@ -414,35 +336,14 @@ xfield_type(subscription_depth) ->
%% Return the XForm variable label for a subscription option key. %% Return the XForm variable label for a subscription option key.
xfield_label(deliver) -> ?DELIVER_LABEL; xfield_label(deliver) -> ?DELIVER_LABEL;
%xfield_label(digest) -> ?DIGEST_LABEL; %xfield_label(digest) -> ?DIGEST_LABEL;
%xfield_label(digest_frequency) -> %xfield_label(digest_frequency) -> ?DIGEST_FREQUENCY_LABEL;
% ?DIGEST_FREQUENCY_LABEL;
%xfield_label(expire) -> ?EXPIRE_LABEL; %xfield_label(expire) -> ?EXPIRE_LABEL;
%xfield_label(include_body) -> ?INCLUDE_BODY_LABEL; %xfield_label(include_body) -> ?INCLUDE_BODY_LABEL;
xfield_label(show_values) -> ?SHOW_VALUES_LABEL; xfield_label(show_values) -> ?SHOW_VALUES_LABEL;
%% Return the XForm value for a subscription option key. %% Return the XForm value for a subscription option key.
%% Convert erlang booleans to XForms. %% Convert erlang booleans to XForms.
xfield_label(subscription_type) -> xfield_label(subscription_type) -> ?SUBSCRIPTION_TYPE_LABEL;
?SUBSCRIPTION_TYPE_LABEL; xfield_label(subscription_depth) -> ?SUBSCRIPTION_DEPTH_LABEL.
xfield_label(subscription_depth) ->
?SUBSCRIPTION_DEPTH_LABEL.
-spec(xfield_val/2 ::
(
Field :: 'deliver'
% | 'digest'
% | 'digest_frequency'
% | 'expire'
% | 'include_body'
| 'show_values'
| 'subscription_type'
| 'subscription_depth',
Val :: boolean()
| binary()
| integer()
| [binary()])
% | erlang:timestamp())
-> [binary()]
).
xfield_val(deliver, Val) -> [bool_to_xopt(Val)]; xfield_val(deliver, Val) -> [bool_to_xopt(Val)];
%xfield_val(digest, Val) -> [bool_to_xopt(Val)]; %xfield_val(digest, Val) -> [bool_to_xopt(Val)];
@ -450,7 +351,7 @@ xfield_val(deliver, Val) -> [bool_to_xopt(Val)];
% [iolist_to_binary(integer_to_list(Val))]; % [iolist_to_binary(integer_to_list(Val))];
%xfield_val(expire, Val) -> %xfield_val(expire, Val) ->
% [jlib:now_to_utc_string(Val)]; % [jlib:now_to_utc_string(Val)];
%%xfield_val(include_body, Val) -> [bool_to_xopt(Val)]; %xfield_val(include_body, Val) -> [bool_to_xopt(Val)];
xfield_val(show_values, Val) -> Val; xfield_val(show_values, Val) -> Val;
xfield_val(subscription_type, items) -> [<<"items">>]; xfield_val(subscription_type, items) -> [<<"items">>];
xfield_val(subscription_type, nodes) -> [<<"nodes">>]; xfield_val(subscription_type, nodes) -> [<<"nodes">>];

View File

@ -22,7 +22,6 @@
%%% ==================================================================== %%% ====================================================================
-module(pubsub_subscription_odbc). -module(pubsub_subscription_odbc).
-author("pablo.polvorin@process-one.net"). -author("pablo.polvorin@process-one.net").
%% API %% API
@ -35,85 +34,33 @@
-include("jlib.hrl"). -include("jlib.hrl").
-define(PUBSUB_DELIVER, <<"pubsub#deliver">>). -define(PUBSUB_DELIVER, <<"pubsub#deliver">>).
-define(PUBSUB_DIGEST, <<"pubsub#digest">>). -define(PUBSUB_DIGEST, <<"pubsub#digest">>).
-define(PUBSUB_DIGEST_FREQUENCY, <<"pubsub#digest_frequency">>).
-define(PUBSUB_DIGEST_FREQUENCY,
<<"pubsub#digest_frequency">>).
-define(PUBSUB_EXPIRE, <<"pubsub#expire">>). -define(PUBSUB_EXPIRE, <<"pubsub#expire">>).
-define(PUBSUB_INCLUDE_BODY, <<"pubsub#include_body">>). -define(PUBSUB_INCLUDE_BODY, <<"pubsub#include_body">>).
-define(PUBSUB_SHOW_VALUES, <<"pubsub#show-values">>). -define(PUBSUB_SHOW_VALUES, <<"pubsub#show-values">>).
-define(PUBSUB_SUBSCRIPTION_TYPE, <<"pubsub#subscription_type">>).
-define(PUBSUB_SUBSCRIPTION_TYPE, -define(PUBSUB_SUBSCRIPTION_DEPTH, <<"pubsub#subscription_depth">>).
<<"pubsub#subscription_type">>). -define(DELIVER_LABEL, <<"Whether an entity wants to receive or disable notifications">>).
-define(DIGEST_LABEL, <<"Whether an entity wants to receive digests "
-define(PUBSUB_SUBSCRIPTION_DEPTH, "(aggregations) of notifications or all notifications individually">>).
<<"pubsub#subscription_depth">>). -define(DIGEST_FREQUENCY_LABEL, <<"The minimum number of milliseconds between "
-define(DELIVER_LABEL,
<<"Whether an entity wants to receive or "
"disable notifications">>).
-define(DIGEST_LABEL,
<<"Whether an entity wants to receive digests "
"(aggregations) of notifications or all "
"notifications individually">>).
-define(DIGEST_FREQUENCY_LABEL,
<<"The minimum number of milliseconds between "
"sending any two notification digests">>). "sending any two notification digests">>).
-define(EXPIRE_LABEL, <<"The DateTime at which a leased subscription will end or has ended">>).
-define(EXPIRE_LABEL, -define(INCLUDE_BODY_LABEL, <<"Whether an entity wants to receive an "
<<"The DateTime at which a leased subscription " "XMPP message body in addition to the payload format">>).
"will end or has ended">>). -define(SHOW_VALUES_LABEL, <<"The presence states for which an entity wants to receive notifications">>).
-define(SUBSCRIPTION_TYPE_LABEL, <<"Type of notification to receive">>).
-define(INCLUDE_BODY_LABEL, -define(SUBSCRIPTION_DEPTH_LABEL, <<"Depth from subscription for which to receive notifications">>).
<<"Whether an entity wants to receive an " -define(SHOW_VALUE_AWAY_LABEL, <<"XMPP Show Value of Away">>).
"XMPP message body in addition to the " -define(SHOW_VALUE_CHAT_LABEL, <<"XMPP Show Value of Chat">>).
"payload format">>). -define(SHOW_VALUE_DND_LABEL, <<"XMPP Show Value of DND (Do Not Disturb)">>).
-define(SHOW_VALUE_ONLINE_LABEL, <<"Mere Availability in XMPP (No Show Value)">>).
-define(SHOW_VALUES_LABEL, -define(SHOW_VALUE_XA_LABEL, <<"XMPP Show Value of XA (Extended Away)">>).
<<"The presence states for which an entity " -define(SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL, <<"Receive notification of new items only">>).
"wants to receive notifications">>). -define(SUBSCRIPTION_TYPE_VALUE_NODES_LABEL, <<"Receive notification of new nodes only">>).
-define(SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL, <<"Receive notification from direct child nodes only">>).
-define(SUBSCRIPTION_TYPE_LABEL, -define(SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL, <<"Receive notification from all descendent nodes">>).
<<"Type of notification to receive">>).
-define(SUBSCRIPTION_DEPTH_LABEL,
<<"Depth from subscription for which to "
"receive notifications">>).
-define(SHOW_VALUE_AWAY_LABEL,
<<"XMPP Show Value of Away">>).
-define(SHOW_VALUE_CHAT_LABEL,
<<"XMPP Show Value of Chat">>).
-define(SHOW_VALUE_DND_LABEL,
<<"XMPP Show Value of DND (Do Not Disturb)">>).
-define(SHOW_VALUE_ONLINE_LABEL,
<<"Mere Availability in XMPP (No Show Value)">>).
-define(SHOW_VALUE_XA_LABEL,
<<"XMPP Show Value of XA (Extended Away)">>).
-define(SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL,
<<"Receive notification of new items only">>).
-define(SUBSCRIPTION_TYPE_VALUE_NODES_LABEL,
<<"Receive notification of new nodes only">>).
-define(SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL,
<<"Receive notification from direct child "
"nodes only">>).
-define(SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL,
<<"Receive notification from all descendent "
"nodes">>).
-define(DB_MOD, pubsub_db_odbc). -define(DB_MOD, pubsub_db_odbc).
%%==================================================================== %%====================================================================
@ -125,41 +72,38 @@ init() -> ok = create_table().
-spec(subscribe_node/3 :: -spec(subscribe_node/3 ::
( (
_JID :: _, _JID :: _,
_NodeID :: _, _NodeId :: _,
Options :: mod_pubsub:subOptions()) Options :: [] | mod_pubsub:subOptions())
-> {result, mod_pubsub:subId()} -> {result, mod_pubsub:subId()}
). ).
subscribe_node(_JID, _NodeID, Options) -> subscribe_node(_JID, _NodeId, Options) ->
SubID = make_subid(), SubID = make_subid(),
(?DB_MOD):add_subscription(#pubsub_subscription{subid = (?DB_MOD):add_subscription(#pubsub_subscription{subid = SubID, options = Options}),
SubID,
options = Options}),
{result, SubID}. {result, SubID}.
-spec(unsubscribe_node/3 :: -spec(unsubscribe_node/3 ::
( (
_JID :: _, _JID :: _,
_NodeID :: _, _NodeId :: _,
SubID :: mod_pubsub:subId()) SubID :: mod_pubsub:subId())
-> {result, mod_pubsub:subscription()} -> {result, mod_pubsub:subscription()}
| {error, notfound} | {error, notfound}
). ).
unsubscribe_node(_JID, _NodeID, SubID) -> unsubscribe_node(_JID, _NodeId, SubID) ->
case (?DB_MOD):read_subscription(SubID) of case (?DB_MOD):read_subscription(SubID) of
{ok, Sub} -> {ok, Sub} -> (?DB_MOD):delete_subscription(SubID), {result, Sub};
(?DB_MOD):delete_subscription(SubID), {result, Sub};
notfound -> {error, notfound} notfound -> {error, notfound}
end. end.
-spec(get_subscription/3 :: -spec(get_subscription/3 ::
( (
_JID :: _, _JID :: _,
_NodeID :: _, _NodeId :: _,
SubId :: mod_pubsub:subId()) SubId :: mod_pubsub:subId())
-> {result, mod_pubsub:subscription()} -> {result, mod_pubsub:subscription()}
| {error, notfound} | {error, notfound}
). ).
get_subscription(_JID, _NodeID, SubID) -> get_subscription(_JID, _NodeId, SubID) ->
case (?DB_MOD):read_subscription(SubID) of case (?DB_MOD):read_subscription(SubID) of
{ok, Sub} -> {result, Sub}; {ok, Sub} -> {result, Sub};
notfound -> {error, notfound} notfound -> {error, notfound}
@ -168,30 +112,26 @@ get_subscription(_JID, _NodeID, SubID) ->
-spec(set_subscription/4 :: -spec(set_subscription/4 ::
( (
_JID :: _, _JID :: _,
_NodeID :: _, _NodeId :: _,
SubId :: mod_pubsub:subId(), SubId :: mod_pubsub:subId(),
Options :: mod_pubsub:subOptions()) Options :: mod_pubsub:subOptions())
-> {result, ok} -> {result, ok}
). ).
set_subscription(_JID, _NodeID, SubID, Options) -> set_subscription(_JID, _NodeId, SubID, Options) ->
case (?DB_MOD):read_subscription(SubID) of case (?DB_MOD):read_subscription(SubID) of
{ok, _} -> {ok, _} ->
(?DB_MOD):update_subscription(#pubsub_subscription{subid (?DB_MOD):update_subscription(#pubsub_subscription{subid = SubID,
= SubID, options = Options}),
options =
Options}),
{result, ok}; {result, ok};
notfound -> notfound ->
(?DB_MOD):add_subscription(#pubsub_subscription{subid = (?DB_MOD):add_subscription(#pubsub_subscription{subid = SubID,
SubID,
options = Options}), options = Options}),
{result, ok} {result, ok}
end. end.
get_options_xform(Lang, Options) -> get_options_xform(Lang, Options) ->
Keys = [deliver, show_values, subscription_type, subscription_depth], Keys = [deliver, show_values, subscription_type, subscription_depth],
XFields = [get_option_xfield(Lang, Key, Options) XFields = [get_option_xfield(Lang, Key, Options) || Key <- Keys],
|| Key <- Keys],
{result, {result,
#xmlel{name = <<"x">>, #xmlel{name = <<"x">>,
attrs = [{<<"xmlns">>, ?NS_XDATA}], attrs = [{<<"xmlns">>, ?NS_XDATA}],
@ -247,25 +187,24 @@ set_xoption([{Var, Value} | T], Opts) ->
%% Return the options list's key for an XForm var. %% Return the options list's key for an XForm var.
%% Convert Values for option list's Key. %% Convert Values for option list's Key.
var_xfield(?PUBSUB_DELIVER) -> deliver; var_xfield(?PUBSUB_DELIVER) -> deliver;
%var_xfield(?PUBSUB_DIGEST) -> digest; var_xfield(?PUBSUB_DIGEST) -> digest;
%var_xfield(?PUBSUB_DIGEST_FREQUENCY) -> var_xfield(?PUBSUB_DIGEST_FREQUENCY) -> digest_frequency;
% digest_frequency; var_xfield(?PUBSUB_EXPIRE) -> expire;
%var_xfield(?PUBSUB_EXPIRE) -> expire; var_xfield(?PUBSUB_INCLUDE_BODY) -> include_body;
%var_xfield(?PUBSUB_INCLUDE_BODY) -> include_body;
var_xfield(?PUBSUB_SHOW_VALUES) -> show_values; var_xfield(?PUBSUB_SHOW_VALUES) -> show_values;
var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) -> var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) -> subscription_type;
subscription_type; var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) -> subscription_depth;
var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) ->
subscription_depth;
var_xfield(_) -> {error, badarg}. var_xfield(_) -> {error, badarg}.
val_xfield(deliver, [Val]) -> xopt_to_bool(Val); val_xfield(deliver, [Val]) -> xopt_to_bool(Val);
%val_xfield(digest, [Val]) -> xopt_to_bool(Val); val_xfield(digest, [Val]) -> xopt_to_bool(Val);
%val_xfield(digest_frequency, [Val]) -> val_xfield(digest_frequency, [Val]) ->
% jlib:binary_to_integer(Val); case catch jlib:binary_to_integer(Val) of
%val_xfield(expire, [Val]) -> N when is_integer(N) -> N;
% jlib:datetime_string_to_timestamp(Val); _ -> {error, ?ERR_NOT_ACCEPTABLE}
%val_xfield(include_body, [Val]) -> xopt_to_bool(Val); end;
val_xfield(expire, [Val]) -> jlib:datetime_string_to_timestamp(Val);
val_xfield(include_body, [Val]) -> xopt_to_bool(Val);
val_xfield(show_values, Vals) -> Vals; val_xfield(show_values, Vals) -> Vals;
val_xfield(subscription_type, [<<"items">>]) -> items; val_xfield(subscription_type, [<<"items">>]) -> items;
val_xfield(subscription_type, [<<"nodes">>]) -> nodes; val_xfield(subscription_type, [<<"nodes">>]) -> nodes;
@ -288,8 +227,7 @@ xopt_to_bool(_) -> {error, ?ERR_NOT_ACCEPTABLE}.
get_option_xfield(Lang, Key, Options) -> get_option_xfield(Lang, Key, Options) ->
Var = xfield_var(Key), Var = xfield_var(Key),
Label = xfield_label(Key), Label = xfield_label(Key),
{Type, OptEls} = type_and_options(xfield_type(Key), {Type, OptEls} = type_and_options(xfield_type(Key), Lang),
Lang),
Vals = case lists:keysearch(Key, 1, Options) of Vals = case lists:keysearch(Key, 1, Options) of
{value, {_, Val}} -> {value, {_, Val}} ->
[tr_xfield_values(Vals) [tr_xfield_values(Vals)
@ -322,15 +260,12 @@ tr_xfield_values(Value) ->
xfield_var(deliver) -> ?PUBSUB_DELIVER; xfield_var(deliver) -> ?PUBSUB_DELIVER;
%xfield_var(digest) -> ?PUBSUB_DIGEST; %xfield_var(digest) -> ?PUBSUB_DIGEST;
%xfield_var(digest_frequency) -> %xfield_var(digest_frequency) -> ?PUBSUB_DIGEST_FREQUENCY;
% ?PUBSUB_DIGEST_FREQUENCY;
%xfield_var(expire) -> ?PUBSUB_EXPIRE; %xfield_var(expire) -> ?PUBSUB_EXPIRE;
%xfield_var(include_body) -> ?PUBSUB_INCLUDE_BODY; %xfield_var(include_body) -> ?PUBSUB_INCLUDE_BODY;
xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES; xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES;
xfield_var(subscription_type) -> xfield_var(subscription_type) -> ?PUBSUB_SUBSCRIPTION_TYPE;
?PUBSUB_SUBSCRIPTION_TYPE; xfield_var(subscription_depth) -> ?PUBSUB_SUBSCRIPTION_DEPTH.
xfield_var(subscription_depth) ->
?PUBSUB_SUBSCRIPTION_DEPTH.
xfield_type(deliver) -> <<"boolean">>; xfield_type(deliver) -> <<"boolean">>;
%xfield_type(digest) -> <<"boolean">>; %xfield_type(digest) -> <<"boolean">>;
@ -356,17 +291,14 @@ xfield_type(subscription_depth) ->
%% Return the XForm variable label for a subscription option key. %% Return the XForm variable label for a subscription option key.
xfield_label(deliver) -> ?DELIVER_LABEL; xfield_label(deliver) -> ?DELIVER_LABEL;
%xfield_label(digest) -> ?DIGEST_LABEL; %xfield_label(digest) -> ?DIGEST_LABEL;
%xfield_label(digest_frequency) -> %xfield_label(digest_frequency) -> ?DIGEST_FREQUENCY_LABEL;
% ?DIGEST_FREQUENCY_LABEL;
%xfield_label(expire) -> ?EXPIRE_LABEL; %xfield_label(expire) -> ?EXPIRE_LABEL;
%xfield_label(include_body) -> ?INCLUDE_BODY_LABEL; %xfield_label(include_body) -> ?INCLUDE_BODY_LABEL;
xfield_label(show_values) -> ?SHOW_VALUES_LABEL; xfield_label(show_values) -> ?SHOW_VALUES_LABEL;
%% Return the XForm value for a subscription option key. %% Return the XForm value for a subscription option key.
%% Convert erlang booleans to XForms. %% Convert erlang booleans to XForms.
xfield_label(subscription_type) -> xfield_label(subscription_type) -> ?SUBSCRIPTION_TYPE_LABEL;
?SUBSCRIPTION_TYPE_LABEL; xfield_label(subscription_depth) -> ?SUBSCRIPTION_DEPTH_LABEL.
xfield_label(subscription_depth) ->
?SUBSCRIPTION_DEPTH_LABEL.
xfield_val(deliver, Val) -> [bool_to_xopt(Val)]; xfield_val(deliver, Val) -> [bool_to_xopt(Val)];
%xfield_val(digest, Val) -> [bool_to_xopt(Val)]; %xfield_val(digest, Val) -> [bool_to_xopt(Val)];

View File

@ -813,7 +813,7 @@ pubsub(Config) ->
node = Node, node = Node,
jid = my_jid(Config)}}]}), jid = my_jid(Config)}}]}),
?recv2( ?recv2(
#message{sub_els = [#pubsub_event{}, #delay{}, #legacy_delay{}]}, #message{sub_els = [#pubsub_event{}, #delay{}]},
#iq{type = result, id = I1}), #iq{type = result, id = I1}),
%% Get subscriptions %% Get subscriptions
true = lists:member(?PUBSUB("retrieve-subscriptions"), Features), true = lists:member(?PUBSUB("retrieve-subscriptions"), Features),
@ -860,8 +860,7 @@ pubsub(Config) ->
#message{sub_els = [#pubsub_event{ #message{sub_els = [#pubsub_event{
items = [#pubsub_event_items{ items = [#pubsub_event_items{
node = Node, node = Node,
retract = [ItemID]}]}, retract = [ItemID]}]}]}),
#shim{headers = [{<<"Collection">>, Node}]}]}),
%% Unsubscribe from node "presence" %% Unsubscribe from node "presence"
#iq{type = result, sub_els = []} = #iq{type = result, sub_els = []} =
send_recv(Config, send_recv(Config,

View File

@ -94,7 +94,8 @@
{mod_offline, [{db_type, odbc}]}, {mod_offline, [{db_type, odbc}]},
{mod_privacy, [{db_type, odbc}]}, {mod_privacy, [{db_type, odbc}]},
{mod_private, [{db_type, odbc}]}, {mod_private, [{db_type, odbc}]},
{mod_pubsub_odbc, [{access_createnode, pubsub_createnode}, {mod_pubsub, [{db_type, odbc},
{access_createnode, pubsub_createnode},
{ignore_pep_from_offline, true}, {ignore_pep_from_offline, true},
{last_item_cache, false}, {last_item_cache, false},
{plugins, ["flat", "hometree", "pep"]}]}, {plugins, ["flat", "hometree", "pep"]}]},
@ -114,7 +115,8 @@
{mod_offline, [{db_type, odbc}]}, {mod_offline, [{db_type, odbc}]},
{mod_privacy, [{db_type, odbc}]}, {mod_privacy, [{db_type, odbc}]},
{mod_private, [{db_type, odbc}]}, {mod_private, [{db_type, odbc}]},
{mod_pubsub_odbc, [{access_createnode, pubsub_createnode}, {mod_pubsub, [{db_type, odbc},
{access_createnode, pubsub_createnode},
{ignore_pep_from_offline, true}, {ignore_pep_from_offline, true},
{last_item_cache, false}, {last_item_cache, false},
{plugins, ["flat", "hometree", "pep"]}]}, {plugins, ["flat", "hometree", "pep"]}]},
@ -133,7 +135,8 @@
{mod_offline, [{db_type, odbc}]}, {mod_offline, [{db_type, odbc}]},
{mod_privacy, [{db_type, odbc}]}, {mod_privacy, [{db_type, odbc}]},
{mod_private, [{db_type, odbc}]}, {mod_private, [{db_type, odbc}]},
{mod_pubsub_odbc, [{access_createnode, pubsub_createnode}, {mod_pubsub, [{db_type, odbc},
{access_createnode, pubsub_createnode},
{ignore_pep_from_offline, true}, {ignore_pep_from_offline, true},
{last_item_cache, false}, {last_item_cache, false},
{plugins, ["flat", "hometree", "pep"]}]}, {plugins, ["flat", "hometree", "pep"]}]},

View File

@ -26,7 +26,8 @@ host_config:
db_type: odbc db_type: odbc
mod_private: mod_private:
db_type: odbc db_type: odbc
mod_pubsub_odbc: mod_pubsub:
db_type: odbc
access_createnode: pubsub_createnode access_createnode: pubsub_createnode
ignore_pep_from_offline: true ignore_pep_from_offline: true
last_item_cache: false last_item_cache: false
@ -76,7 +77,8 @@ Welcome to this XMPP server."
db_type: odbc db_type: odbc
mod_private: mod_private:
db_type: odbc db_type: odbc
mod_pubsub_odbc: mod_pubsub:
db_type: odbc
access_createnode: pubsub_createnode access_createnode: pubsub_createnode
ignore_pep_from_offline: true ignore_pep_from_offline: true
last_item_cache: false last_item_cache: false
@ -132,7 +134,8 @@ Welcome to this XMPP server."
db_type: odbc db_type: odbc
mod_private: mod_private:
db_type: odbc db_type: odbc
mod_pubsub_odbc: mod_pubsub:
db_type: odbc
access_createnode: pubsub_createnode access_createnode: pubsub_createnode
ignore_pep_from_offline: true ignore_pep_from_offline: true
last_item_cache: false last_item_cache: false