diff --git a/apps/emqx/src/emqx_hocon.erl b/apps/emqx/src/emqx_hocon.erl index 6b2cdfb55..ebf5e0f44 100644 --- a/apps/emqx/src/emqx_hocon.erl +++ b/apps/emqx/src/emqx_hocon.erl @@ -17,13 +17,40 @@ %% @doc HOCON schema help module -module(emqx_hocon). --export([format_path/1]). +-export([ format_path/1 + , check/2 + ]). +%% @doc Format hocon config field path to dot-separated string in iolist format. +-spec format_path([atom() | string() | binary()]) -> iolist(). format_path([]) -> ""; format_path([Name]) -> iol(Name); format_path([Name | Rest]) -> [iol(Name) , "." | format_path(Rest)]. +%% @doc Plain check the input config. +%% The input can either be `richmap' or plain `map'. +%% Always return plain map with atom keys. +-spec check(module(), hocon:config() | iodata()) -> + {ok, hocon:config()} | {error, any()}. +check(SchemaModule, Conf) when is_map(Conf) -> + %% TODO: remove nullable + %% fields should state nullable or not in their schema + Opts = #{atom_key => true, nullable => true}, + try + {ok, hocon_tconf:check_plain(SchemaModule, Conf, Opts)} + catch + throw : Reason -> + {error, Reason} + end; +check(SchemaModule, HoconText) -> + case hocon:binary(HoconText, #{format => map}) of + {ok, MapConfig} -> + check(SchemaModule, MapConfig); + {error, Reason} -> + {error, Reason} + end. + %% Ensure iolist() iol(B) when is_binary(B) -> B; iol(A) when is_atom(A) -> atom_to_binary(A, utf8); diff --git a/apps/emqx_resource/src/emqx_resource.erl b/apps/emqx_resource/src/emqx_resource.erl index 48641e4ba..851d2a4c4 100644 --- a/apps/emqx_resource/src/emqx_resource.erl +++ b/apps/emqx_resource/src/emqx_resource.erl @@ -82,7 +82,6 @@ , list_group_instances/1 ]). --define(HOCON_CHECK_OPTS, #{atom_key => true, nullable => true}). -define(DEFAULT_RESOURCE_GROUP, <<"default">>). -optional_callbacks([ on_query/4 @@ -294,22 +293,8 @@ call_jsonify(Mod, Config) -> -spec check_config(resource_type(), raw_resource_config()) -> {ok, resource_config()} | {error, term()}. -check_config(ResourceType, RawConfig) when is_binary(RawConfig) -> - case hocon:binary(RawConfig, #{format => map}) of - {ok, MapConfig} -> - check_config(ResourceType, MapConfig); - {error, Reason} -> - {error, Reason} - end; -check_config(ResourceType, RawConfigTerm) -> - %% hocon_tconf map and check APIs throw exception on bad configs - try hocon_tconf:check_plain(ResourceType, RawConfigTerm, ?HOCON_CHECK_OPTS) of - Config -> - {ok, Config} - catch - throw : Reason -> - {error, Reason} - end. +check_config(ResourceType, Conf) -> + emqx_hocon:check(ResourceType, Conf). -spec check_and_create(instance_id(), resource_type(), raw_resource_config()) -> {ok, resource_data() | 'already_created'} | {error, term()}. diff --git a/apps/emqx_rule_engine/src/emqx_rule_api_schema.erl b/apps/emqx_rule_engine/src/emqx_rule_api_schema.erl index e91a95802..196ec642b 100644 --- a/apps/emqx_rule_engine/src/emqx_rule_api_schema.erl +++ b/apps/emqx_rule_engine/src/emqx_rule_api_schema.erl @@ -15,16 +15,14 @@ -spec check_params(map(), tag()) -> {ok, map()} | {error, term()}. check_params(Params, Tag) -> BTag = atom_to_binary(Tag), - try hocon_tconf:check_plain(?MODULE, #{BTag => Params}, - #{atom_key => true, nullable => true}, [BTag]) of - #{Tag := Checked} -> {ok, Checked} - catch - Error:Reason:ST -> + case emqx_hocon:check(?MODULE, #{BTag => Params}) of + {ok, #{Tag := Checked}} -> + {ok, Checked}; + {error, Reason} -> ?SLOG(error, #{msg => "check_rule_params_failed", - exception => Error, - reason => Reason, - stacktrace => ST}), - {error, {Reason, ST}} + reason => Reason + }), + {error, Reason} end. %%======================================================================================