|
|
@@ -40,14 +40,12 @@
|
|
|
|
|
|
-export([api_spec/0]).
|
|
|
|
|
|
--define(ALREADY_ENABLED, 'ALREADY_ENABLED').
|
|
|
--define(ALREADY_DISABLED, 'ALREADY_DISABLED').
|
|
|
-
|
|
|
-define(INTERNAL_ERROR, 'INTERNAL_ERROR').
|
|
|
-define(BAD_REQUEST, 'BAD_REQUEST').
|
|
|
|
|
|
-define(MESSAGE_ID_NOT_FOUND, 'MESSAGE_ID_NOT_FOUND').
|
|
|
-define(MESSAGE_ID_SCHEMA_ERROR, 'MESSAGE_ID_SCHEMA_ERROR').
|
|
|
+-define(INVALID_NODE, 'INVALID_NODE').
|
|
|
-define(MAX_PAYLOAD_SIZE, 1048576). %% 1MB = 1024 x 1024
|
|
|
|
|
|
api_spec() ->
|
|
|
@@ -56,7 +54,7 @@ api_spec() ->
|
|
|
paths() ->
|
|
|
[ "/mqtt/delayed"
|
|
|
, "/mqtt/delayed/messages"
|
|
|
- , "/mqtt/delayed/messages/:msgid"
|
|
|
+ , "/mqtt/delayed/messages/:node/:msgid"
|
|
|
].
|
|
|
|
|
|
schema("/mqtt/delayed") ->
|
|
|
@@ -83,12 +81,16 @@ schema("/mqtt/delayed") ->
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-schema("/mqtt/delayed/messages/:msgid") ->
|
|
|
+schema("/mqtt/delayed/messages/:node/:msgid") ->
|
|
|
#{'operationId' => delayed_message,
|
|
|
get => #{
|
|
|
tags => ?API_TAG_MQTT,
|
|
|
description => <<"Get delayed message">>,
|
|
|
- parameters => [{msgid, mk(binary(), #{in => path, desc => <<"delay message ID">>})}],
|
|
|
+ parameters => [ {node,
|
|
|
+ mk(binary(),
|
|
|
+ #{in => path, desc => <<"The node where message from">>})}
|
|
|
+ , {msgid, mk(binary(), #{in => path, desc => <<"Delay message ID">>})}
|
|
|
+ ],
|
|
|
responses => #{
|
|
|
200 => ref("message_without_payload"),
|
|
|
400 => emqx_dashboard_swagger:error_codes( [?MESSAGE_ID_SCHEMA_ERROR]
|
|
|
@@ -100,7 +102,12 @@ schema("/mqtt/delayed/messages/:msgid") ->
|
|
|
delete => #{
|
|
|
tags => ?API_TAG_MQTT,
|
|
|
description => <<"Delete delayed message">>,
|
|
|
- parameters => [{msgid, mk(binary(), #{in => path, desc => <<"delay message ID">>})}],
|
|
|
+ parameters => [ {node,
|
|
|
+ mk(binary(),
|
|
|
+ #{in => path, desc => <<"The node where message from">>})}
|
|
|
+ , {msgid,
|
|
|
+ mk(binary(), #{in => path, desc => <<"Delay message ID">>})}
|
|
|
+ ],
|
|
|
responses => #{
|
|
|
204 => <<"Delete delayed message success">>,
|
|
|
400 => emqx_dashboard_swagger:error_codes( [?MESSAGE_ID_SCHEMA_ERROR]
|
|
|
@@ -133,15 +140,16 @@ schema("/mqtt/delayed/messages") ->
|
|
|
|
|
|
fields("message_without_payload") ->
|
|
|
[
|
|
|
- {msgid, mk(integer(), #{desc => <<"Message Id (MQTT message id hash)">>})},
|
|
|
- {publish_at, mk(binary(), #{desc => <<"Client publish message time, rfc 3339">>})},
|
|
|
- {delayed_interval, mk(integer(), #{desc => <<"Delayed interval, second">>})},
|
|
|
- {delayed_remaining, mk(integer(), #{desc => <<"Delayed remaining, second">>})},
|
|
|
- {expected_at, mk(binary(), #{desc => <<"Expect publish time, rfc 3339">>})},
|
|
|
- {topic, mk(binary(), #{desc => <<"Topic">>, example => <<"/sys/#">>})},
|
|
|
- {qos, mk(binary(), #{desc => <<"QoS">>})},
|
|
|
- {from_clientid, mk(binary(), #{desc => <<"From ClientId">>})},
|
|
|
- {from_username, mk(binary(), #{desc => <<"From Username">>})}
|
|
|
+ {msgid, mk(integer(), #{desc => <<"Message Id (MQTT message id hash)">>})},
|
|
|
+ {node, mk(binary(), #{desc => <<"The node where message from">>})},
|
|
|
+ {publish_at, mk(binary(), #{desc => <<"Client publish message time, rfc 3339">>})},
|
|
|
+ {delayed_interval, mk(integer(), #{desc => <<"Delayed interval, second">>})},
|
|
|
+ {delayed_remaining, mk(integer(), #{desc => <<"Delayed remaining, second">>})},
|
|
|
+ {expected_at, mk(binary(), #{desc => <<"Expect publish time, rfc 3339">>})},
|
|
|
+ {topic, mk(binary(), #{desc => <<"Topic">>, example => <<"/sys/#">>})},
|
|
|
+ {qos, mk(binary(), #{desc => <<"QoS">>})},
|
|
|
+ {from_clientid, mk(binary(), #{desc => <<"From ClientId">>})},
|
|
|
+ {from_username, mk(binary(), #{desc => <<"From Username">>})}
|
|
|
];
|
|
|
fields("message") ->
|
|
|
PayloadDesc = io_lib:format(
|
|
|
@@ -162,31 +170,37 @@ status(put, #{body := Body}) ->
|
|
|
delayed_messages(get, #{query_string := Qs}) ->
|
|
|
{200, emqx_delayed:cluster_list(Qs)}.
|
|
|
|
|
|
-delayed_message(get, #{bindings := #{msgid := Id}}) ->
|
|
|
- case emqx_delayed:get_delayed_message(Id) of
|
|
|
- {ok, Message} ->
|
|
|
- Payload = maps:get(payload, Message),
|
|
|
- case erlang:byte_size(Payload) > ?MAX_PAYLOAD_SIZE of
|
|
|
- true ->
|
|
|
- {200, Message};
|
|
|
- _ ->
|
|
|
- {200, Message#{payload => base64:encode(Payload)}}
|
|
|
- end;
|
|
|
- {error, id_schema_error} ->
|
|
|
- {400, generate_http_code_map(id_schema_error, Id)};
|
|
|
- {error, not_found} ->
|
|
|
- {404, generate_http_code_map(not_found, Id)}
|
|
|
- end;
|
|
|
-delayed_message(delete, #{bindings := #{msgid := Id}}) ->
|
|
|
- case emqx_delayed:get_delayed_message(Id) of
|
|
|
- {ok, _Message} ->
|
|
|
- _ = emqx_delayed:delete_delayed_message(Id),
|
|
|
- {204};
|
|
|
- {error, id_schema_error} ->
|
|
|
- {400, generate_http_code_map(id_schema_error, Id)};
|
|
|
- {error, not_found} ->
|
|
|
- {404, generate_http_code_map(not_found, Id)}
|
|
|
- end.
|
|
|
+delayed_message(get, #{bindings := #{node := NodeBin, msgid := HexId}}) ->
|
|
|
+ MaybeNode = make_maybe(NodeBin, invalid_node, fun erlang:binary_to_atom/1),
|
|
|
+ MaybeId = make_maybe(HexId, id_schema_error, fun emqx_guid:from_hexstr/1),
|
|
|
+ with_maybe([MaybeNode, MaybeId],
|
|
|
+ fun(Node, Id) ->
|
|
|
+ case emqx_delayed:get_delayed_message(Node, Id) of
|
|
|
+ {ok, Message} ->
|
|
|
+ Payload = maps:get(payload, Message),
|
|
|
+ case erlang:byte_size(Payload) > ?MAX_PAYLOAD_SIZE of
|
|
|
+ true ->
|
|
|
+ {200, Message};
|
|
|
+ _ ->
|
|
|
+ {200, Message#{payload => base64:encode(Payload)}}
|
|
|
+ end;
|
|
|
+ {error, not_found} ->
|
|
|
+ {404, generate_http_code_map(not_found, Id)}
|
|
|
+ end
|
|
|
+ end);
|
|
|
+
|
|
|
+delayed_message(delete, #{bindings := #{node := NodeBin, msgid := HexId}}) ->
|
|
|
+ MaybeNode = make_maybe(NodeBin, invalid_node, fun erlang:binary_to_atom/1),
|
|
|
+ MaybeId = make_maybe(HexId, id_schema_error, fun emqx_guid:from_hexstr/1),
|
|
|
+ with_maybe([MaybeNode, MaybeId],
|
|
|
+ fun(Node, Id) ->
|
|
|
+ case emqx_delayed:delete_delayed_message(Node, Id) of
|
|
|
+ ok ->
|
|
|
+ {204};
|
|
|
+ {error, not_found} ->
|
|
|
+ {404, generate_http_code_map(not_found, Id)}
|
|
|
+ end
|
|
|
+ end).
|
|
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
%% internal function
|
|
|
@@ -236,4 +250,25 @@ generate_http_code_map(id_schema_error, Id) ->
|
|
|
iolist_to_binary(io_lib:format("Message ID ~p schema error", [Id]))};
|
|
|
generate_http_code_map(not_found, Id) ->
|
|
|
#{code => ?MESSAGE_ID_NOT_FOUND, message =>
|
|
|
- iolist_to_binary(io_lib:format("Message ID ~p not found", [Id]))}.
|
|
|
+ iolist_to_binary(io_lib:format("Message ID ~p not found", [Id]))};
|
|
|
+generate_http_code_map(invalid_node, Node) ->
|
|
|
+ #{code => ?INVALID_NODE, message =>
|
|
|
+ iolist_to_binary(io_lib:format("The node name ~p is invalid", [Node]))}.
|
|
|
+
|
|
|
+make_maybe(X, Error, Fun) ->
|
|
|
+ try Fun(X) of
|
|
|
+ Right ->
|
|
|
+ Right
|
|
|
+ catch _:_ ->
|
|
|
+ {left, X, Error}
|
|
|
+ end.
|
|
|
+
|
|
|
+with_maybe(Maybes, Cont) ->
|
|
|
+ with_maybe(Maybes, Cont, []).
|
|
|
+
|
|
|
+with_maybe([], Cont, Rights) ->
|
|
|
+ erlang:apply(Cont, lists:reverse(Rights));
|
|
|
+with_maybe([{left, X, Error} | _], _Cont, _Rights) ->
|
|
|
+ {400, generate_http_code_map(Error, X)};
|
|
|
+with_maybe([Right | T], Cont, Rights) ->
|
|
|
+ with_maybe(T, Cont, [Right | Rights]).
|