emqx_utils_api.erl 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2020-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
  3. %%
  4. %% Licensed under the Apache License, Version 2.0 (the "License");
  5. %% you may not use this file except in compliance with the License.
  6. %% You may obtain a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing, software
  11. %% distributed under the License is distributed on an "AS IS" BASIS,
  12. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. %% See the License for the specific language governing permissions and
  14. %% limitations under the License.
  15. %%--------------------------------------------------------------------
  16. -module(emqx_utils_api).
  17. -export([
  18. to_json/1,
  19. with_node/2,
  20. with_node_or_cluster/2
  21. ]).
  22. -include("emqx_utils_api.hrl").
  23. -define(NODE_NOT_FOUND(NODE), ?NOT_FOUND(<<"Node not found: ", NODE/binary>>)).
  24. %%--------------------------------------------------------------------
  25. %% exported API
  26. %%--------------------------------------------------------------------
  27. -spec with_node(binary() | atom(), fun((atom()) -> {ok, term()} | {error, term()})) ->
  28. ?OK(term()) | ?NOT_FOUND(binary()) | ?BAD_REQUEST(term()).
  29. with_node(Node0, Fun) ->
  30. case lookup_node(Node0) of
  31. {ok, Node} ->
  32. handle_result(Fun(Node));
  33. not_found ->
  34. ?NODE_NOT_FOUND(Node0)
  35. end.
  36. -spec with_node_or_cluster(binary() | atom(), fun((atom()) -> {ok, term()} | {error, term()})) ->
  37. ?OK(term()) | ?NOT_FOUND(iolist()) | ?BAD_REQUEST(term()).
  38. with_node_or_cluster(<<"all">>, Fun) ->
  39. handle_result(Fun(all));
  40. with_node_or_cluster(Node, Fun) ->
  41. with_node(Node, Fun).
  42. -spec to_json(map()) -> emqx_utils_json:json_text().
  43. to_json(M0) ->
  44. %% When dealing with Hocon validation errors, `value' might contain non-serializable
  45. %% values (e.g.: user_lookup_fun), so we try again without that key if serialization
  46. %% fails as a best effort.
  47. M1 = emqx_utils_maps:jsonable_map(M0, fun(K, V) -> {K, emqx_utils_maps:binary_string(V)} end),
  48. try
  49. emqx_utils_json:encode(M1)
  50. catch
  51. error:_ ->
  52. M2 = maps:without([value, <<"value">>], M1),
  53. emqx_utils_json:encode(M2)
  54. end.
  55. %%--------------------------------------------------------------------
  56. %% Internal
  57. %%--------------------------------------------------------------------
  58. -spec lookup_node(atom() | binary()) -> {ok, atom()} | not_found.
  59. lookup_node(BinNode) when is_binary(BinNode) ->
  60. case emqx_utils:safe_to_existing_atom(BinNode, utf8) of
  61. {ok, Node} ->
  62. is_running_node(Node);
  63. _Error ->
  64. not_found
  65. end;
  66. lookup_node(Node) when is_atom(Node) ->
  67. is_running_node(Node).
  68. -spec is_running_node(atom()) -> {ok, atom()} | not_found.
  69. is_running_node(Node) ->
  70. case lists:member(Node, mria:running_nodes()) of
  71. true ->
  72. {ok, Node};
  73. false ->
  74. not_found
  75. end.
  76. handle_result({ok, Result}) ->
  77. ?OK(Result);
  78. handle_result({error, Reason}) ->
  79. ?BAD_REQUEST(Reason);
  80. handle_result({HTTPCode}) when is_integer(HTTPCode) ->
  81. {HTTPCode};
  82. handle_result({HTTPCode, Content}) when is_integer(HTTPCode) ->
  83. {HTTPCode, Content}.