diff --git a/apps/emqx/src/emqx_config_handler.erl b/apps/emqx/src/emqx_config_handler.erl index a9020a87a..f64ffabcb 100644 --- a/apps/emqx/src/emqx_config_handler.erl +++ b/apps/emqx/src/emqx_config_handler.erl @@ -39,6 +39,7 @@ code_change/3]). -define(MOD, {mod}). +-define(WKEY, '?'). -define(ATOM_CONF_PATH(PATH, EXP, EXP_ON_FAIL), try [safe_atom(Key) || Key <- PATH] of @@ -80,11 +81,11 @@ update_config(SchemaModule, ConfKeyPath, UpdateArgs) -> -spec add_handler(emqx_config:config_key_path(), handler_name()) -> ok. add_handler(ConfKeyPath, HandlerName) -> - gen_server:call(?MODULE, {add_child, ConfKeyPath, HandlerName}). + gen_server:call(?MODULE, {add_handler, ConfKeyPath, HandlerName}). -spec remove_handler(emqx_config:config_key_path()) -> ok. remove_handler(ConfKeyPath) -> - gen_server:call(?MODULE, {remove_child, ConfKeyPath}). + gen_server:call(?MODULE, {remove_handler, ConfKeyPath}). %%============================================================================ @@ -92,15 +93,18 @@ remove_handler(ConfKeyPath) -> init(_) -> {ok, #{handlers => #{?MOD => ?MODULE}}}. -handle_call({add_child, ConfKeyPath, HandlerName}, _From, - State = #{handlers := Handlers}) -> - {reply, ok, State#{handlers => - emqx_map_lib:deep_put(ConfKeyPath, Handlers, #{?MOD => HandlerName})}}; +handle_call({add_handler, ConfKeyPath, HandlerName}, _From, State = #{handlers := Handlers}) -> + case deep_put_handler(ConfKeyPath, Handlers, HandlerName) of + {ok, NewHandlers} -> + {reply, ok, State#{handlers => NewHandlers}}; + Error -> + {reply, Error, State} + end; -handle_call({remove_child, ConfKeyPath}, _From, +handle_call({remove_handler, ConfKeyPath}, _From, State = #{handlers := Handlers}) -> {reply, ok, State#{handlers => - emqx_map_lib:deep_remove(ConfKeyPath, Handlers)}}; + emqx_map_lib:deep_remove(ConfKeyPath ++ [?MOD], Handlers)}}; handle_call({change_config, SchemaModule, ConfKeyPath, UpdateArgs}, _From, #{handlers := Handlers} = State) -> @@ -134,6 +138,27 @@ terminate(_Reason, _State) -> code_change(_OldVsn, State, _Extra) -> {ok, State}. +deep_put_handler([], _Handlers, Mod) -> + {ok, #{?MOD => Mod}}; +deep_put_handler([?WKEY | KeyPath], Handlers, Mod) -> + deep_put_handler2(?WKEY, KeyPath, Handlers, Mod); +deep_put_handler([Key | KeyPath], Handlers, Mod) -> + case maps:find(?WKEY, Handlers) of + error -> + deep_put_handler2(Key, KeyPath, Handlers, Mod); + {ok, _SubHandlers} -> + {error, {cannot_override_a_wildcard_path, [?WKEY | KeyPath]}} + end. + +deep_put_handler2(Key, KeyPath, Handlers, Mod) -> + SubHandlers = maps:get(Key, Handlers, #{}), + case deep_put_handler(KeyPath, SubHandlers, Mod) of + {ok, SubHandlers1} -> + {ok, Handlers#{Key => SubHandlers1}}; + Error -> + Error + end. + process_update_request(ConfKeyPath, _Handlers, {remove, Opts}) -> OldRawConf = emqx_config:get_root_raw(ConfKeyPath), BinKeyPath = bin_path(ConfKeyPath), @@ -153,7 +178,7 @@ do_update_config([], Handlers, OldRawConf, UpdateReq) -> call_pre_config_update(Handlers, OldRawConf, UpdateReq); do_update_config([ConfKey | ConfKeyPath], Handlers, OldRawConf, UpdateReq) -> SubOldRawConf = get_sub_config(bin(ConfKey), OldRawConf), - SubHandlers = maps:get(ConfKey, Handlers, #{}), + SubHandlers = get_sub_handlers(ConfKey, Handlers), case do_update_config(ConfKeyPath, SubHandlers, SubOldRawConf, UpdateReq) of {ok, NewUpdateReq} -> call_pre_config_update(Handlers, OldRawConf, #{bin(ConfKey) => NewUpdateReq}); @@ -184,7 +209,7 @@ do_post_config_update([ConfKey | ConfKeyPath], Handlers, OldConf, NewConf, AppEn Result) -> SubOldConf = get_sub_config(ConfKey, OldConf), SubNewConf = get_sub_config(ConfKey, NewConf), - SubHandlers = maps:get(ConfKey, Handlers, #{}), + SubHandlers = get_sub_handlers(ConfKey, Handlers), case do_post_config_update(ConfKeyPath, SubHandlers, SubOldConf, SubNewConf, AppEnvs, UpdateArgs, Result) of {ok, Result1} -> @@ -193,6 +218,12 @@ do_post_config_update([ConfKey | ConfKeyPath], Handlers, OldConf, NewConf, AppEn Error -> Error end. +get_sub_handlers(ConfKey, Handlers) -> + case maps:find(ConfKey, Handlers) of + error -> maps:get(?WKEY, Handlers, #{}); + {ok, SubHandlers} -> SubHandlers + end. + get_sub_config(ConfKey, Conf) when is_map(Conf) -> maps:get(ConfKey, Conf, undefined); get_sub_config(_, _Conf) -> %% the Conf is a primitive diff --git a/apps/emqx/src/emqx_map_lib.erl b/apps/emqx/src/emqx_map_lib.erl index d5e851971..6aa6606c0 100644 --- a/apps/emqx/src/emqx_map_lib.erl +++ b/apps/emqx/src/emqx_map_lib.erl @@ -65,13 +65,11 @@ deep_find(_KeyPath, Data) -> {not_found, _KeyPath, Data}. -spec deep_put(config_key_path(), map(), term()) -> map(). -deep_put([], Map, Data) when is_map(Map) -> - Data; -deep_put([], _Map, Data) -> %% not map, replace it +deep_put([], _Map, Data) -> Data; deep_put([Key | KeyPath], Map, Data) -> - SubMap = deep_put(KeyPath, maps:get(Key, Map, #{}), Data), - Map#{Key => SubMap}. + SubMap = maps:get(Key, Map, #{}), + Map#{Key => deep_put(KeyPath, SubMap, Data)}. -spec deep_remove(config_key_path(), map()) -> map(). deep_remove([], Map) ->