./ct_report/coverage/mod_mam_rdbms_user.COVER.html

1 %%%-------------------------------------------------------------------
2 %%% @author Uvarov Michael <arcusfelis@gmail.com>
3 %%% @copyright (C) 2013, Uvarov Michael
4 %%% @doc Assigns archive integer identifiers (multihost version).
5 %%%
6 %%% This module supports several hosts.
7 %%%
8 %%% Archive id is assigned based on user_name and host.
9 %%% @end
10 %%%-------------------------------------------------------------------
11 -module(mod_mam_rdbms_user).
12
13 %% gen_mod handlers
14 -export([start/2, stop/1, supported_features/0]).
15
16 %% ejabberd handlers
17 -export([archive_id/3,
18 remove_archive/4]).
19
20 %% For debugging ONLY
21 -export([create_user_archive/3]).
22
23 -ignore_xref([archive_id/3, create_user_archive/3, remove_archive/4, start/2,
24 stop/1, supported_features/0]).
25
26 -include("mongoose.hrl").
27 -include("jlib.hrl").
28
29 %% ----------------------------------------------------------------------
30 %% gen_mod callbacks
31 -spec start(mongooseim:host_type(), gen_mod:module_opts()) -> ok.
32 start(HostType, _Opts) ->
33 89 prepare_queries(),
34 89 ejabberd_hooks:add(hooks(HostType)),
35 89 ok.
36
37 -spec stop(mongooseim:host_type()) -> ok.
38 stop(HostType) ->
39 89 ejabberd_hooks:delete(hooks(HostType)),
40 89 ok.
41
42 -spec supported_features() -> [atom()].
43 supported_features() ->
44 89 [dynamic_domains].
45
46 hooks(HostType) ->
47 178 [{Hook, HostType, ?MODULE, Fun, N}
48 178 || {true, Hook, Fun, N} <- hooks2(HostType)].
49
50 hooks2(HostType) ->
51 178 AR = gen_mod:get_module_opt(HostType, ?MODULE, auto_remove, false),
52 178 PM = gen_mod:get_module_opt(HostType, ?MODULE, pm, false),
53 178 MUC = gen_mod:get_module_opt(HostType, ?MODULE, muc, false),
54 178 [{PM, mam_archive_id, archive_id, 50},
55 {PM and AR, mam_remove_archive, remove_archive, 90},
56 {MUC, mam_muc_archive_id, archive_id, 50},
57 {MUC and AR, mam_muc_remove_archive, remove_archive, 90}].
58
59 prepare_queries() ->
60 89 mongoose_rdbms:prepare(mam_user_insert, mam_server_user, [server, user_name],
61 <<"INSERT INTO mam_server_user (server, user_name) VALUES (?, ?)">>),
62 89 mongoose_rdbms:prepare(mam_user_select, mam_server_user, [server, user_name],
63 <<"SELECT id FROM mam_server_user WHERE server=? AND user_name=?">>),
64 89 mongoose_rdbms:prepare(mam_user_remove, mam_server_user, [server, user_name],
65 <<"DELETE FROM mam_server_user WHERE server=? AND user_name=?">>),
66 89 ok.
67
68 %%====================================================================
69 %% API
70 %%====================================================================
71 -spec archive_id(ArcID :: undefined | mod_mam:archive_id(),
72 HostType :: mongooseim:host_type(),
73 ArchiveJID :: jid:jid()) -> mod_mam:archive_id().
74 archive_id(undefined, HostType, _ArcJID=#jid{lserver = LServer, luser = LUser}) ->
75 6423 query_archive_id(HostType, LServer, LUser);
76 archive_id(ArcID, _Host, _ArcJID) ->
77 2626 ArcID.
78
79 -spec remove_archive(Acc :: map(), HostType :: mongooseim:host_type(),
80 ArchiveID :: mod_mam:archive_id(),
81 ArchiveJID :: jid:jid()) -> map().
82 remove_archive(Acc, HostType, _ArcID, _ArcJID = #jid{lserver = LServer, luser = LUser}) ->
83
:-(
execute_user_remove(HostType, LServer, LUser),
84
:-(
Acc.
85
86 %%====================================================================
87 %% Internal functions
88 %%====================================================================
89
90 execute_user_remove(HostType, LServer, LUser) ->
91
:-(
{updated, _} =
92 mongoose_rdbms:execute(HostType, mam_user_remove, [LUser, LServer]).
93
94 -spec query_archive_id(mongooseim:host_type(), jid:lserver(), jid:luser()) -> integer().
95 query_archive_id(HostType, LServer, LUser) ->
96 6423 Tries = 5,
97 6423 query_archive_id(HostType, LServer, LUser, Tries).
98
99 query_archive_id(HostType, LServer, LUser, 0) ->
100
:-(
?LOG_ERROR(#{what => query_archive_id_failed,
101
:-(
host => HostType, server => LServer, user => LUser}),
102
:-(
error(query_archive_id_failed);
103 query_archive_id(HostType, LServer, LUser, Tries) when Tries > 0 ->
104 8003 Result = mongoose_rdbms:execute(HostType, mam_user_select, [LServer, LUser]),
105 8003 case Result of
106 {selected, [{IdBin}]} ->
107 6423 mongoose_rdbms:result_to_integer(IdBin);
108 {selected, []} ->
109 %% The user is not found
110 1580 create_user_archive(HostType, LServer, LUser),
111 1580 query_archive_id(HostType, LServer, LUser, Tries - 1)
112 end.
113
114 -spec create_user_archive(mongooseim:host_type(), jid:lserver(), jid:luser()) -> ok.
115 create_user_archive(HostType, LServer, LUser) ->
116 1580 Res = mongoose_rdbms:execute(HostType, mam_user_insert, [LServer, LUser]),
117 1580 case Res of
118 {updated, 1} ->
119 1484 ok;
120 _ ->
121 %% There is a common race condition case
122 %% Duplicate entry ... for key 'uc_mam_server_user_name'.
123 %% In this case Res can de:
124 %% - {error, duplicate_key}
125 %% - {error, "[FreeTDS][SQL Server]Violation of UNIQUE KEY constraint" ++ _}
126 %% Let's ignore the errors and just retry in query_archive_id
127 96 ?LOG_WARNING(#{what => create_user_archive_failed, reason => Res,
128
:-(
user => LUser, host => HostType, server => LServer}),
129 96 ok
130 end.
Line Hits Source