From d06f410fd52dbc792207541a4eeb6bc9fef81a13 Mon Sep 17 00:00:00 2001 From: JimMoen Date: Wed, 24 Apr 2024 15:24:38 +0800 Subject: [PATCH] fix(plugins): read avsc file --- apps/emqx_plugins/src/emqx_plugins.erl | 56 +++++++++++++------ apps/emqx_plugins/src/emqx_plugins_serde.erl | 4 +- apps/emqx_plugins/test/emqx_plugins_tests.erl | 6 +- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/apps/emqx_plugins/src/emqx_plugins.erl b/apps/emqx_plugins/src/emqx_plugins.erl index ce66fc94d..6d5a4bcbc 100644 --- a/apps/emqx_plugins/src/emqx_plugins.erl +++ b/apps/emqx_plugins/src/emqx_plugins.erl @@ -81,7 +81,9 @@ %% Defines -define(PLUGIN_PERSIS_CONFIG_KEY(NameVsn), {?MODULE, NameVsn}). -%% Types +-define(RAW_BIN, binary). +-define(JSON_MAP, json_map). + %% "my_plugin-0.1.0" -type name_vsn() :: binary() | string(). %% the parse result of the JSON info file @@ -590,30 +592,36 @@ do_read_plugin(NameVsn) -> do_read_plugin2(NameVsn, #{}). do_read_plugin2(NameVsn, Option) -> - do_read_plugin3(NameVsn, info_file(NameVsn), Option). + do_read_plugin3(NameVsn, info_file_path(NameVsn), Option). do_read_plugin3(NameVsn, InfoFilePath, Options) -> - {ok, PlainMap} = (read_file_fun(InfoFilePath, "bad_info_file"))(), + {ok, PlainMap} = (read_file_fun(InfoFilePath, "bad_info_file", #{read_mode => ?JSON_MAP}))(), Info0 = check_plugin(PlainMap, NameVsn, InfoFilePath), Info1 = plugins_readme(NameVsn, Options, Info0), plugin_status(NameVsn, Info1). read_plugin_avsc(NameVsn) -> + read_plugin_avsc(NameVsn, #{read_mode => ?JSON_MAP}). +read_plugin_avsc(NameVsn, Options) -> tryit( atom_to_list(?FUNCTION_NAME), - read_file_fun(schema_file(NameVsn), "bad_avsc_file") + read_file_fun(avsc_file_path(NameVsn), "bad_avsc_file", Options) ). read_plugin_i18n(NameVsn) -> + read_plugin_i18n(NameVsn, #{read_mode => ?JSON_MAP}). +read_plugin_i18n(NameVsn, Options) -> tryit( atom_to_list(?FUNCTION_NAME), - read_file_fun(i18n_file(NameVsn), "bad_i18n_file") + read_file_fun(i18n_file_path(NameVsn), "bad_i18n_file", Options) ). read_plugin_avro(NameVsn) -> + read_plugin_avro(NameVsn, #{read_mode => ?RAW_BIN}). +read_plugin_avro(NameVsn, Options) -> tryit( atom_to_list(?FUNCTION_NAME), - read_file_fun(schema_file(NameVsn), "bad_avro_file") + read_file_fun(avro_config_file(NameVsn), "bad_avro_file", Options) ). ensure_exists_and_installed(NameVsn) -> @@ -1000,15 +1008,22 @@ maybe_post_op_after_install(NameVsn) -> ok. maybe_load_config_schema(NameVsn) -> - case read_plugin_avsc(NameVsn) of - {ok, Avsc} -> - case emqx_plugins_serde:add_schema(NameVsn, Avsc) of + filelib:is_regular(avsc_file_path(NameVsn)) andalso + do_load_config_schema(NameVsn). + +do_load_config_schema(NameVsn) -> + case read_plugin_avsc(NameVsn, #{read_mode => ?RAW_BIN}) of + {ok, AvscBin} -> + case emqx_plugins_serde:add_schema(NameVsn, AvscBin) of ok -> ok; {error, already_exists} -> ok; - {error, Reason} -> {error, Reason} + {error, _Reason} -> ok end; {error, Reason} -> - ?SLOG(warning, Reason) + ?SLOG(warning, #{ + msg => "failed_to_read_plugin_avsc", reason => Reason, name_vsn => NameVsn + }), + ok end. maybe_create_config_dir(NameVsn) -> @@ -1020,14 +1035,23 @@ maybe_create_config_dir(NameVsn) -> write_avro_bin(NameVsn, AvroBin) -> ok = file:write_file(avro_config_file(NameVsn), AvroBin). -read_file_fun(Path, ErrMsg) -> +read_file_fun(Path, ErrMsg, #{read_mode := ?RAW_BIN}) -> + fun() -> + case file:read_file(Path) of + {ok, Bin} -> + {ok, Bin}; + {error, Reason} -> + ErrMeta = #{error_msg => ErrMsg, reason => Reason}, + throw(ErrMeta) + end + end; +read_file_fun(Path, ErrMsg, #{read_mode := ?JSON_MAP}) -> fun() -> case hocon:load(Path, #{format => richmap}) of {ok, RichMap} -> {ok, hocon_maps:ensure_plain(RichMap)}; {error, Reason} -> ErrMeta = #{error_msg => ErrMsg, reason => Reason}, - ?SLOG(warning, ErrMeta), throw(ErrMeta) end end. @@ -1043,16 +1067,16 @@ plugin_config_dir(NameVsn) -> pkg_file(NameVsn) -> filename:join([install_dir(), bin([NameVsn, ".tar.gz"])]). -info_file(NameVsn) -> +info_file_path(NameVsn) -> filename:join([plugin_dir(NameVsn), "release.json"]). -schema_file(NameVsn) -> +avsc_file_path(NameVsn) -> filename:join([plugin_dir(NameVsn), "config_schema.avsc"]). avro_config_file(NameVsn) -> filename:join([plugin_config_dir(NameVsn), "config.avro"]). -i18n_file(NameVsn) -> +i18n_file_path(NameVsn) -> filename:join([plugin_dir(NameVsn), "i18n.json"]). readme_file(NameVsn) -> diff --git a/apps/emqx_plugins/src/emqx_plugins_serde.erl b/apps/emqx_plugins/src/emqx_plugins_serde.erl index a89f16e70..083f9740d 100644 --- a/apps/emqx_plugins/src/emqx_plugins_serde.erl +++ b/apps/emqx_plugins/src/emqx_plugins_serde.erl @@ -79,7 +79,7 @@ add_schema(Name, Avsc) -> end. get_schema(NameVsn) -> - Path = emqx_plugins:schema_file(NameVsn), + Path = emqx_plugins:avsc_file_path(NameVsn), case read_avsc_file(Path) of {ok, Avsc} -> {ok, Avsc}; @@ -129,7 +129,7 @@ handle_continue({build_serdes, SchemasMap}, State) -> _ = build_serdes(SchemasMap), {noreply, State}. -handle_call({build_serdes, {NameVsn, Avsc}}, _From, State) -> +handle_call({build_serdes, NameVsn, Avsc}, _From, State) -> BuildRes = do_build_serde(NameVsn, Avsc), {reply, BuildRes, State}; handle_call(_Call, _From, State) -> diff --git a/apps/emqx_plugins/test/emqx_plugins_tests.erl b/apps/emqx_plugins/test/emqx_plugins_tests.erl index 010d96de9..910c30564 100644 --- a/apps/emqx_plugins/test/emqx_plugins_tests.erl +++ b/apps/emqx_plugins/test/emqx_plugins_tests.erl @@ -49,7 +49,7 @@ read_plugin_test() -> with_rand_install_dir( fun(_Dir) -> NameVsn = "bar-5", - InfoFile = emqx_plugins:info_file(NameVsn), + InfoFile = emqx_plugins:info_file_path(NameVsn), FakeInfo = "name=bar, rel_vsn=\"5\", rel_apps=[justname_no_vsn]," "description=\"desc bar\"", @@ -90,7 +90,7 @@ delete_package_test() -> meck_emqx(), with_rand_install_dir( fun(_Dir) -> - File = emqx_plugins:pkg_file("a-1"), + File = emqx_plugins:pkg_file_path("a-1"), ok = write_file(File, "a"), ok = emqx_plugins:delete_package("a-1"), %% delete again should be ok @@ -108,7 +108,7 @@ purge_test() -> meck_emqx(), with_rand_install_dir( fun(_Dir) -> - File = emqx_plugins:info_file("a-1"), + File = emqx_plugins:info_file_path("a-1"), Dir = emqx_plugins:plugin_dir("a-1"), ok = filelib:ensure_dir(File), ?assertMatch({ok, _}, file:read_file_info(Dir)),