./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 -behaviour(gen_mod).
13
14 %% gen_mod handlers
15 -export([start/2, stop/1, hooks/1, supported_features/0]).
16
17 %% ejabberd handlers
18 -export([archive_id/3,
19 remove_archive/3]).
20
21 %% For debugging ONLY
22 -export([create_user_archive/3]).
23 -ignore_xref([create_user_archive/3]).
24
25 -include("mongoose.hrl").
26 -include("jlib.hrl").
27
28 %% ----------------------------------------------------------------------
29 %% gen_mod callbacks
30 -spec start(mongooseim:host_type(), gen_mod:module_opts()) -> ok.
31 start(_HostType, _Opts) ->
32 100 prepare_queries(),
33 100 ok.
34
35 -spec stop(mongooseim:host_type()) -> ok.
36 stop(_HostType) ->
37 100 ok.
38
39 -spec supported_features() -> [atom()].
40 supported_features() ->
41 1 [dynamic_domains].
42
43 hooks(HostType) ->
44 200 [{Hook, HostType, Fun, #{}, N}
45 200 || {true, Hook, Fun, N} <- hooks2(HostType)].
46
47 hooks2(HostType) ->
48 %% FIXME the auto_remove option is missing from the config spec
49 200 AR = gen_mod:get_module_opt(HostType, ?MODULE, auto_remove, false),
50 200 PM = gen_mod:get_module_opt(HostType, ?MODULE, pm, false),
51 200 MUC = gen_mod:get_module_opt(HostType, ?MODULE, muc, false),
52 200 [{PM, mam_archive_id, fun ?MODULE:archive_id/3, 50},
53 {PM and AR, mam_remove_archive, fun ?MODULE:remove_archive/3, 90},
54 {MUC, mam_muc_archive_id, fun ?MODULE:archive_id/3, 50},
55 {MUC and AR, mam_muc_remove_archive, fun ?MODULE:remove_archive/3, 90}].
56
57 prepare_queries() ->
58 100 mongoose_rdbms:prepare(mam_user_insert, mam_server_user, [server, user_name],
59 <<"INSERT INTO mam_server_user (server, user_name) VALUES (?, ?)">>),
60 100 mongoose_rdbms:prepare(mam_user_select, mam_server_user, [server, user_name],
61 <<"SELECT id FROM mam_server_user WHERE server=? AND user_name=?">>),
62 100 mongoose_rdbms:prepare(mam_user_remove, mam_server_user, [server, user_name],
63 <<"DELETE FROM mam_server_user WHERE server=? AND user_name=?">>),
64 100 ok.
65
66 %%====================================================================
67 %% API
68 %%====================================================================
69 -spec archive_id(Acc, Params, Extra) -> {ok, Acc} when
70 Acc :: mod_mam:archive_id() | undefined,
71 Params :: map(),
72 Extra :: gen_hook:extra().
73 archive_id(undefined,
74 #{owner := #jid{lserver = LServer, luser = LUser}},
75 #{host_type := HostType}) ->
76 7624 {ok, query_archive_id(HostType, LServer, LUser)};
77 archive_id(ArcID, _Params, _Extra) ->
78 3865 {ok, ArcID}.
79
80 -spec remove_archive(Acc, Params, Extra) -> {ok, Acc} when
81 Acc :: term(),
82 Params :: map(),
83 Extra :: gen_hook:extra().
84 remove_archive(Acc,
85 #{owner := #jid{lserver = LServer, luser = LUser}},
86 #{host_type := HostType}) ->
87
:-(
execute_user_remove(HostType, LServer, LUser),
88
:-(
{ok, Acc}.
89
90 %%====================================================================
91 %% Internal functions
92 %%====================================================================
93
94 execute_user_remove(HostType, LServer, LUser) ->
95
:-(
{updated, _} =
96 mongoose_rdbms:execute(HostType, mam_user_remove, [LUser, LServer]).
97
98 -spec query_archive_id(mongooseim:host_type(), jid:lserver(), jid:luser()) -> integer().
99 query_archive_id(HostType, LServer, LUser) ->
100 7624 Tries = 5,
101 7624 query_archive_id(HostType, LServer, LUser, Tries).
102
103 query_archive_id(HostType, LServer, LUser, 0) ->
104
:-(
?LOG_ERROR(#{what => query_archive_id_failed,
105
:-(
host => HostType, server => LServer, user => LUser}),
106
:-(
error(query_archive_id_failed);
107 query_archive_id(HostType, LServer, LUser, Tries) when Tries > 0 ->
108 9586 Result = mongoose_rdbms:execute(HostType, mam_user_select, [LServer, LUser]),
109 9586 case Result of
110 {selected, [{IdBin}]} ->
111 7624 mongoose_rdbms:result_to_integer(IdBin);
112 {selected, []} ->
113 %% The user is not found
114 1962 create_user_archive(HostType, LServer, LUser),
115 1962 query_archive_id(HostType, LServer, LUser, Tries - 1)
116 end.
117
118 -spec create_user_archive(mongooseim:host_type(), jid:lserver(), jid:luser()) -> ok.
119 create_user_archive(HostType, LServer, LUser) ->
120 1962 Res = mongoose_rdbms:execute(HostType, mam_user_insert, [LServer, LUser]),
121 1962 case Res of
122 {updated, 1} ->
123 1872 ok;
124 _ ->
125 %% There is a common race condition case
126 %% Duplicate entry ... for key 'uc_mam_server_user_name'.
127 %% In this case Res can de:
128 %% - {error, duplicate_key}
129 %% - {error, "[FreeTDS][SQL Server]Violation of UNIQUE KEY constraint" ++ _}
130 %% Let's ignore the errors and just retry in query_archive_id
131 90 ?LOG_WARNING(#{what => create_user_archive_failed, reason => Res,
132
:-(
user => LUser, host => HostType, server => LServer}),
133 90 ok
134 end.
Line Hits Source