From 378a2b7b9e54c7caca20b8dde5b81c7e775306b0 Mon Sep 17 00:00:00 2001 From: Shawn <506895667@qq.com> Date: Tue, 15 Jun 2021 18:47:43 +0800 Subject: [PATCH] feat(config): update config to the sub config handler --- apps/emqx/src/emqx_config.erl | 15 ++++++ apps/emqx/src/emqx_config_handler.erl | 51 ++++++++++++------- .../emqx_data_bridge/src/emqx_data_bridge.erl | 17 ------- .../src/emqx_data_bridge_api.erl | 13 ++++- .../src/emqx_data_bridge_sup.erl | 7 ++- 5 files changed, 66 insertions(+), 37 deletions(-) diff --git a/apps/emqx/src/emqx_config.erl b/apps/emqx/src/emqx_config.erl index 3dd0c3087..d05486328 100644 --- a/apps/emqx/src/emqx_config.erl +++ b/apps/emqx/src/emqx_config.erl @@ -20,7 +20,9 @@ -export([ get/0 , get/2 , put/1 + , put/2 , deep_get/3 + , deep_put/3 ]). -spec get() -> term(). @@ -31,6 +33,7 @@ get() -> get(KeyPath, Default) -> deep_get(KeyPath, get(), Default). +-spec deep_get([atom()], map(), term()) -> term(). deep_get([], Map, _Default) -> Map; deep_get([Key | KeyPath], Map, Default) when is_map(Map) -> @@ -41,5 +44,17 @@ deep_get([Key | KeyPath], Map, Default) when is_map(Map) -> deep_get([_Key | _KeyPath], _Map, Default) -> Default. +-spec put(term()) -> ok. put(Config) -> persistent_term:put(?MODULE, Config). + +-spec put([atom()], term()) -> ok. +put(KeyPath, Config) -> + put(deep_put(KeyPath, get(), Config)). + +-spec deep_put([atom()], map(), term()) -> ok. +deep_put([], Map, Config) when is_map(Map) -> + Config; +deep_put([Key | KeyPath], Map, Config) -> + SubMap = deep_put(KeyPath, maps:get(Key, Map, #{}), Config), + Map#{Key => SubMap}. diff --git a/apps/emqx/src/emqx_config_handler.erl b/apps/emqx/src/emqx_config_handler.erl index fd01b648f..792ede35b 100644 --- a/apps/emqx/src/emqx_config_handler.erl +++ b/apps/emqx/src/emqx_config_handler.erl @@ -21,13 +21,13 @@ %% API functions -export([ start_link/0 - , start_handler/2 + , start_handler/3 , update_config/2 + , child_spec/2 ]). %% emqx_config_handler callbacks -export([ handle_update_config/2 - , config_key_path/0 ]). %% gen_server callbacks @@ -39,24 +39,35 @@ code_change/3]). -type config() :: term(). --type config_map() :: #{atom() => config()}. +-type config_map() :: #{atom() => config()} | [config_map()]. -type handler_name() :: module(). -type key_path() :: [atom()]. -%% the path of the config that maintained by the (sub) handler. --callback config_key_path() -> key_path(). +-optional_callbacks([handle_update_config/2]). -callback handle_update_config(config(), config_map()) -> config_map(). --record(state, {handler_name :: handler_name(), parent :: handler_name()}). +-record(state, { + handler_name :: handler_name(), + parent :: handler_name(), + key_path :: key_path() +}). start_link() -> - start_handler(?MODULE, top). + start_handler(?MODULE, top, []). --spec start_handler(handler_name(), handler_name()) -> +-spec start_handler(handler_name(), handler_name(), key_path()) -> {ok, pid()} | {error, {already_started, pid()}} | {error, term()}. -start_handler(HandlerName, Parent) -> - gen_server:start_link({local, HandlerName}, ?MODULE, {HandlerName, Parent}, []). +start_handler(HandlerName, Parent, ConfKeyPath) -> + gen_server:start_link({local, HandlerName}, ?MODULE, {HandlerName, Parent, ConfKeyPath}, []). + +-spec child_spec(module(), key_path()) -> supervisor:child_spec(). +child_spec(Mod, KeyPath) -> + #{id => Mod, + start => {?MODULE, start_handler, [Mod, ?MODULE, KeyPath]}, + restart => permanent, + type => worker, + modules => [?MODULE]}. -spec update_config(handler_name(), config()) -> ok. update_config(top, Config) -> @@ -67,28 +78,29 @@ update_config(Handler, Config) -> %%============================================================================ %% callbacks of emqx_config_handler (the top-level handler) -config_key_path() -> []. - handle_update_config(Config, undefined) -> handle_update_config(Config, #{}); handle_update_config(Config, OldConfigMap) -> %% simply merge the config to the overall config maps:merge(OldConfigMap, Config). -init({HandlerName, Parent}) -> - {ok, #state{handler_name = HandlerName, parent = Parent}}. +init({HandlerName, Parent, ConfKeyPath}) -> + {ok, #state{handler_name = HandlerName, parent = Parent, key_path = ConfKeyPath}}. handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. handle_cast({handle_update_config, Config}, #state{handler_name = HandlerName, - parent = Parent} = State) -> + parent = Parent, key_path = ConfKeyPath} = State) -> %% accumulate the config map of this config handler - OldConfigMap = emqx_config:get(HandlerName:config_key_path(), undefined), - AccConfig = HandlerName:handle_update_config(Config, OldConfigMap), + OldConfigMap = emqx_config:get(ConfKeyPath, undefined), + SubConfigMap = case erlang:function_exported(HandlerName, handle_update_config, 2) of + true -> HandlerName:handle_update_config(Config, OldConfigMap); + false -> wrap_sub_config(ConfKeyPath, Config) + end, %% then notify the parent handler - update_config(Parent, AccConfig), + update_config(Parent, SubConfigMap), {noreply, State}; handle_cast(_Msg, State) -> @@ -114,3 +126,6 @@ save_config_to_disk(ConfigMap) -> emqx_data_dir() -> %emqx_config:get([node, data_dir]) "data". + +wrap_sub_config(ConfKeyPath, Config) -> + emqx_config:deep_put(ConfKeyPath, #{}, Config). diff --git a/apps/emqx_data_bridge/src/emqx_data_bridge.erl b/apps/emqx_data_bridge/src/emqx_data_bridge.erl index 3aa72b1da..2adc48111 100644 --- a/apps/emqx_data_bridge/src/emqx_data_bridge.erl +++ b/apps/emqx_data_bridge/src/emqx_data_bridge.erl @@ -15,12 +15,6 @@ %%-------------------------------------------------------------------- -module(emqx_data_bridge). --behaviour(emqx_config_handler). - --export([ config_key_path/0 - , handle_update_config/2 - ]). - -export([ load_bridges/0 , resource_type/1 , bridge_type/1 @@ -52,14 +46,3 @@ is_bridge(#{id := <<"bridge:", _/binary>>}) -> true; is_bridge(_Data) -> false. - -%%============================================================================ - -config_key_path() -> [emqx_data_bridge, bridges]. - -handle_update_config(_Config, _OldConfigMap) -> - [format_conf(Data) || Data <- emqx_data_bridge:list_bridges()]. - -format_conf(#{resource_type := Type, id := Id, config := Conf}) -> - #{type => Type, name => emqx_data_bridge:resource_id_to_name(Id), - config => Conf}. \ No newline at end of file diff --git a/apps/emqx_data_bridge/src/emqx_data_bridge_api.erl b/apps/emqx_data_bridge/src/emqx_data_bridge_api.erl index 1a27351eb..df07d7a5e 100644 --- a/apps/emqx_data_bridge/src/emqx_data_bridge_api.erl +++ b/apps/emqx_data_bridge/src/emqx_data_bridge_api.erl @@ -76,6 +76,7 @@ create_bridge(#{name := Name}, Params) -> emqx_data_bridge:name_to_resource_id(Name), emqx_data_bridge:resource_type(BridgeType), Config) of {ok, Data} -> + emqx_config_handler:update_config(emqx_data_bridge, get_all_configs()), {200, #{code => 0, data => format_api_reply(emqx_resource_api:format_data(Data))}}; {error, already_created} -> {400, #{code => 102, message => <<"bridge already created: ", Name/binary>>}}; @@ -92,6 +93,7 @@ update_bridge(#{name := Name}, Params) -> emqx_data_bridge:name_to_resource_id(Name), emqx_data_bridge:resource_type(BridgeType), Config, []) of {ok, Data} -> + emqx_config_handler:update_config(emqx_data_bridge, get_all_configs()), {200, #{code => 0, data => format_api_reply(emqx_resource_api:format_data(Data))}}; {error, not_found} -> {400, #{code => 102, message => <<"bridge not_found: ", Name/binary>>}}; @@ -103,7 +105,9 @@ update_bridge(#{name := Name}, Params) -> delete_bridge(#{name := Name}, _Params) -> case emqx_resource:remove(emqx_data_bridge:name_to_resource_id(Name)) of - ok -> {200, #{code => 0, data => #{}}}; + ok -> + emqx_config_handler:update_config(emqx_data_bridge, get_all_configs()), + {200, #{code => 0, data => #{}}}; {error, Reason} -> {500, #{code => 102, message => emqx_resource_api:stringnify(Reason)}} end. @@ -112,3 +116,10 @@ format_api_reply(#{resource_type := Type, id := Id, config := Conf, status := St #{type => emqx_data_bridge:bridge_type(Type), name => emqx_data_bridge:resource_id_to_name(Id), config => Conf, status => Status}. + +format_conf(#{resource_type := Type, id := Id, config := Conf}) -> + #{type => Type, name => emqx_data_bridge:resource_id_to_name(Id), + config => Conf}. + +get_all_configs() -> + [format_conf(Data) || Data <- emqx_data_bridge:list_bridges()]. diff --git a/apps/emqx_data_bridge/src/emqx_data_bridge_sup.erl b/apps/emqx_data_bridge/src/emqx_data_bridge_sup.erl index 516d9b5ab..20a447bf0 100644 --- a/apps/emqx_data_bridge/src/emqx_data_bridge_sup.erl +++ b/apps/emqx_data_bridge/src/emqx_data_bridge_sup.erl @@ -35,7 +35,12 @@ init([]) -> start => {emqx_data_bridge_monitor, start_link, []}, restart => permanent, type => worker, - modules => [emqx_data_bridge_monitor]}], + modules => [emqx_data_bridge_monitor]}, + emqx_config_handler:child_spec(emqx_data_bridge_config_handler, config_key_path()) + ], {ok, {SupFlags, ChildSpecs}}. %% internal functions + +config_key_path() -> + [emqx_data_bridge, bridges].