./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 81 prepare_queries(),
34 81 ejabberd_hooks:add(hooks(HostType)),
35 81 ok.
36
37 -spec stop(mongooseim:host_type()) -> ok.
38 stop(HostType) ->
39 81 ejabberd_hooks:delete(hooks(HostType)),
40 81 ok.
41
42 -spec supported_features() -> [atom()].
43 supported_features() ->
44 81 [dynamic_domains].
45
46 hooks(HostType) ->
47 162 [{Hook, HostType, ?MODULE, Fun, N}
48 162 || {true, Hook, Fun, N} <- hooks2(HostType)].
49
50 hooks2(HostType) ->
51 %% FIXME the auto_remove option is missing from the config spec
52 162 AR = gen_mod:get_module_opt(HostType, ?MODULE, auto_remove, false),
53 162 PM = gen_mod:get_module_opt(HostType, ?MODULE, pm, false),
54 162 MUC = gen_mod:get_module_opt(HostType, ?MODULE, muc, false),
55 162 [{PM, mam_archive_id, archive_id, 50},
56 {PM and AR, mam_remove_archive, remove_archive, 90},
57 {MUC, mam_muc_archive_id, archive_id, 50},
58 {MUC and AR, mam_muc_remove_archive, remove_archive, 90}].
59
60 prepare_queries() ->
61 81 mongoose_rdbms:prepare(mam_user_insert, mam_server_user, [server, user_name],
62 <<"INSERT INTO mam_server_user (server, user_name) VALUES (?, ?)">>),
63 81 mongoose_rdbms:prepare(mam_user_select, mam_server_user, [server, user_name],
64 <<"SELECT id FROM mam_server_user WHERE server=? AND user_name=?">>),
65 81 mongoose_rdbms:prepare(mam_user_remove, mam_server_user, [server, user_name],
66 <<"DELETE FROM mam_server_user WHERE server=? AND user_name=?">>),
67 81 ok.
68
69 %%====================================================================
70 %% API
71 %%====================================================================
72 -spec archive_id(ArcID :: undefined | mod_mam:archive_id(),
73 HostType :: mongooseim:host_type(),
74 ArchiveJID :: jid:jid()) -> mod_mam:archive_id().
75 archive_id(undefined, HostType, _ArcJID=#jid{lserver = LServer, luser = LUser}) ->
76 5901 query_archive_id(HostType, LServer, LUser);
77 archive_id(ArcID, _Host, _ArcJID) ->
78 3039 ArcID.
79
80 -spec remove_archive(Acc :: map(), HostType :: mongooseim:host_type(),
81 ArchiveID :: mod_mam:archive_id(),
82 ArchiveJID :: jid:jid()) -> map().
83 remove_archive(Acc, HostType, _ArcID, _ArcJID = #jid{lserver = LServer, luser = LUser}) ->
84
:-(
execute_user_remove(HostType, LServer, LUser),
85
:-(
Acc.
86
87 %%====================================================================
88 %% Internal functions
89 %%====================================================================
90
91 execute_user_remove(HostType, LServer, LUser) ->
92
:-(
{updated, _} =
93 mongoose_rdbms:execute(HostType, mam_user_remove, [LUser, LServer]).
94
95 -spec query_archive_id(mongooseim:host_type(), jid:lserver(), jid:luser()) -> integer().
96 query_archive_id(HostType, LServer, LUser) ->
97 5901 Tries = 5,
98 5901 query_archive_id(HostType, LServer, LUser, Tries).
99
100 query_archive_id(HostType, LServer, LUser, 0) ->
101
:-(
?LOG_ERROR(#{what => query_archive_id_failed,
102
:-(
host => HostType, server => LServer, user => LUser}),
103
:-(
error(query_archive_id_failed);
104 query_archive_id(HostType, LServer, LUser, Tries) when Tries > 0 ->
105 7572 Result = mongoose_rdbms:execute(HostType, mam_user_select, [LServer, LUser]),
106 7572 case Result of
107 {selected, [{IdBin}]} ->
108 5901 mongoose_rdbms:result_to_integer(IdBin);
109 {selected, []} ->
110 %% The user is not found
111 1671 create_user_archive(HostType, LServer, LUser),
112 1671 query_archive_id(HostType, LServer, LUser, Tries - 1)
113 end.
114
115 -spec create_user_archive(mongooseim:host_type(), jid:lserver(), jid:luser()) -> ok.
116 create_user_archive(HostType, LServer, LUser) ->
117 1671 Res = mongoose_rdbms:execute(HostType, mam_user_insert, [LServer, LUser]),
118 1671 case Res of
119 {updated, 1} ->
120 1592 ok;
121 _ ->
122 %% There is a common race condition case
123 %% Duplicate entry ... for key 'uc_mam_server_user_name'.
124 %% In this case Res can de:
125 %% - {error, duplicate_key}
126 %% - {error, "[FreeTDS][SQL Server]Violation of UNIQUE KEY constraint" ++ _}
127 %% Let's ignore the errors and just retry in query_archive_id
128 79 ?LOG_WARNING(#{what => create_user_archive_failed, reason => Res,
129
:-(
user => LUser, host => HostType, server => LServer}),
130 79 ok
131 end.
Line Hits Source