Просмотр исходного кода

feat(config): support wildcard paths for config handlers

Shawn 4 лет назад
Родитель
Сommit
60b8215360
2 измененных файлов с 44 добавлено и 15 удалено
  1. 41 10
      apps/emqx/src/emqx_config_handler.erl
  2. 3 5
      apps/emqx/src/emqx_map_lib.erl

+ 41 - 10
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

+ 3 - 5
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) ->