• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

processone / ejabberd / 603

17 Oct 2023 01:57PM UTC coverage: 32.654% (-0.4%) from 33.021%
603

push

github

badlop
Fixing minor typos in CHANGELOG

13497 of 41333 relevant lines covered (32.65%)

646.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

38.04
/src/mod_push_sql.erl
1
%%%----------------------------------------------------------------------
2
%%% File    : mod_push_sql.erl
3
%%% Author  : Evgeniy Khramtsov <ekhramtsov@process-one.net>
4
%%% Purpose : 
5
%%% Created : 26 Oct 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net>
6
%%%
7
%%%
8
%%% ejabberd, Copyright (C) 2017-2023   ProcessOne
9
%%%
10
%%% This program is free software; you can redistribute it and/or
11
%%% modify it under the terms of the GNU General Public License as
12
%%% published by the Free Software Foundation; either version 2 of the
13
%%% License, or (at your option) any later version.
14
%%%
15
%%% This program is distributed in the hope that it will be useful,
16
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
17
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
%%% General Public License for more details.
19
%%%
20
%%% You should have received a copy of the GNU General Public License along
21
%%% with this program; if not, write to the Free Software Foundation, Inc.,
22
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23
%%%
24
%%%----------------------------------------------------------------------
25

26
-module(mod_push_sql).
27
-behaviour(mod_push).
28

29
%% API
30
-export([init/2, store_session/6, lookup_session/4, lookup_session/3,
31
         lookup_sessions/3, lookup_sessions/2, lookup_sessions/1,
32
         delete_session/3, delete_old_sessions/2, export/1]).
33

34
-include_lib("xmpp/include/xmpp.hrl").
35
-include("logger.hrl").
36
-include("ejabberd_sql_pt.hrl").
37
-include("mod_push.hrl").
38

39
%%%===================================================================
40
%%% API
41
%%%===================================================================
42
init(Host, _Opts) ->
43
    ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
3✔
44
    ok.
3✔
45

46
schemas() ->
47
    [#sql_schema{
3✔
48
        version = 1,
49
        tables =
50
            [#sql_table{
51
                name = <<"push_session">>,
52
                columns =
53
                    [#sql_column{name = <<"username">>, type = text},
54
                     #sql_column{name = <<"server_host">>, type = text},
55
                     #sql_column{name = <<"timestamp">>, type = bigint},
56
                     #sql_column{name = <<"service">>, type = text},
57
                     #sql_column{name = <<"node">>, type = text},
58
                     #sql_column{name = <<"xml">>, type = text}],
59
                indices = [#sql_index{
60
                              columns = [<<"server_host">>, <<"username">>,
61
                                         <<"timestamp">>],
62
                              unique = true},
63
                           #sql_index{
64
                              columns = [<<"server_host">>, <<"username">>,
65
                                         <<"service">>, <<"node">>],
66
                              unique = true}]}]}].
67

68
store_session(LUser, LServer, NowTS, PushJID, Node, XData) ->
69
    XML = encode_xdata(XData),
6✔
70
    TS = misc:now_to_usec(NowTS),
6✔
71
    PushLJID = jid:tolower(PushJID),
6✔
72
    Service = jid:encode(PushLJID),
6✔
73
    MaxSessions = ejabberd_sm:get_max_user_sessions(LUser, LServer),
6✔
74
    enforce_max_sessions(LUser, LServer, MaxSessions),
6✔
75
    case ?SQL_UPSERT(LServer, "push_session",
6✔
76
                     ["!username=%(LUser)s",
77
                      "!server_host=%(LServer)s",
78
                      "timestamp=%(TS)d",
79
                      "!service=%(Service)s",
80
                      "!node=%(Node)s",
81
                      "xml=%(XML)s"]) of
82
        ok ->
83
            {ok, {NowTS, PushLJID, Node, XData}};
6✔
84
        _Err ->
85
            {error, db_failure}
×
86
    end.
87

88
lookup_session(LUser, LServer, PushJID, Node) ->
89
    PushLJID = jid:tolower(PushJID),
9✔
90
    Service = jid:encode(PushLJID),
9✔
91
    case ejabberd_sql:sql_query(
9✔
92
           LServer,
93
           ?SQL("select @(timestamp)d, @(xml)s from push_session "
9✔
94
                "where username=%(LUser)s and %(LServer)H "
95
                "and service=%(Service)s "
96
                "and node=%(Node)s")) of
97
        {selected, [{TS, XML}]} ->
98
            NowTS = misc:usec_to_now(TS),
6✔
99
            XData = decode_xdata(XML, LUser, LServer),
6✔
100
            {ok, {NowTS, PushLJID, Node, XData}};
6✔
101
        {selected, []} ->
102
            {error, notfound};
3✔
103
        _Err ->
104
            {error, db_failure}
×
105
    end.
106

107
lookup_session(LUser, LServer, NowTS) ->
108
    TS = misc:now_to_usec(NowTS),
×
109
    case ejabberd_sql:sql_query(
×
110
           LServer,
111
           ?SQL("select @(service)s, @(node)s, @(xml)s "
×
112
                "from push_session where username=%(LUser)s and %(LServer)H "
113
                "and timestamp=%(TS)d")) of
114
        {selected, [{Service, Node, XML}]} ->
115
            PushLJID = jid:tolower(jid:decode(Service)),
×
116
            XData = decode_xdata(XML, LUser, LServer),
×
117
            {ok, {NowTS, PushLJID, Node, XData}};
×
118
        {selected, []} ->
119
            {error, notfound};
×
120
        _Err ->
121
            {error, db_failure}
×
122
    end.
123

124
lookup_sessions(LUser, LServer, PushJID) ->
125
    PushLJID = jid:tolower(PushJID),
×
126
    Service = jid:encode(PushLJID),
×
127
    case ejabberd_sql:sql_query(
×
128
           LServer,
129
           ?SQL("select @(timestamp)d, @(xml)s, @(node)s from push_session "
×
130
                "where username=%(LUser)s and %(LServer)H "
131
                "and service=%(Service)s")) of
132
        {selected, Rows} ->
133
            {ok, lists:map(
×
134
                   fun({TS, XML, Node}) ->
135
                           NowTS = misc:usec_to_now(TS),
×
136
                           XData = decode_xdata(XML, LUser, LServer),
×
137
                           {NowTS, PushLJID, Node, XData}
×
138
                   end, Rows)};
139
        _Err ->
140
            {error, db_failure}
×
141
    end.
142

143
lookup_sessions(LUser, LServer) ->
144
    case ejabberd_sql:sql_query(
27✔
145
           LServer,
146
           ?SQL("select @(timestamp)d, @(xml)s, @(node)s, @(service)s "
27✔
147
                "from push_session "
148
                "where username=%(LUser)s and %(LServer)H")) of
149
        {selected, Rows} ->
150
            {ok, lists:map(
27✔
151
                   fun({TS, XML, Node, Service}) ->
152
                           NowTS = misc:usec_to_now(TS),
3✔
153
                           XData = decode_xdata(XML, LUser, LServer),
3✔
154
                           PushLJID = jid:tolower(jid:decode(Service)),
3✔
155
                           {NowTS, PushLJID,Node, XData}
3✔
156
                   end, Rows)};
157
        _Err ->
158
            {error, db_failure}
×
159
    end.
160

161
lookup_sessions(LServer) ->
162
    case ejabberd_sql:sql_query(
×
163
           LServer,
164
           ?SQL("select @(username)s, @(timestamp)d, @(xml)s, "
×
165
                "@(node)s, @(service)s from push_session "
166
                "where %(LServer)H")) of
167
        {selected, Rows} ->
168
            {ok, lists:map(
×
169
                   fun({LUser, TS, XML, Node, Service}) ->
170
                           NowTS = misc:usec_to_now(TS),
×
171
                           XData = decode_xdata(XML, LUser, LServer),
×
172
                           PushLJID = jid:tolower(jid:decode(Service)),
×
173
                           {NowTS, PushLJID, Node, XData}
×
174
                   end, Rows)};
175
        _Err ->
176
            {error, db_failure}
×
177
    end.
178

179
delete_session(LUser, LServer, NowTS) ->
180
    TS = misc:now_to_usec(NowTS),
6✔
181
    case ejabberd_sql:sql_query(
6✔
182
           LServer,
183
           ?SQL("delete from push_session where "
6✔
184
                "username=%(LUser)s and %(LServer)H and timestamp=%(TS)d")) of
185
        {updated, _} ->
186
            ok;
6✔
187
        _Err ->
188
            {error, db_failure}
×
189
    end.
190

191
delete_old_sessions(LServer, Time) ->
192
    TS = misc:now_to_usec(Time),
×
193
    case ejabberd_sql:sql_query(
×
194
           LServer,
195
           ?SQL("delete from push_session where timestamp<%(TS)d "
×
196
                "and %(LServer)H")) of
197
        {updated, _} ->
198
            ok;
×
199
        _Err ->
200
            {error, db_failure}
×
201
    end.
202

203
export(_Server) ->
204
    [{push_session,
×
205
      fun(Host, #push_session{us = {LUser, LServer},
206
                              timestamp = NowTS,
207
                              service = PushLJID,
208
                              node = Node,
209
                              xml = XData})
210
            when LServer == Host ->
211
              TS = misc:now_to_usec(NowTS),
×
212
              Service = jid:encode(PushLJID),
×
213
              XML = encode_xdata(XData),
×
214
              [?SQL("delete from push_session where "
×
215
                    "username=%(LUser)s and %(LServer)H and "
216
                    "timestamp=%(TS)d and "
217
                    "service=%(Service)s and node=%(Node)s and "
218
                    "xml=%(XML)s;"),
219
               ?SQL_INSERT(
×
220
                  "push_session",
221
                  ["username=%(LUser)s",
222
                   "server_host=%(LServer)s",
223
                   "timestamp=%(TS)d",
224
                   "service=%(Service)s",
225
                   "node=%(Node)s",
226
                   "xml=%(XML)s"])];
227
         (_Host, _R) ->
228
              []
×
229
      end}].
230

231
%%%===================================================================
232
%%% Internal functions
233
%%%===================================================================
234
enforce_max_sessions(_LUser, _LServer, infinity) ->
235
    ok;
×
236
enforce_max_sessions(LUser, LServer, MaxSessions) ->
237
    case lookup_sessions(LUser, LServer) of
6✔
238
        {ok, Sessions} when length(Sessions) >= MaxSessions ->
239
            ?INFO_MSG("Disabling old push session(s) of ~ts@~ts",
×
240
                      [LUser, LServer]),
×
241
            Sessions1 = lists:sort(fun({TS1, _, _, _}, {TS2, _, _, _}) ->
×
242
                                           TS1 >= TS2
×
243
                                   end, Sessions),
244
            OldSessions = lists:nthtail(MaxSessions - 1, Sessions1),
×
245
            lists:foreach(fun({TS, _, _, _}) ->
×
246
                                  delete_session(LUser, LServer, TS)
×
247
                          end, OldSessions);
248
        _ ->
249
            ok
6✔
250
    end.
251

252
decode_xdata(<<>>, _LUser, _LServer) ->
253
    undefined;
×
254
decode_xdata(XML, LUser, LServer) ->
255
    case fxml_stream:parse_element(XML) of
9✔
256
        #xmlel{} = El ->
257
            try xmpp:decode(El)
9✔
258
            catch _:{xmpp_codec, Why} ->
259
                    ?ERROR_MSG("Failed to decode ~ts for user ~ts@~ts "
×
260
                               "from table 'push_session': ~ts",
261
                               [XML, LUser, LServer, xmpp:format_error(Why)]),
×
262
                    undefined
×
263
            end;
264
        Err ->
265
            ?ERROR_MSG("Failed to decode ~ts for user ~ts@~ts from "
×
266
                       "table 'push_session': ~p",
267
                       [XML, LUser, LServer, Err]),
×
268
            undefined
×
269
    end.
270

271
encode_xdata(undefined) ->
272
    <<>>;
×
273
encode_xdata(XData) ->
274
    fxml:element_to_binary(xmpp:encode(XData)).
6✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc