Skip to content

Commit

Permalink
Merge pull request #2122 from esl/pubsub-state-refactoring
Browse files Browse the repository at this point in the history
Refactor PubSub code to prepare for RDBMS
  • Loading branch information
michalwski authored Nov 8, 2018
2 parents 6e192e2 + 6802251 commit bf33ae1
Show file tree
Hide file tree
Showing 8 changed files with 438 additions and 251 deletions.
6 changes: 1 addition & 5 deletions include/pubsub.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,8 @@
%% of the current node. For example:
%% ```<<"/home/localhost/user">>'''</p>

-type(nodeIdx() :: pos_integer() | binary()).
-type(nodeIdx() :: pos_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 rdbms.

-type(itemId() :: binary()).
%% @type itemId() = string().
Expand Down
7 changes: 7 additions & 0 deletions src/jid.erl
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,16 @@ are_equal(_, _) ->
false.

%% @doc Returns true if `are_equal(to_bare(A), to_bare(B))'
-spec are_bare_equal(jid() | ljid(), jid() | ljid()) -> boolean().
are_bare_equal(#jid{luser = LUser, lserver = LServer},
#jid{luser = LUser, lserver = LServer}) ->
true;
are_bare_equal(#jid{luser = LUser, lserver = LServer}, {LUser, LServer, _}) ->
true;
are_bare_equal({LUser, LServer, _}, #jid{luser = LUser, lserver = LServer}) ->
true;
are_bare_equal({LUser, LServer, _}, {LUser, LServer, _}) ->
true;
are_bare_equal(_, _) ->
false.

Expand Down
2 changes: 1 addition & 1 deletion src/pubsub/gen_pubsub_node.erl
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@

-callback subscribe_node(NodeIdx :: nodeIdx(),
Sender :: jid:jid(),
Subscriber :: jid:jid(),
Subscriber :: jid:ljid(),
AccessModel :: accessModel(),
SendLast :: 'never' | 'on_sub' | 'on_sub_and_presence',
PresenceSubscription :: boolean(),
Expand Down
140 changes: 91 additions & 49 deletions src/pubsub/mod_pubsub.erl

Large diffs are not rendered by default.

97 changes: 92 additions & 5 deletions src/pubsub/mod_pubsub_db.erl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

-include("mongoose_logger.hrl").

-export([transaction_error/2, dirty_error/4]).

%%====================================================================
%% Behaviour callbacks
%%====================================================================
Expand All @@ -20,23 +22,33 @@

-callback stop() -> ok.

-callback transaction(Fun :: fun(() -> {result | error, any()})) ->
%% ----------------------- Fun execution ------------------------

%% `ErrorDebug` are the maps of extra data that will be added to error tuple

-callback transaction(Fun :: fun(() -> {result | error, any()}),
ErrorDebug :: map()) ->
{result | error, any()}.

%% Synchronous
-callback dirty(Fun :: fun(() -> {result | error, any()})) ->
-callback dirty(Fun :: fun(() -> {result | error, any()}),
ErrorDebug :: map()) ->
{result | error, any()}.

-callback set_state(State :: mod_pubsub:pubsubState()) -> ok.
%% ----------------------- Direct #pubsub_state access ------------------------

%% TODO: Replace with del_node when it is fully possible from backend
%% i.e. when pubsub_item is migrated to RDBMS as well
-callback del_state(Nidx :: mod_pubsub:nodeIdx(),
UserLJID :: jid:ljid()) -> ok.
LJID :: jid:ljid()) -> ok.

%% When a state is not found, returns empty state.
%% Maybe can be removed completely later?
-callback get_state(Nidx :: mod_pubsub:nodeIdx(),
UserLJID :: jid:ljid()) ->
JID :: jid:jid()) ->
{ok, mod_pubsub:pubsubState()}.

%% Maybe can be removed completely later?
-callback get_states(Nidx :: mod_pubsub:nodeIdx()) ->
{ok, [mod_pubsub:pubsubState()]}.

Expand All @@ -52,10 +64,85 @@
-callback get_own_nodes_states(JID :: jid:jid()) ->
{ok, [mod_pubsub:pubsubState()]}.

%% ----------------------- Affiliations ------------------------

-callback set_affiliation(Nidx :: mod_pubsub:nodeIdx(),
JID :: jid:jid(),
Affiliation :: mod_pubsub:affiliation()) ->
ok.

-callback get_affiliation(Nidx :: mod_pubsub:nodeIdx(),
JID :: jid:jid()) ->
{ok, mod_pubsub:affiliation()}.

%% ----------------------- Subscriptions ------------------------

-callback add_subscription(Nidx :: mod_pubsub:nodeIdx(),
JID :: jid:jid(),
Sub :: mod_pubsub:subscription(),
SubId :: mod_pubsub:subId()) ->
ok.

-callback update_subscription(Nidx :: mod_pubsub:nodeIdx(),
JID :: jid:jid(),
Subscription :: mod_pubsub:subscription(),
SubId :: mod_pubsub:subId()) ->
ok.

-callback get_node_subscriptions(Nidx :: mod_pubsub:nodeIdx()) ->
{ok, [{Entity :: jid:jid(), Sub :: mod_pubsub:subscription(), SubId :: mod_pubsub:subId()}]}.

-callback get_node_entity_subscriptions(Nidx :: mod_pubsub:nodeIdx(),
JID :: jid:jid()) ->
{ok, [{Sub :: mod_pubsub:subscription(), SubId :: mod_pubsub:subId()}]}.

-callback delete_subscription(
Nidx :: mod_pubsub:nodeIdx(),
JID :: jid:jid(),
SubId :: mod_pubsub:subId()) ->
ok.

-callback delete_all_subscriptions(
Nidx :: mod_pubsub:nodeIdx(),
JID :: jid:jid()) ->
ok.

%% ----------------------- Items ------------------------

%% TODO: Refactor to use MaxItems value, so separate remove_items in publishing
%% won't be necessary and the whole operation may be optimised in DB layer.
-callback add_item(Nidx :: mod_pubsub:nodeIdx(),
JID :: jid:jid(),
ItemId :: mod_pubsub:itemId()) ->
ok.

-callback remove_items(Nidx :: mod_pubsub:nodeIdx(),
JID :: jid:jid(),
ItemIds :: [mod_pubsub:itemId()]) ->
ok.

-callback remove_all_items(Nidx :: mod_pubsub:nodeIdx()) ->
ok.

%%====================================================================
%% API
%%====================================================================

%% These are made as separate functions to make tracing easier, just in case.

-spec transaction_error(Reason :: any(), ErrorDebug :: map()) ->
{error, Details :: map()}.
transaction_error(Reason, ErrorDebug) ->
{error, ErrorDebug#{ event => transaction_failure,
reason => Reason }}.

-spec dirty_error(Class :: atom(), Reason :: any(), StackTrace :: list(), ErrorDebug :: map()) ->
{error, Details :: map()}.
dirty_error(Class, Reason, StackTrace, ErrorDebug) ->
{error, ErrorDebug#{ event => dirty_failure,
class => Class,
reason => Reason,
stacktrace => StackTrace}}.

%%====================================================================
%% Internal functions
Expand Down
Loading

0 comments on commit bf33ae1

Please sign in to comment.