aboutsummaryrefslogtreecommitdiff
path: root/src/mod_mix_mnesia.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_mix_mnesia.erl')
-rw-r--r--src/mod_mix_mnesia.erl189
1 files changed, 189 insertions, 0 deletions
diff --git a/src/mod_mix_mnesia.erl b/src/mod_mix_mnesia.erl
new file mode 100644
index 000000000..19b2c3983
--- /dev/null
+++ b/src/mod_mix_mnesia.erl
@@ -0,0 +1,189 @@
+%%%-------------------------------------------------------------------
+%%% Created : 1 Dec 2018 by Evgeny Khramtsov <ekhramtsov@process-one.net>
+%%%
+%%%
+%%% ejabberd, Copyright (C) 2002-2018 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.,
+%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+%%%
+%%%----------------------------------------------------------------------
+-module(mod_mix_mnesia).
+-behaviour(mod_mix).
+-compile([{parse_transform, ejabberd_sql_pt}]).
+
+%% API
+-export([init/2]).
+-export([set_channel/6, get_channels/2, get_channel/3, del_channel/3]).
+-export([set_participant/6, get_participant/4, get_participants/3, del_participant/4]).
+-export([subscribe/5, unsubscribe/4, unsubscribe/5, get_subscribed/4]).
+
+-include("logger.hrl").
+-include("ejabberd_sql_pt.hrl").
+
+-record(mix_channel,
+ {chan_serv :: {binary(), binary()},
+ service :: binary(),
+ creator :: jid:jid(),
+ hidden :: boolean(),
+ hmac_key :: binary(),
+ created_at :: erlang:timestamp()}).
+
+-record(mix_participant,
+ {user_chan :: {binary(), binary(), binary(), binary()},
+ chan_serv :: {binary(), binary()},
+ jid :: jid:jid(),
+ id :: binary(),
+ nick :: binary(),
+ created_at :: erlang:timestamp()}).
+
+-record(mix_subscription,
+ {user_chan_node :: {binary(), binary(), binary(), binary(), binary()},
+ user_chan :: {binary(), binary(), binary(), binary()},
+ chan_serv_node :: {binary(), binary(), binary()},
+ chan_serv :: {binary(), binary()},
+ jid :: jid:jid()}).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+init(_Host, _Opts) ->
+ try
+ {atomic, _} = ejabberd_mnesia:create(
+ ?MODULE, mix_channel,
+ [{disc_only_copies, [node()]},
+ {attributes, record_info(fields, mix_channel)},
+ {index, [service]}]),
+ {atomic, _} = ejabberd_mnesia:create(
+ ?MODULE, mix_participant,
+ [{disc_only_copies, [node()]},
+ {attributes, record_info(fields, mix_participant)},
+ {index, [chan_serv]}]),
+ {atomic, _} = ejabberd_mnesia:create(
+ ?MODULE, mix_subscription,
+ [{disc_only_copies, [node()]},
+ {attributes, record_info(fields, mix_subscription)},
+ {index, [user_chan, chan_serv_node, chan_serv]}]),
+ ok
+ catch _:{badmatch, _} ->
+ {error, db_failure}
+ end.
+
+set_channel(_LServer, Channel, Service, CreatorJID, Hidden, Key) ->
+ mnesia:dirty_write(
+ #mix_channel{chan_serv = {Channel, Service},
+ service = Service,
+ creator = jid:remove_resource(CreatorJID),
+ hidden = Hidden,
+ hmac_key = Key,
+ created_at = p1_time_compat:timestamp()}).
+
+get_channels(_LServer, Service) ->
+ Ret = mnesia:dirty_index_read(mix_channel, Service, #mix_channel.service),
+ {ok, lists:filtermap(
+ fun(#mix_channel{chan_serv = {Channel, _},
+ hidden = false}) ->
+ {true, Channel};
+ (_) ->
+ false
+ end, Ret)}.
+
+get_channel(_LServer, Channel, Service) ->
+ case mnesia:dirty_read(mix_channel, {Channel, Service}) of
+ [#mix_channel{creator = JID,
+ hidden = Hidden,
+ hmac_key = Key}] ->
+ {ok, {JID, Hidden, Key}};
+ [] ->
+ {error, notfound}
+ end.
+
+del_channel(_LServer, Channel, Service) ->
+ Key = {Channel, Service},
+ L1 = mnesia:dirty_read(mix_channel, Key),
+ L2 = mnesia:dirty_index_read(mix_participant, Key,
+ #mix_participant.chan_serv),
+ L3 = mnesia:dirty_index_read(mix_subscription, Key,
+ #mix_subscription.chan_serv),
+ lists:foreach(fun mnesia:dirty_delete_object/1, L1++L2++L3).
+
+set_participant(_LServer, Channel, Service, JID, ID, Nick) ->
+ {User, Domain, _} = jid:tolower(JID),
+ mnesia:dirty_write(
+ #mix_participant{
+ user_chan = {User, Domain, Channel, Service},
+ chan_serv = {Channel, Service},
+ jid = jid:remove_resource(JID),
+ id = ID,
+ nick = Nick,
+ created_at = p1_time_compat:timestamp()}).
+
+get_participant(_LServer, Channel, Service, JID) ->
+ {User, Domain, _} = jid:tolower(JID),
+ case mnesia:dirty_read(mix_participant, {User, Domain, Channel, Service}) of
+ [#mix_participant{id = ID, nick = Nick}] -> {ok, {ID, Nick}};
+ [] -> {error, notfound}
+ end.
+
+get_participants(_LServer, Channel, Service) ->
+ Ret = mnesia:dirty_index_read(mix_participant,
+ {Channel, Service},
+ #mix_participant.chan_serv),
+ {ok, lists:map(
+ fun(#mix_participant{jid = JID, id = ID, nick = Nick}) ->
+ {JID, ID, Nick}
+ end, Ret)}.
+
+del_participant(_LServer, Channel, Service, JID) ->
+ {User, Domain, _} = jid:tolower(JID),
+ mnesia:dirty_delete(mix_participant, {User, Domain, Channel, Service}).
+
+subscribe(_LServer, Channel, Service, JID, Nodes) ->
+ {User, Domain, _} = jid:tolower(JID),
+ BJID = jid:remove_resource(JID),
+ lists:foreach(
+ fun(Node) ->
+ mnesia:dirty_write(
+ #mix_subscription{
+ user_chan_node = {User, Domain, Channel, Service, Node},
+ user_chan = {User, Domain, Channel, Service},
+ chan_serv_node = {Channel, Service, Node},
+ chan_serv = {Channel, Service},
+ jid = BJID})
+ end, Nodes).
+
+get_subscribed(_LServer, Channel, Service, Node) ->
+ Ret = mnesia:dirty_index_read(mix_subscription,
+ {Channel, Service, Node},
+ #mix_subscription.chan_serv_node),
+ {ok, [JID || #mix_subscription{jid = JID} <- Ret]}.
+
+unsubscribe(_LServer, Channel, Service, JID) ->
+ {User, Domain, _} = jid:tolower(JID),
+ Ret = mnesia:dirty_index_read(mix_subscription,
+ {User, Domain, Channel, Service},
+ #mix_subscription.user_chan),
+ lists:foreach(fun mnesia:dirty_delete_object/1, Ret).
+
+unsubscribe(_LServer, Channel, Service, JID, Nodes) ->
+ {User, Domain, _} = jid:tolower(JID),
+ lists:foreach(
+ fun(Node) ->
+ mnesia:dirty_delete(mix_subscription,
+ {User, Domain, Channel, Service, Node})
+ end, Nodes).
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================