./ct_report/coverage/mongoose_c2s_acc.COVER.html

1 %% @doc Interface for actions that handler modules might request `mongoose_c2s' to act upon.
2 %% Note that some of the keys take a list of elements, which, in the case of a hook with many
3 %% handlers, means that at the end of the queue `mongoose_c2s' will get a list of requests
4 %% by different modules. These will be acted upon in the same order they were inserted in the
5 %% hook list, according to their priority.
6 %% The following keys are defined:
7 %% - `state_mod': key-value pairs of gen_mod module names and their desired state.
8 %% - `actions': a list of valid `gen_statem:action()' to request the `mongoose_c2s' engine.
9 %% - `c2s_state': a new state is requested for the state machine.
10 %% - `c2s_data': a new state data is requested for the state machine.
11 %% - `stop': an action of type `{cast, {stop, Reason}}' is to be triggered.
12 %% - `hard_stop': no other request is allowed, the state machine is immediatly triggered to stop.
13 %% - `route': mongoose_acc elements to trigger the whole `handle_route' pipeline.
14 %% - `flush': mongoose_acc elements to trigger the `handle_flush` pipeline.
15 %% - `socket_send': xml elements to send on the socket to the user.
16 %% - `socket_send_first': xml elements to send on the socket to the user, but appended first.
17 -module(mongoose_c2s_acc).
18
19 -export([new/0, new/1,
20 get_statem_result/1,
21 from_mongoose_acc/2,
22 to_acc/3, to_acc_many/2
23 ]).
24
25 -type key() :: state_mod
26 | actions
27 | c2s_state
28 | c2s_data
29 | stop
30 | hard_stop
31 | route
32 | flush
33 | socket_send
34 | socket_send_first.
35 -type pairs() :: [pair()].
36 -type pair() :: {state_mod, {module(), term()}}
37 | {actions, gen_statem:action()}
38 | {c2s_state, mongoose_c2s:state()}
39 | {c2s_data, mongoose_c2s:data()}
40 | {stop, term() | {shutdown, atom()}}
41 | {hard_stop, term() | {shutdown, atom()}}
42 | {route, mongoose_acc:t()}
43 | {flush, mongoose_acc:t()}
44 | {socket_send, exml:element() | [exml:element()]}
45 | {socket_send_first, exml:element() | [exml:element()]}.
46
47 -type t() :: #{
48 state_mod := #{module() => term()},
49 actions := [gen_statem:action()],
50 c2s_state := undefined | mongoose_c2s:state(),
51 c2s_data := undefined | mongoose_c2s:data(),
52 hard_stop := undefined | Reason :: term(),
53 socket_send := [exml:element()]
54 }.
55
56 -type params() :: #{
57 state_mod => #{module() => term()},
58 actions => [gen_statem:action()],
59 c2s_state => mongoose_c2s:state(),
60 c2s_data => mongoose_c2s:data(),
61 stop => Reason :: term(),
62 hard_stop => Reason :: term(),
63 route => [mongoose_acc:t()],
64 flush => [mongoose_acc:t()],
65 socket_send => [exml:element()]
66 }.
67
68 -export_type([t/0, pairs/0]).
69
70 %% --------------------------------------------------------
71 %% API
72 %% --------------------------------------------------------
73
74 -spec new() -> t().
75 new() ->
76 120272 #{
77 state_mod => #{},
78 actions => [],
79 c2s_state => undefined,
80 c2s_data => undefined,
81 hard_stop => undefined,
82 socket_send => []
83 }.
84
85 -spec new(params()) -> t().
86 new(Params) ->
87 11637 Params1 = extract_stop(Params),
88 11637 Params2 = extract_routes(Params1),
89 11637 Params3 = extract_flushes(Params2),
90 11637 maps:merge(new(), Params3).
91
92 extract_stop(Params = #{stop := Reason}) ->
93 4 WithoutStop = maps:remove(stop, Params),
94 4 NewAction = [{next_event, cast, {stop, Reason}}],
95 4 Fun = fun(Actions) -> [NewAction | Actions] end,
96 4 maps:update_with(actions, Fun, NewAction, WithoutStop);
97 extract_stop(Params) ->
98 11633 Params.
99
100 extract_flushes(Params = #{flush := Accs}) ->
101
:-(
WithoutFlush = maps:remove(flush, Params),
102
:-(
NewAction = [{next_event, internal, {flush, Acc}} || Acc <- Accs ],
103
:-(
Fun = fun(Actions) -> NewAction ++ Actions end,
104
:-(
maps:update_with(actions, Fun, NewAction, WithoutFlush);
105 extract_flushes(Params) ->
106 11637 Params.
107
108 extract_routes(Params = #{route := Accs}) ->
109 5810 WithoutRoute = maps:remove(route, Params),
110 5810 NewAction = [{next_event, info, {route, Acc}} || Acc <- Accs ],
111 5810 Fun = fun(Actions) -> NewAction ++ Actions end,
112 5810 maps:update_with(actions, Fun, NewAction, WithoutRoute);
113 extract_routes(Params) ->
114 5827 Params.
115
116 -spec get_statem_result(mongoose_acc:t()) -> mongoose_c2s_acc:t().
117 get_statem_result(Acc) ->
118 63935 C2SAcc = #{actions := Actions,
119 socket_send := SocketSend} = mongoose_acc:get_statem_acc(Acc),
120 63935 C2SAcc#{actions := lists:reverse(Actions),
121 socket_send := lists:reverse(SocketSend)}.
122
123 -spec from_mongoose_acc(mongoose_acc:t(), key()) -> term().
124 from_mongoose_acc(Acc, Key) ->
125
:-(
#{Key := Value} = mongoose_acc:get_statem_acc(Acc),
126
:-(
Value.
127
128 -spec to_acc(mongoose_acc:t(), state_mod, {module(), term()}) -> mongoose_acc:t();
129 (mongoose_acc:t(), actions, gen_statem:action() | [gen_statem:action()]) -> mongoose_acc:t();
130 (mongoose_acc:t(), c2s_state, mongoose_c2s:state()) -> mongoose_acc:t();
131 (mongoose_acc:t(), c2s_data, mongoose_c2s:data()) -> mongoose_acc:t();
132 (mongoose_acc:t(), hard_stop, atom()) -> mongoose_acc:t();
133 (mongoose_acc:t(), stop, atom() | {shutdown, atom()}) -> mongoose_acc:t();
134 (mongoose_acc:t(), route, mongoose_acc:t()) -> mongoose_acc:t();
135 (mongoose_acc:t(), flush, mongoose_acc:t()) -> mongoose_acc:t();
136 (mongoose_acc:t(), socket_send, exml:element() | [exml:element()]) -> mongoose_acc:t();
137 (mongoose_acc:t(), socket_send_first, exml:element() | [exml:element()]) -> mongoose_acc:t().
138 to_acc(Acc, Key, NewValue) ->
139 15438 C2SAcc = mongoose_acc:get_statem_acc(Acc),
140 15438 C2SAcc1 = to_c2s_acc(C2SAcc, {Key, NewValue}),
141 15438 mongoose_acc:set_statem_acc(C2SAcc1, Acc).
142
143 -spec to_acc_many(mongoose_acc:t(), pairs()) -> mongoose_acc:t().
144 to_acc_many(Acc, Pairs) ->
145 5497 C2SAcc = mongoose_acc:get_statem_acc(Acc),
146 5497 to_acc_many(Acc, C2SAcc, Pairs).
147
148 -spec to_acc_many(mongoose_acc:t(), mongoose_c2s_acc:t(), pairs()) -> mongoose_acc:t().
149 to_acc_many(Acc, C2SAcc, []) ->
150 5497 mongoose_acc:set_statem_acc(C2SAcc, Acc);
151 to_acc_many(Acc, C2SAcc, [Pair | Pairs]) ->
152 11072 NewCAcc = to_c2s_acc(C2SAcc, Pair),
153 11072 to_acc_many(Acc, NewCAcc, Pairs).
154
155 -spec to_c2s_acc(mongoose_c2s_acc:t(), pair()) -> mongoose_c2s_acc:t().
156 to_c2s_acc(C2SAcc = #{state_mod := ModStates}, {state_mod, {ModName, ModState}}) ->
157 14668 C2SAcc#{state_mod := ModStates#{ModName => ModState}};
158 to_c2s_acc(C2SAcc = #{actions := Actions}, {actions, NewActions}) when is_list(NewActions) ->
159 6109 C2SAcc#{actions := lists:reverse(NewActions) ++ Actions};
160 to_c2s_acc(C2SAcc = #{actions := Actions}, {actions, Action}) ->
161 124 C2SAcc#{actions := [Action | Actions]};
162 to_c2s_acc(C2SAcc = #{actions := Actions}, {route, Accs}) when is_list(Accs) ->
163 5111 Routes = [{next_event, info, {route, Acc}} || Acc <- Accs ],
164 5111 C2SAcc#{actions := lists:reverse(Routes) ++ Actions};
165 to_c2s_acc(C2SAcc = #{actions := Actions}, {route, Acc}) ->
166 118 C2SAcc#{actions := [{next_event, info, {route, Acc}} | Actions]};
167 to_c2s_acc(C2SAcc = #{actions := Actions}, {flush, Accs}) when is_list(Accs) ->
168 8 Routes = [{next_event, internal, {flush, Acc}} || Acc <- Accs ],
169 8 C2SAcc#{actions := lists:reverse(Routes) ++ Actions};
170 to_c2s_acc(C2SAcc = #{actions := Actions}, {flush, Acc}) ->
171 18 C2SAcc#{actions := [{next_event, internal, {flush, Acc}} | Actions]};
172 to_c2s_acc(C2SAcc = #{socket_send := Stanzas}, {socket_send, NewStanzas}) when is_list(NewStanzas) ->
173 12 C2SAcc#{socket_send := lists:reverse(NewStanzas) ++ Stanzas};
174 to_c2s_acc(C2SAcc = #{socket_send := Stanzas}, {socket_send, Stanza}) ->
175 194 C2SAcc#{socket_send := [Stanza | Stanzas]};
176 to_c2s_acc(C2SAcc = #{socket_send := Stanzas}, {socket_send_first, NewStanzas}) when is_list(NewStanzas) ->
177
:-(
C2SAcc#{socket_send := Stanzas ++ lists:reverse(NewStanzas)};
178 to_c2s_acc(C2SAcc = #{socket_send := Stanzas}, {socket_send_first, Stanza}) ->
179 20 C2SAcc#{socket_send := Stanzas ++ [Stanza]};
180 to_c2s_acc(C2SAcc = #{actions := Actions}, {stop, Reason}) ->
181 4 C2SAcc#{actions := [{next_event, cast, {stop, Reason}} | Actions]};
182 to_c2s_acc(C2SAcc, {Key, NewValue}) ->
183 124 #{Key := _OldValue} = C2SAcc,
184 124 C2SAcc#{Key := NewValue}.
Line Hits Source