|
|
@@ -14,7 +14,7 @@
|
|
|
%% limitations under the License.
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
|
|
-%% transport manager
|
|
|
+%% the transport state machine manager
|
|
|
-module(emqx_coap_tm).
|
|
|
|
|
|
-export([ new/0
|
|
|
@@ -23,23 +23,23 @@
|
|
|
, handle_out/3
|
|
|
, timeout/3]).
|
|
|
|
|
|
--export_type([manager/0, event_result/2]).
|
|
|
+-export_type([manager/0, event_result/1]).
|
|
|
|
|
|
-include_lib("emqx/include/logger.hrl").
|
|
|
-include_lib("emqx_gateway/src/coap/include/emqx_coap.hrl").
|
|
|
|
|
|
-type direction() :: in | out.
|
|
|
--type transport_id() :: {direction(), non_neg_integer()}.
|
|
|
+-type state_machine_id() :: {direction(), non_neg_integer()}.
|
|
|
|
|
|
--record(transport, { id :: transport_id()
|
|
|
- , state :: atom()
|
|
|
- , timers :: maps:map()
|
|
|
- , data :: any()}).
|
|
|
--type transport() :: #transport{}.
|
|
|
+-record(state_machine, { id :: state_machine_id()
|
|
|
+ , state :: atom()
|
|
|
+ , timers :: maps:map()
|
|
|
+ , transport :: emqx_coap_transport:transport()}).
|
|
|
+-type state_machine() :: #state_machine{}.
|
|
|
|
|
|
-type message_id() :: 0 .. ?MAX_MESSAGE_ID.
|
|
|
|
|
|
--type manager() :: #{message_id() => transport()}.
|
|
|
+-type manager() :: #{message_id() => state_machine()}.
|
|
|
|
|
|
-type ttimeout() :: {state_timeout, pos_integer(), any()}
|
|
|
| {stop_timeout, pos_integer()}.
|
|
|
@@ -47,32 +47,31 @@
|
|
|
-type topic() :: binary().
|
|
|
-type token() :: binary().
|
|
|
-type sub_register() :: {topic(), token()} | topic().
|
|
|
-
|
|
|
--type event_result(State, Data) ::
|
|
|
+-type event_result(State) ::
|
|
|
#{next => State,
|
|
|
outgoing => emqx_coap_message(),
|
|
|
timeouts => list(ttimeout()),
|
|
|
has_sub => undefined | sub_register(),
|
|
|
- data => Data}.
|
|
|
+ transport => emqx_coap_transport:transprot()}.
|
|
|
|
|
|
-%%%===================================================================
|
|
|
-%%% API
|
|
|
-%%%===================================================================
|
|
|
+%%--------------------------------------------------------------------
|
|
|
+%% API
|
|
|
+%%--------------------------------------------------------------------
|
|
|
new() ->
|
|
|
#{}.
|
|
|
|
|
|
-handle_request(#coap_message{id = MsgId} = Msg, TM, Cfg) ->
|
|
|
+handle_request(#coap_message{id = MsgId} = Msg, Cfg, TM) ->
|
|
|
Id = {in, MsgId},
|
|
|
case maps:get(Id, TM, undefined) of
|
|
|
- undefined ->
|
|
|
- Data = emqx_coap_transport:new(),
|
|
|
- Transport = new_transport(Id, Data),
|
|
|
- process_event(in, Msg, TM, Transport, Cfg);
|
|
|
- TP ->
|
|
|
- process_event(in, Msg, TM, TP, Cfg)
|
|
|
+ undefined ->
|
|
|
+ Transport = emqx_coap_transport:new(),
|
|
|
+ Machine = new_state_machine(Id, Transport),
|
|
|
+ process_event(in, Msg, TM, Machine, Cfg);
|
|
|
+ Machine ->
|
|
|
+ process_event(in, Msg, TM, Machine, Cfg)
|
|
|
end.
|
|
|
|
|
|
-handle_response(#coap_message{type = Type, id = MsgId} = Msg, TM, Cfg) ->
|
|
|
+handle_response(#coap_message{type = Type, id = MsgId} = Msg, Cfg, TM) ->
|
|
|
Id = {out, MsgId},
|
|
|
case maps:get(Id, TM, undefined) of
|
|
|
undefined ->
|
|
|
@@ -83,56 +82,50 @@ handle_response(#coap_message{type = Type, id = MsgId} = Msg, TM, Cfg) ->
|
|
|
#{out => #coap_message{type = reset,
|
|
|
id = MsgId}}
|
|
|
end;
|
|
|
- TP ->
|
|
|
- process_event(in, Msg, TM, TP, Cfg)
|
|
|
+ Machine ->
|
|
|
+ process_event(in, Msg, TM, Machine, Cfg)
|
|
|
end.
|
|
|
|
|
|
-handle_out(#coap_message{id = MsgId} = Msg, TM, Cfg) ->
|
|
|
+handle_out(#coap_message{id = MsgId} = Msg, Cfg, TM) ->
|
|
|
Id = {out, MsgId},
|
|
|
case maps:get(Id, TM, undefined) of
|
|
|
undefined ->
|
|
|
- Data = emqx_coap_transport:new(),
|
|
|
- Transport = new_transport(Id, Data),
|
|
|
- process_event(out, Msg, TM, Transport, Cfg);
|
|
|
+ Transport = emqx_coap_transport:new(),
|
|
|
+ Machine = new_state_machine(Id, Transport),
|
|
|
+ process_event(out, Msg, TM, Machine, Cfg);
|
|
|
_ ->
|
|
|
?WARN("Repeat sending message with id:~p~n", [Id]),
|
|
|
?EMPTY_RESULT
|
|
|
end.
|
|
|
|
|
|
-timeout({Id, Type, Msg}, TM, Cfg) ->
|
|
|
+timeout({Id, Type, Msg}, Cfg, TM) ->
|
|
|
case maps:get(Id, TM, undefined) of
|
|
|
undefined ->
|
|
|
?EMPTY_RESULT;
|
|
|
- #transport{timers = Timers} = TP ->
|
|
|
+ #state_machine{timers = Timers} = Machine ->
|
|
|
%% maybe timer has been canceled
|
|
|
case maps:is_key(Type, Timers) of
|
|
|
true ->
|
|
|
- process_event(Type, Msg, TM, TP, Cfg);
|
|
|
+ process_event(Type, Msg, TM, Machine, Cfg);
|
|
|
_ ->
|
|
|
?EMPTY_RESULT
|
|
|
end
|
|
|
end.
|
|
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
-%% @doc
|
|
|
-%% @spec
|
|
|
-%% @end
|
|
|
+%% Internal functions
|
|
|
%%--------------------------------------------------------------------
|
|
|
-
|
|
|
-%%%===================================================================
|
|
|
-%%% Internal functions
|
|
|
-%%%===================================================================
|
|
|
-new_transport(Id, Data) ->
|
|
|
- #transport{id = Id,
|
|
|
- state = idle,
|
|
|
- timers = #{},
|
|
|
- data = Data}.
|
|
|
+new_state_machine(Id, Transport) ->
|
|
|
+ #state_machine{id = Id,
|
|
|
+ state = idle,
|
|
|
+ timers = #{},
|
|
|
+ transport = Transport}.
|
|
|
|
|
|
process_event(stop_timeout,
|
|
|
_,
|
|
|
TM,
|
|
|
- #transport{id = Id,
|
|
|
- timers = Timers},
|
|
|
+ #state_machine{id = Id,
|
|
|
+ timers = Timers},
|
|
|
_) ->
|
|
|
lists:foreach(fun({_, Ref}) ->
|
|
|
emqx_misc:cancel_timer(Ref)
|
|
|
@@ -143,42 +136,42 @@ process_event(stop_timeout,
|
|
|
process_event(Event,
|
|
|
Msg,
|
|
|
TM,
|
|
|
- #transport{id = Id,
|
|
|
- state = State,
|
|
|
- data = Data} = TP,
|
|
|
+ #state_machine{id = Id,
|
|
|
+ state = State,
|
|
|
+ transport = Transport} = Machine,
|
|
|
Cfg) ->
|
|
|
- Result = emqx_coap_transport:State(Event, Msg, Data, Cfg),
|
|
|
- {ok, _, TP2} = emqx_misc:pipeline([fun process_state_change/2,
|
|
|
- fun process_data_change/2,
|
|
|
- fun process_timeouts/2],
|
|
|
- Result,
|
|
|
- TP),
|
|
|
- TM2 = TM#{Id => TP2},
|
|
|
- emqx_coap_session:transfer_result(Result, tm, TM2).
|
|
|
-
|
|
|
-process_state_change(#{next := Next}, TP) ->
|
|
|
- {ok, cancel_state_timer(TP#transport{state = Next})};
|
|
|
-process_state_change(_, TP) ->
|
|
|
- {ok, TP}.
|
|
|
-
|
|
|
-cancel_state_timer(#transport{timers = Timers} = TP) ->
|
|
|
+ Result = emqx_coap_transport:State(Event, Msg, Transport, Cfg),
|
|
|
+ {ok, _, Machine2} = emqx_misc:pipeline([fun process_state_change/2,
|
|
|
+ fun process_transport_change/2,
|
|
|
+ fun process_timeouts/2],
|
|
|
+ Result,
|
|
|
+ Machine),
|
|
|
+ TM2 = TM#{Id => Machine2},
|
|
|
+ emqx_coap_session:transfer_result(tm, TM2, Result).
|
|
|
+
|
|
|
+process_state_change(#{next := Next}, Machine) ->
|
|
|
+ {ok, cancel_state_timer(Machine#state_machine{state = Next})};
|
|
|
+process_state_change(_, Machine) ->
|
|
|
+ {ok, Machine}.
|
|
|
+
|
|
|
+cancel_state_timer(#state_machine{timers = Timers} = Machine) ->
|
|
|
case maps:get(state_timer, Timers, undefined) of
|
|
|
undefined ->
|
|
|
- TP;
|
|
|
+ Machine;
|
|
|
Ref ->
|
|
|
_ = emqx_misc:cancel_timer(Ref),
|
|
|
- TP#transport{timers = maps:remove(state_timer, Timers)}
|
|
|
+ Machine#state_machine{timers = maps:remove(state_timer, Timers)}
|
|
|
end.
|
|
|
|
|
|
-process_data_change(#{data := Data}, TP) ->
|
|
|
- {ok, TP#transport{data = Data}};
|
|
|
-process_data_change(_, TP) ->
|
|
|
- {ok, TP}.
|
|
|
+process_transport_change(#{transport := Transport}, Machine) ->
|
|
|
+ {ok, Machine#state_machine{transport = Transport}};
|
|
|
+process_transport_change(_, Machine) ->
|
|
|
+ {ok, Machine}.
|
|
|
|
|
|
-process_timeouts(#{timeouts := []}, TP) ->
|
|
|
- {ok, TP};
|
|
|
+process_timeouts(#{timeouts := []}, Machine) ->
|
|
|
+ {ok, Machine};
|
|
|
process_timeouts(#{timeouts := Timeouts},
|
|
|
- #transport{id = Id, timers = Timers} = TP) ->
|
|
|
+ #state_machine{id = Id, timers = Timers} = Machine) ->
|
|
|
NewTimers = lists:foldl(fun({state_timeout, _, _} = Timer, Acc) ->
|
|
|
process_timer(Id, Timer, Acc);
|
|
|
({stop_timeout, I}, Acc) ->
|
|
|
@@ -186,11 +179,11 @@ process_timeouts(#{timeouts := Timeouts},
|
|
|
end,
|
|
|
Timers,
|
|
|
Timeouts),
|
|
|
- {ok, TP#transport{timers = NewTimers}};
|
|
|
+ {ok, Machine#state_machine{timers = NewTimers}};
|
|
|
|
|
|
-process_timeouts(_, TP) ->
|
|
|
- {ok, TP}.
|
|
|
+process_timeouts(_, Machine) ->
|
|
|
+ {ok, Machine}.
|
|
|
|
|
|
process_timer(Id, {Type, Interval, Msg}, Timers) ->
|
|
|
- Ref = emqx_misc:start_timer(Interval, {transport, {Id, Type, Msg}}),
|
|
|
+ Ref = emqx_misc:start_timer(Interval, {state_machine, {Id, Type, Msg}}),
|
|
|
Timers#{Type => Ref}.
|