./ct_report/coverage/mongoose_session_api.COVER.html

1 %% @doc Provide an interface for frontends (like graphql or ctl) to manage sessions.
2 -module(mongoose_session_api).
3
4 -export([list_sessions/0,
5 list_sessions/1,
6 count_sessions/0,
7 count_sessions/1,
8 list_user_sessions/1,
9 list_user_sessions/2,
10 list_resources/1,
11 list_user_resources/1,
12 num_resources/1,
13 num_resources/2,
14 get_user_resource/2,
15 get_user_resource/3,
16 list_status_users/1,
17 list_status_users/2,
18 num_status_users/1,
19 num_status_users/2,
20 set_presence/7,
21 set_presence/5,
22 kick_session/2,
23 kick_session/4,
24 kick_sessions/2,
25 prepare_reason/1]).
26
27 -ignore_xref([prepare_reason/1,
28 get_user_resources/2,
29 list_user_sessions/1,
30 num_resources/1]).
31
32 -include("session.hrl").
33 -include_lib("jid/include/jid.hrl").
34 -include_lib("exml/include/exml.hrl").
35
36 -type status() :: binary().
37 -type session() :: #session{}.
38 -type status_user_info() :: {User :: jid:user(),
39 Server :: jid:server(),
40 Res :: jid:resource(),
41 Prio :: ejabberd_sm:priority(),
42 Status :: status()}.
43
44 -type session_info() :: {USR :: binary(),
45 Conn :: binary(),
46 IPS :: binary(),
47 Port :: inet:port_number(),
48 Prio :: ejabberd_sm:priority(),
49 NodeS :: binary(),
50 Uptime :: integer()}.
51
52 -type res_number_result() :: {ok | wrong_res_number, binary()}.
53
54 -type kick_session_result() :: {ok | no_session, binary()}.
55
56 -type set_presence_result() :: {ok | empty_resource, binary()}.
57
58 -export_type([res_number_result/0,
59 kick_session_result/0,
60 set_presence_result/0,
61 status_user_info/0,
62 session_info/0,
63 status/0]).
64
65 -spec list_sessions() -> [session_info()].
66 list_sessions() ->
67 2 USRIs = ejabberd_sm:get_full_session_list(),
68 2 lists:map(fun format_user_info/1, USRIs).
69
70 -spec list_sessions(jid:server()) -> [session_info()].
71 list_sessions(Host) ->
72 3 USRIs = ejabberd_sm:get_vh_session_list(Host),
73 3 lists:map(fun format_user_info/1, USRIs).
74
75 -spec count_sessions() -> non_neg_integer().
76 count_sessions() ->
77 1 ejabberd_sm:get_total_sessions_number().
78
79 -spec count_sessions(jid:server()) -> non_neg_integer().
80 count_sessions(Host) ->
81 1 ejabberd_sm:get_vh_session_number(Host).
82
83 -spec list_resources(jid:server()) -> [jid:literal_jid()].
84 list_resources(Host) ->
85 3 Lst = ejabberd_sm:get_vh_session_list(Host),
86 3 [jid:to_binary(USR) || #session{usr = USR} <- Lst].
87
88 -spec list_user_resources(jid:jid()) -> [jid:literal_jid()].
89 list_user_resources(JID) ->
90 2 ejabberd_sm:get_user_resources(JID).
91
92 -spec list_user_sessions(jid:user(), jid:server()) -> [session_info()].
93 list_user_sessions(User, Host) ->
94 1 JID = jid:make(User, Host, <<>>),
95 1 list_user_sessions(JID).
96
97 -spec list_user_sessions(jid:jid()) -> [session_info()].
98 list_user_sessions(JID) ->
99 3 Resources = ejabberd_sm:get_user_resources(JID),
100 3 lists:foldl(fun(Res, Acc) ->
101 4 RJID = jid:replace_resource(JID, Res),
102 4 case ejabberd_sm:get_session(RJID) of
103
:-(
offline -> Acc;
104 4 Session -> [format_user_info(Session) | Acc]
105 end
106 end, [], Resources).
107
108 -spec num_resources(jid:user(), jid:server()) -> non_neg_integer().
109 num_resources(User, Host) ->
110 1 JID = jid:make(User, Host, <<>>),
111 1 num_resources(JID).
112
113 -spec num_resources(jid:jid()) -> non_neg_integer().
114 num_resources(JID) ->
115 2 length(ejabberd_sm:get_user_resources(JID)).
116
117 -spec get_user_resource(jid:user(), jid:server(), integer()) -> res_number_result().
118 get_user_resource(User, Host, Num) ->
119 1 JID = jid:make(User, Host, <<>>),
120 1 get_user_resource(JID, Num).
121
122 -spec get_user_resource(jid:jid(), integer()) -> res_number_result().
123 get_user_resource(JID, Num) ->
124 6 Resources = ejabberd_sm:get_user_resources(JID),
125 6 case (0 < Num) and (Num =< length(Resources)) of
126 true ->
127 4 {ok, lists:nth(Num, Resources)};
128 false ->
129 2 {wrong_res_number, iolist_to_binary(io_lib:format("Wrong resource number: ~p", [Num]))}
130 end.
131
132 -spec num_status_users(jid:server(), status()) -> non_neg_integer().
133 num_status_users(Host, Status) ->
134 3 length(list_status_users(Host, Status)).
135
136 -spec num_status_users(status()) -> non_neg_integer().
137 num_status_users(Status) ->
138 3 length(list_status_users(Status)).
139
140 -spec list_status_users(jid:server(), status()) -> [status_user_info()].
141 list_status_users(Host, Status) ->
142 6 Sessions = ejabberd_sm:get_vh_session_list(Host),
143 6 get_status_list(Sessions, Status).
144
145 -spec list_status_users(status()) -> [status_user_info()].
146 list_status_users(Status) ->
147 6 Sessions = ejabberd_sm:get_full_session_list(),
148 6 get_status_list(Sessions, Status).
149
150 -spec set_presence(jid:user(), jid:server(), jid:resource(),
151 Type :: binary(), Show :: binary(), Status :: binary(),
152 Prio :: binary()) -> set_presence_result().
153 set_presence(User, Host, Resource, Type, Show, Status, Priority) ->
154 1 JID = jid:make(User, Host, Resource),
155 1 set_presence(JID, Type, Show, Status, Priority).
156
157 -spec set_presence(jid:jid(), Type :: binary(), Show :: binary(),
158 Status :: binary(), Prio :: binary()) -> set_presence_result().
159 set_presence(#jid{resource = <<>>}, _Type, _Show, _Status, _Priority) ->
160 1 {empty_resource, <<"The resource is empty. You need to provide a full JID">>};
161 set_presence(JID, Type, Show, Status, Priority) ->
162 4 Pid = ejabberd_sm:get_session_pid(JID),
163 4 USR = jid:to_binary(JID),
164 4 US = jid:to_binary(jid:to_bare(JID)),
165
166 4 Children = maybe_pres_status(Status,
167 maybe_pres_priority(Priority,
168 maybe_pres_show(Show, []))),
169 4 Message = {xmlstreamelement,
170 #xmlel{name = <<"presence">>,
171 attrs = [{<<"from">>, USR}, {<<"to">>, US} | maybe_type_attr(Type)],
172 children = Children}},
173 4 ok = p1_fsm_old:send_event(Pid, Message),
174 4 {ok, <<"Presence set successfully">>}.
175
176 -spec kick_sessions(jid:jid(), binary()) -> [kick_session_result()].
177 kick_sessions(JID, Reason) ->
178 3 lists:map(
179 fun(Resource) ->
180 2 service_admin_extra_sessions:kick_session(
181 jid:replace_resource(JID, Resource), Reason)
182 end,
183 ejabberd_sm:get_user_resources(JID)).
184
185 -spec kick_session(jid:user(), jid:server(), jid:resource(), binary()) -> kick_session_result().
186 kick_session(User, Server, Resource, ReasonText) ->
187 3 kick_session(jid:make(User, Server, Resource), prepare_reason(ReasonText)).
188
189 -spec kick_session(jid:jid(), binary()) -> kick_session_result().
190 kick_session(JID, ReasonText) ->
191 9 case ejabberd_c2s:terminate_session(JID, prepare_reason(ReasonText)) of
192 no_session ->
193 3 {no_session, <<"No active session">>};
194 {exit, ReasonText} ->
195 6 {ok, <<"Session kicked">>}
196 end.
197
198 -spec prepare_reason(binary() | string()) -> binary().
199 prepare_reason(<<>>) ->
200
:-(
<<"Kicked by administrator">>;
201 prepare_reason([Reason]) ->
202
:-(
prepare_reason(Reason);
203 prepare_reason(Reason) when is_list(Reason) ->
204
:-(
list_to_binary(Reason);
205 prepare_reason(Reason) when is_binary(Reason) ->
206 15 Reason.
207
208 %% Internal
209
210 -spec get_status_list([session()], status()) -> [status_user_info()].
211 get_status_list(Sessions0, StatusRequired) ->
212 12 Sessions = [ {catch ejabberd_c2s:get_presence(Pid), S, P}
213 12 || #session{sid = {_, Pid}, usr = {_, S, _}, priority = P} <- Sessions0
214 ],
215
216 12 [{User, Server, Resource, Priority, StatusText}
217 12 || {{User, Resource, Status, StatusText}, Server, Priority} <- Sessions,
218 22 Status == StatusRequired].
219
220 -spec format_user_info(ejabberd_sm:session()) -> session_info().
221 format_user_info(#session{sid = {Microseconds, Pid}, usr = Usr,
222 priority = Priority, info = Info}) ->
223 14 Conn = atom_to_binary(maps:get(conn, Info, undefined)),
224 14 {Ip, Port} = maps:get(ip, Info, undefined),
225 14 IPS = list_to_binary(inet_parse:ntoa(Ip)),
226 14 NodeS = atom_to_binary(node(Pid)),
227 14 Uptime = (erlang:system_time(microsecond) - Microseconds) div 1000000,
228 14 BinJID = jid:to_binary(Usr),
229 14 {BinJID, Conn, IPS, Port, Priority, NodeS, Uptime}.
230
231 -spec maybe_type_attr(binary())-> list().
232 maybe_type_attr(<<"available">>) ->
233 3 [];
234 maybe_type_attr(Type) ->
235 1 [{<<"type">>, Type}].
236
237 -spec maybe_pres_show(binary(), list()) -> list().
238 maybe_pres_show(Show, Children) when Show =:= <<>>;
239 Show =:= <<"online">> ->
240 2 Children;
241 maybe_pres_show(Show, Children) ->
242 2 [#xmlel{name = <<"show">>,
243 children = [#xmlcdata{content = Show}]} | Children].
244
245 -spec maybe_pres_priority(binary(), list()) -> list().
246 maybe_pres_priority(<<>>, Children) ->
247 2 Children;
248 maybe_pres_priority(Prio, Children) ->
249 2 [#xmlel{name = <<"priority">>,
250 children = [#xmlcdata{content = Prio}]} | Children].
251
252 -spec maybe_pres_status(binary(), list()) -> list().
253 maybe_pres_status(<<>>, Children) ->
254 1 Children;
255 maybe_pres_status(Status, Children) ->
256 3 [#xmlel{name = <<"status">>,
257 children = [#xmlcdata{content = Status}]} | Children].
Line Hits Source