./ct_report/coverage/mongoose_iq_handler.COVER.html

1 -module(mongoose_iq_handler).
2 -include("mongoose.hrl").
3 -include("jlib.hrl").
4
5 %%----------------------------------------------------------------------
6 %% Types
7 %%----------------------------------------------------------------------
8
9 -record(iq_handler, {handler_fn :: handler_fn(),
10 extra :: map(),
11 execution_method :: execution_method()}).
12
13 -type t() :: #iq_handler{}.
14
15 -type handler_fn() :: fun((Acc :: mongoose_acc:t(),
16 From :: jid:jid(),
17 To :: jid:jid(),
18 IQ :: jlib:iq(),
19 Extra :: map()) -> {NewAcc :: mongoose_acc:t(),
20 IQResp :: ignore | jlib:iq()}).
21
22 -type execution_method() :: no_queue | parallel | {one_queue, pid()} | {queues, [pid()]}.
23
24 -type execution_type() :: no_queue | parallel | one_queue | {queues, pos_integer()}.
25
26 -export_type([t/0, handler_fn/0, execution_type/0]).
27
28 %%----------------------------------------------------------------------
29 %% API
30 %%----------------------------------------------------------------------
31
32 -export([new/3,
33 delete/1,
34 process_iq/5,
35 add_extra/2,
36 execute_handler/5]).
37 %% Getters
38 -export([module/1, extra/1]).
39
40 -ignore_xref([module/1]).
41
42 -spec new(IQHandlerFn :: handler_fn(),
43 Extra :: map(),
44 ExecutionType :: execution_type()) -> t().
45 new(IQHandlerFn, Extra, ExecutionType) ->
46 2593 ExecutionMethod = execution_method(ExecutionType),
47 2593 #iq_handler{handler_fn = IQHandlerFn, extra = Extra,
48 execution_method = ExecutionMethod}.
49
50 -spec delete(IQHandler :: t()) -> ok.
51 delete(#iq_handler{execution_method = ExecutionMethod}) ->
52 2328 case ExecutionMethod of
53 1318 {one_queue, Pid} -> mongoose_iq_worker:stop(Pid);
54 {queues, Pids} ->
55
:-(
[mongoose_iq_worker:stop(Pid) || Pid <- Pids],
56
:-(
ok;
57 1010 _ -> ok
58 end.
59
60 -spec module(t()) -> module().
61 module(#iq_handler{handler_fn = Fn}) ->
62
:-(
{module, Mod} = erlang:fun_info(Fn, module),
63
:-(
Mod.
64
65 -spec process_iq(Handler :: t(),
66 Acc :: mongoose_acc:t(),
67 From :: jid:jid(),
68 To :: jid:jid(),
69 IQ :: jlib:iq()) -> mongoose_acc:t().
70 process_iq(#iq_handler{execution_method = ExecutionMethod} = Handler,
71 Acc, From, To, IQ) ->
72 3507 case ExecutionMethod of
73 no_queue ->
74 1473 ?MODULE:execute_handler(Handler, Acc, From, To, IQ);
75 {one_queue, Pid} ->
76 557 mongoose_iq_worker:process_iq(Pid, Handler, Acc, From, To, IQ),
77 557 Acc;
78 {queues, Pids} ->
79
:-(
Pid = lists:nth(rand:uniform(length(Pids)), Pids),
80
:-(
mongoose_iq_worker:process_iq(Pid, Handler, Acc, From, To, IQ),
81
:-(
Acc;
82 parallel ->
83 1477 spawn(?MODULE, execute_handler, [Handler, Acc, From, To, IQ]),
84 1477 Acc
85 end.
86
87 -spec extra(t()) -> map().
88 extra(#iq_handler{ extra = Extra }) ->
89 839 Extra.
90
91 -spec add_extra(t(), map()) -> t().
92 add_extra(#iq_handler{ extra = OldExtra } = Handler, Extra) ->
93 %% KV pairs from the OldExtra map will remain unchanged, only
94 %% the new keys from Extra map will be added to the NewExtra map
95 2537 NewExtra = maps:merge(Extra, OldExtra),
96 2537 Handler#iq_handler{extra = NewExtra}.
97
98 -spec execute_handler(Handler :: t(),
99 Acc :: mongoose_acc:t(),
100 From :: jid:jid(),
101 To :: jid:jid(),
102 IQ :: jlib:iq()) -> mongoose_acc:t().
103 execute_handler(#iq_handler{handler_fn = IQHandlerFn, extra = Extra},
104 Acc, From, To, IQ = #iq{sub_el = SubEl, lang = Lang}) ->
105 3507 try IQHandlerFn(Acc, From, To, IQ, Extra) of
106 {Acc1, ignore} ->
107 108 Acc1;
108 {Acc1, ResIQ} ->
109 3399 reply(From, To, Acc1, ResIQ)
110 catch
111 Class:Reason:StackTrace ->
112
:-(
?LOG_WARNING(#{what => process_iq_error, from => From, to => To, iq => IQ,
113 acc => Acc, extra => Extra, handler_function => IQHandlerFn,
114
:-(
class => Class, reason => Reason, stacktrace => StackTrace}),
115
:-(
ErrorMsg = <<"The server could not process the IQ stanza">>,
116
:-(
ErrorEl = mongoose_xmpp_errors:internal_server_error(Lang, ErrorMsg),
117
:-(
ErrorIQ = IQ#iq{type = error, sub_el = [SubEl, ErrorEl]},
118
:-(
reply(From, To, Acc, ErrorIQ)
119 end.
120
121 -spec reply(jid:jid(), jid:jid(), mongoose_acc:t(), jlib:iq()) -> mongoose_acc:t().
122 reply(From, To, Acc, IQReply) ->
123 3399 ejabberd_router:route(To, From, Acc, jlib:iq_to_xml(IQReply)).
124
125 %%--------------------------------------------------------------------
126 %% Internal functions
127 %%--------------------------------------------------------------------
128 -spec execution_method(execution_type()) -> execution_method().
129 execution_method(ExecutionType) ->
130 2593 case ExecutionType of
131 393 no_queue -> no_queue;
132 617 parallel -> parallel;
133 one_queue ->
134 1583 {ok, Pid} = mongoose_iq_worker:start(),
135 1583 {one_queue, Pid};
136 {queues, N} ->
137
:-(
Pids = lists:map(fun(_) ->
138
:-(
{ok, Pid} = mongoose_iq_worker:start(),
139
:-(
Pid
140 end, lists:seq(1, N)),
141
:-(
{queues, Pids}
142 end.
Line Hits Source