diff --git a/sql/lite.sql b/sql/lite.sql index 8b59ef0a1..ddfb91ff0 100644 --- a/sql/lite.sql +++ b/sql/lite.sql @@ -359,3 +359,13 @@ CREATE TABLE bosh ( ); CREATE UNIQUE INDEX i_bosh_sid ON bosh(sid); + +CREATE TABLE carboncopy ( + username text NOT NULL, + resource text NOT NULL, + namespace text NOT NULL, + node text NOT NULL +); + +CREATE UNIQUE INDEX i_carboncopy_ur ON carboncopy (username, resource); +CREATE INDEX i_carboncopy_user ON carboncopy (username); diff --git a/sql/mssql.sql b/sql/mssql.sql index 59c192b98..72b490ecc 100644 --- a/sql/mssql.sql +++ b/sql/mssql.sql @@ -520,7 +520,7 @@ CREATE TABLE [dbo].[route] ( [server_host] [varchar] (255) NOT NULL, [node] [varchar] (255) NOT NULL, [pid] [varchar](100) NOT NULL, - [local_hint] text NOT NULL + [local_hint] [text] NOT NULL ); CREATE UNIQUE CLUSTERED INDEX [route_i] ON [route] (domain, server_host, node, pid) @@ -538,3 +538,16 @@ CREATE TABLE [dbo].[bosh] ( [sid] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ) TEXTIMAGE_ON [PRIMARY]; + +CREATE TABLE [dbo].[carboncopy] ( + [username] [varchar] (255) NOT NULL, + [resource] [varchar] (255) NOT NULL, + [namespace] [varchar] (255) NOT NULL, + [node] [varchar] (255) NOT NULL +); + +CREATE UNIQUE CLUSTERED INDEX [carboncopy_ur] ON [carboncopy] (username, resource) +WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON); + +CREATE INDEX [carboncopy_user] ON [carboncopy] (username) +WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON); diff --git a/sql/mysql.sql b/sql/mysql.sql index edd205f0d..e09c39be5 100644 --- a/sql/mysql.sql +++ b/sql/mysql.sql @@ -375,3 +375,13 @@ CREATE TABLE bosh ( ) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE UNIQUE INDEX i_bosh_sid ON bosh(sid(75)); + +CREATE TABLE carboncopy ( + username text NOT NULL, + resource text NOT NULL, + namespace text NOT NULL, + node text NOT NULL +) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +CREATE UNIQUE INDEX i_carboncopy_ur ON carboncopy (username(75), resource(75)); +CREATE INDEX i_carboncopy_user ON carboncopy (username(75)); diff --git a/sql/pg.sql b/sql/pg.sql index 6c099fc6b..796391c74 100644 --- a/sql/pg.sql +++ b/sql/pg.sql @@ -379,3 +379,13 @@ CREATE TABLE bosh ( ); CREATE UNIQUE INDEX i_bosh_sid ON bosh USING btree (sid); + +CREATE TABLE carboncopy ( + username text NOT NULL, + resource text NOT NULL, + namespace text NOT NULL, + node text NOT NULL +); + +CREATE UNIQUE INDEX i_carboncopy_ur ON carboncopy USING btree (username, resource); +CREATE INDEX i_carboncopy_user ON carboncopy USING btree (username); diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl index 03fe475f2..a7ae37f45 100644 --- a/src/mod_carboncopy.erl +++ b/src/mod_carboncopy.erl @@ -58,7 +58,7 @@ is_carbon_copy(_) -> start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts,fun gen_iq_handler:check_type/1, one_queue), ejabberd_hooks:add(disco_local_features, Host, ?MODULE, disco_features, 50), - Mod = gen_mod:db_mod(Host, ?MODULE), + Mod = gen_mod:ram_db_mod(Host, ?MODULE), Mod:init(Host, Opts), ejabberd_hooks:add(unset_presence_hook,Host, ?MODULE, remove_connection, 10), %% why priority 89: to define clearly that we must run BEFORE mod_logdb hook (90) @@ -75,8 +75,8 @@ stop(Host) -> ejabberd_hooks:delete(unset_presence_hook,Host, ?MODULE, remove_connection, 10). reload(Host, NewOpts, OldOpts) -> - NewMod = gen_mod:db_mod(Host, NewOpts, ?MODULE), - OldMod = gen_mod:db_mod(Host, OldOpts, ?MODULE), + NewMod = gen_mod:ram_db_mod(Host, NewOpts, ?MODULE), + OldMod = gen_mod:ram_db_mod(Host, OldOpts, ?MODULE), if NewMod /= OldMod -> NewMod:init(Host, NewOpts); true -> @@ -246,13 +246,13 @@ build_forward_packet(JID, #message{type = T} = Msg, Sender, Dest, Direction) -> -spec enable(binary(), binary(), binary(), binary()) -> ok | {error, any()}. enable(Host, U, R, CC)-> ?DEBUG("enabling for ~p", [U]), - Mod = gen_mod:db_mod(Host, ?MODULE), + Mod = gen_mod:ram_db_mod(Host, ?MODULE), Mod:enable(U, Host, R, CC). -spec disable(binary(), binary(), binary()) -> ok | {error, any()}. disable(Host, U, R)-> ?DEBUG("disabling for ~p", [U]), - Mod = gen_mod:db_mod(Host, ?MODULE), + Mod = gen_mod:ram_db_mod(Host, ?MODULE), Mod:disable(U, Host, R). -spec complete_packet(jid(), message(), direction()) -> message(). @@ -279,12 +279,12 @@ is_muc_pm(_To, Packet) -> -spec list(binary(), binary()) -> [{binary(), binary()}]. %% list {resource, cc_version} with carbons enabled for given user and host list(User, Server) -> - Mod = gen_mod:db_mod(Server, ?MODULE), + Mod = gen_mod:ram_db_mod(Server, ?MODULE), Mod:list(User, Server). depends(_Host, _Opts) -> []. mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1; -mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; -mod_opt_type(_) -> [db_type, iqdisc]. +mod_opt_type(ram_db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; +mod_opt_type(_) -> [ram_db_type, iqdisc]. diff --git a/src/mod_carboncopy_sql.erl b/src/mod_carboncopy_sql.erl new file mode 100644 index 000000000..2770d40aa --- /dev/null +++ b/src/mod_carboncopy_sql.erl @@ -0,0 +1,93 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% Created : 29 Mar 2017 by Evgeny Khramtsov +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2017 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_carboncopy_sql). +-behaviour(mod_carboncopy). + +-compile([{parse_transform, ejabberd_sql_pt}]). + +%% API +-export([init/2, enable/4, disable/3, list/2]). + +-include("ejabberd.hrl"). +-include("logger.hrl"). +-include("ejabberd_sql_pt.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +init(Host, _Opts) -> + clean_table(Host). + +enable(LUser, LServer, LResource, NS) -> + NodeS = erlang:atom_to_binary(node(), latin1), + case ?SQL_UPSERT(LServer, "carboncopy", + ["!username=%(LUser)s", + "!resource=%(LResource)s", + "namespace=%(NS)s", + "node=%(NodeS)s"]) of + ok -> + ok; + Err -> + ?ERROR_MSG("failed to update 'carboncopy' table: ~p", [Err]), + Err + end. + +disable(LUser, LServer, LResource) -> + case ejabberd_sql:sql_query( + LServer, + ?SQL("delete from carboncopy where username=%(LUser)s " + "and resource=%(LResource)s")) of + {updated, _} -> + ok; + Err -> + ?ERROR_MSG("failed to delete from 'carboncopy' table: ~p", [Err]), + Err + end. + +list(LUser, LServer) -> + case ejabberd_sql:sql_query( + LServer, + ?SQL("select @(resource)s, @(namespace)s from carboncopy " + "where username=%(LUser)s")) of + {selected, Rows} -> + Rows; + Err -> + ?ERROR_MSG("failed to select from 'carboncopy' table: ~p", [Err]), + [] + end. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +clean_table(LServer) -> + NodeS = erlang:atom_to_binary(node(), latin1), + ?INFO_MSG("Cleaning SQL 'carboncopy' table...", []), + case ejabberd_sql:sql_query( + LServer, + ?SQL("delete from carboncopy where node=%(NodeS)s")) of + {updated, _} -> + ok; + Err -> + ?ERROR_MSG("failed to clean 'carboncopy' table: ~p", [Err]), + Err + end. diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 43f0f34db..36a306b59 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -443,7 +443,6 @@ db_tests(DB) when DB == mnesia; DB == redis -> carbons_tests:master_slave_cases(), csi_tests:master_slave_cases()]; db_tests(_) -> - %% No support for carboncopy [{single_user, [sequence], [test_register, legacy_auth_tests(), @@ -469,7 +468,8 @@ db_tests(_) -> mam_tests:master_slave_cases(), mix_tests:master_slave_cases(), vcard_tests:master_slave_cases(), - announce_tests:master_slave_cases()]. + announce_tests:master_slave_cases(), + carbons_tests:master_slave_cases()]. ldap_tests() -> [{ldap_tests, [sequence], diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index 41bf24ab2..f58a429ae 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -47,6 +47,8 @@ host_config: db_type: sql mod_vcard_xupdate: db_type: sql + mod_carboncopy: + ram_db_type: sql mod_adhoc: [] mod_configure: [] mod_disco: [] @@ -105,6 +107,8 @@ Welcome to this XMPP server." db_type: sql mod_vcard_xupdate: db_type: sql + mod_carboncopy: + ram_db_type: sql mod_adhoc: [] mod_configure: [] mod_disco: [] @@ -168,6 +172,8 @@ Welcome to this XMPP server." db_type: sql mod_vcard_xupdate: db_type: sql + mod_carboncopy: + ram_db_type: sql mod_adhoc: [] mod_configure: [] mod_disco: [] @@ -222,7 +228,8 @@ Welcome to this XMPP server." db_type: internal mod_vcard_xupdate: db_type: internal - mod_carboncopy: [] + mod_carboncopy: + ram_db_type: internal mod_client_state: queue_presence: true queue_chat_states: true @@ -282,7 +289,8 @@ Welcome to this XMPP server." db_type: internal mod_vcard_xupdate: db_type: internal - mod_carboncopy: [] + mod_carboncopy: + ram_db_type: internal mod_client_state: queue_presence: true queue_chat_states: true