./ct_report/coverage/mod_event_pusher_http.COVER.html

1 %%%----------------------------------------------------------------------
2 %%% File : mod_event_pusher_http.erl
3 %%% Author : Baibossynv Valery <baibossynov.valery@gmail.com>
4 %%% Purpose : Message passing via http
5 %%% Created : 16 Dec 2015 by Baibossynv Valery <baibossynov.valery@gmail.com>
6 %%%----------------------------------------------------------------------
7
8 -module(mod_event_pusher_http).
9 -author("baibossynov.valery@gmail.com").
10
11 -ignore_xref([behaviour_info/1]).
12
13 -behaviour(gen_mod).
14 -behaviour(mod_event_pusher).
15 -behaviour(mongoose_module_metrics).
16
17 -callback should_make_req(Acc :: mongoose_acc:t(),
18 Dir :: in | out,
19 Packet :: exml:element(),
20 From :: jid:jid(),
21 To :: jid:jid(),
22 Opts :: [{atom(), term()}]) -> boolean().
23 -callback prepare_headers(Acc :: mongoose_acc:t(),
24 Dir :: in | out,
25 Domain :: jid:lserver(),
26 Message :: binary(),
27 Sender :: jid:luser(),
28 Receiver :: jid:luser(),
29 Opts :: [{atom(), term()}]) -> [{binary(), binary()}].
30 -callback prepare_body(Acc :: mongoose_acc:t(),
31 Dir :: in | out,
32 Domain :: jid:lserver(),
33 Message :: binary(),
34 Sender :: jid:luser(),
35 Receiver :: jid:luser(),
36 Opts :: [{atom(), term()}]) -> binary().
37
38 -include("mod_event_pusher_events.hrl").
39 -include("jlib.hrl").
40
41 %% API
42 -export([start/2, stop/1, config_spec/0, push_event/2]).
43
44 %% config spec callbacks
45 -export([fix_path/1]).
46
47 -include("mongoose.hrl").
48 -include("jlib.hrl").
49 -include("mongoose_config_spec.hrl").
50
51 -define(SENT_METRIC, [mod_event_pusher_http, sent]).
52 -define(FAILED_METRIC, [mod_event_pusher_http, failed]).
53 -define(RESPONSE_METRIC, [mod_event_pusher_http, response_time]).
54
55 -spec start(mongooseim:host_type(), gen_mod:module_opts()) -> ok.
56 start(HostType, _Opts) ->
57 5 ensure_metrics(HostType),
58 5 ok.
59
60 -spec stop(mongooseim:host_type()) -> ok.
61 stop(_HostType) ->
62 5 ok.
63
64 -spec config_spec() -> mongoose_config_spec:config_section().
65 config_spec() ->
66 166 #section{items = #{<<"handlers">> => #list{items = handler_config_spec(),
67 validate = unique}},
68 defaults = #{<<"handlers">> => []},
69 format_items = map}.
70
71 handler_config_spec() ->
72 166 #section{items = #{<<"pool_name">> => #option{type = atom,
73 validate = pool_name},
74 <<"path">> => #option{type = binary,
75 process = fun ?MODULE:fix_path/1},
76 <<"callback_module">> => #option{type = atom,
77 validate = module}
78 },
79 defaults = #{<<"pool_name">> => http_pool,
80 <<"path">> => <<>>,
81 <<"callback_module">> => mod_event_pusher_http_defaults},
82 format_items = map
83 }.
84
85 push_event(Acc, #chat_event{direction = Dir, from = From, to = To, packet = Packet}) ->
86 62 HostType = mongoose_acc:host_type(Acc),
87 62 lists:map(fun(Opts) -> push_event(Acc, Dir, From, To, Packet, Opts) end,
88 gen_mod:get_module_opt(HostType, ?MODULE, handlers)),
89 62 Acc;
90 push_event(Acc, _Event) ->
91 44 Acc.
92
93 push_event(Acc, Dir, From, To, Packet, Opts = #{callback_module := Mod}) ->
94 68 Body = exml_query:path(Packet, [{element, <<"body">>}, cdata], <<>>),
95 68 case Mod:should_make_req(Acc, Dir, Packet, From, To, Opts) of
96 true ->
97 19 make_req(Acc, Dir, From#jid.lserver, From#jid.luser, To#jid.luser, Body, Opts);
98 _ ->
99 49 ok
100 end,
101 68 Acc.
102
103 %%%===================================================================
104 %%% Internal functions
105 %%%===================================================================
106
107 make_req(Acc, Dir, Domain, Sender, Receiver, Message, Opts) ->
108 19 #{pool_name := PoolName, path := Path, callback_module := Mod} = Opts,
109 19 HostType = mongoose_acc:host_type(Acc),
110 19 Body = Mod:prepare_body(Acc, Dir, Domain, Message, Sender, Receiver, Opts),
111 19 Headers = Mod:prepare_headers(Acc, Dir, Domain, Message, Sender, Receiver, Opts),
112 19 LogMeta = #{what => event_pusher_http_req,
113 text => <<"mod_event_pusher_http makes an external HTTP call">>,
114 path => Path, body => Body, headers => Headers,
115 sender => Sender, receiver => Receiver, direction => Dir,
116 server => Domain, pool_name => PoolName, acc => Acc},
117 19 ?LOG_INFO(LogMeta),
118 19 T0 = os:timestamp(),
119 19 {Res, Elapsed} = case mongoose_http_client:post(HostType, PoolName, Path, Headers, Body) of
120 {ok, _} ->
121 17 {ok, timer:now_diff(os:timestamp(), T0)};
122 {error, Reason} ->
123 2 {{error, Reason}, 0}
124 end,
125 19 record_result(HostType, Res, Elapsed, LogMeta),
126 19 ok.
127
128 ensure_metrics(HostType) ->
129 5 mongoose_metrics:ensure_metric(HostType, ?SENT_METRIC, spiral),
130 5 mongoose_metrics:ensure_metric(HostType, ?FAILED_METRIC, spiral),
131 5 mongoose_metrics:ensure_metric(HostType, ?RESPONSE_METRIC, histogram),
132 5 ok.
133
134 record_result(HostType, ok, Elapsed, _LogMeta) ->
135 17 mongoose_metrics:update(HostType, ?SENT_METRIC, 1),
136 17 mongoose_metrics:update(HostType, ?RESPONSE_METRIC, Elapsed),
137 17 ok;
138 record_result(HostType, {error, Reason}, _, LogMeta) ->
139 2 mongoose_metrics:update(HostType, ?FAILED_METRIC, 1),
140 2 ?LOG_WARNING(LogMeta#{what => event_pusher_http_req_failed,
141 text => <<"mod_event_pusher_http HTTP call failed">>,
142 reason => Reason
143
:-(
}),
144 2 ok.
145
146 %% @doc Strip initial slash (it is added by mongoose_http_client)
147 fix_path(<<"/", R/binary>>) ->
148
:-(
R;
149 fix_path(R) ->
150
:-(
R.
Line Hits Source