From d1e51d635ddf006a252c961e2afc31bc3e8e4d14 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Thu, 8 May 2025 12:49:54 +0800 Subject: [PATCH] fix service config --- apps/iot/include/iot_tables.hrl | 22 ++++ apps/iot/src/http_handler/service_handler.erl | 52 +++++++++ apps/iot/src/iot_app.erl | 14 ++- apps/iot/src/mnesia/service_config_model.erl | 103 ++++++++++++++++++ 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 apps/iot/include/iot_tables.hrl create mode 100644 apps/iot/src/http_handler/service_handler.erl create mode 100644 apps/iot/src/mnesia/service_config_model.erl diff --git a/apps/iot/include/iot_tables.hrl b/apps/iot/include/iot_tables.hrl new file mode 100644 index 0000000..f330842 --- /dev/null +++ b/apps/iot/include/iot_tables.hrl @@ -0,0 +1,22 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2025, +%%% @doc +%%% +%%% @end +%%% Created : 08. 5月 2025 12:08 +%%%------------------------------------------------------------------- +-author("anlicheng"). + +%% 用来保存微服务的配置 +-record(service_config, { + service_id :: binary(), + config_json = <<>> :: binary(), + %% 保持上一个版本的内容,错误时回滚 + last_config_json = <<>> :: binary(), + %% 最后一次修改的用户id + last_edit_user :: integer(), + %% 状态: 0: 停止, 1: 运行中 + update_ts = 0, + create_ts = 0 +}). \ No newline at end of file diff --git a/apps/iot/src/http_handler/service_handler.erl b/apps/iot/src/http_handler/service_handler.erl new file mode 100644 index 0000000..66a7fd0 --- /dev/null +++ b/apps/iot/src/http_handler/service_handler.erl @@ -0,0 +1,52 @@ +%%%------------------------------------------------------------------- +%%% @author licheng5 +%%% @copyright (C) 2020, +%%% @doc +%%% +%%% @end +%%% Created : 26. 4月 2020 3:36 下午 +%%%------------------------------------------------------------------- +-module(service_handler). +-author("licheng5"). +-include("iot.hrl"). + +%% API +-export([handle_request/4]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% helper methods +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +handle_request("POST", "/service/set_config", _, #{<<"service_id">> := ServiceId, <<"config_json">> := ConfigJson, <<"last_edit_user">> := LastEditUser}) + when is_binary(ServiceId), is_binary(ConfigJson), is_integer(LastEditUser) -> + lager:debug("[service_handler] service_id: ~p, config_json: ~p, last_edit_user:~p", [ServiceId, ConfigJson, LastEditUser]), + + case service_config_model:update(ServiceId, ConfigJson, LastEditUser) of + ok -> + {ok, 200, iot_util:json_data(<<"success">>)}; + {error, Reason} -> + lager:debug("[service_handler] set_config service_id: ~p, get error: ~p", [ServiceId, Reason]), + {ok, 200, iot_util:json_error(404, <<"set service config failed">>)} + end; + +handle_request("GET", "/service/get_config", #{<<"service_id">> := ServiceId}, _) when is_binary(ServiceId) -> + case service_config_model:get_config(ServiceId) of + error -> + {ok, 200, iot_util:json_error(404, <<"service config not found">>)}; + {ok, Config} -> + {ok, 200, iot_util:json_data(service_config_model:as_map(Config))} + end; + +%% 删除对应的主机信息 +handle_request("POST", "/service/delete", _, #{<<"service_id">> := ServiceId}) when is_binary(ServiceId) -> + case service_config_model:delete(ServiceId) of + ok -> + {ok, 200, iot_util:json_data(<<"success">>)}; + {error, Reason} -> + lager:debug("[service_handler] delete config of service_id: ~p, error: ~p", [ServiceId, Reason]), + {ok, 200, iot_util:json_error(404, <<"delete service config errror">>)} + end; + +handle_request(_, Path, _, _) -> + Path1 = list_to_binary(Path), + {ok, 200, iot_util:json_error(-1, <<"url: ", Path1/binary, " not found">>)}. \ No newline at end of file diff --git a/apps/iot/src/iot_app.erl b/apps/iot/src/iot_app.erl index 40f8c8d..8dcf611 100644 --- a/apps/iot/src/iot_app.erl +++ b/apps/iot/src/iot_app.erl @@ -14,6 +14,8 @@ start(_StartType, _StartArgs) -> io:setopts([{encoding, unicode}]), %% 加速内存的回收 erlang:system_flag(fullsweep_after, 16), + %% 启动mnesia数据库 + start_mnesia(), start_tcp_server(), @@ -46,4 +48,14 @@ start_tcp_server() -> ], {ok, _} = esockd:open('iot/tcp_server', Port, TransOpts, {tcp_channel, start_link, []}), - lager:debug("[iot_app] the tcp server start at: ~p", [Port]). \ No newline at end of file + lager:debug("[iot_app] the tcp server start at: ~p", [Port]). + +%% 启动内存数据库 +start_mnesia() -> + %% 启动数据库 + ok = mnesia:start(), + Tables = mnesia:system_info(tables), + lager:debug("[iot_app] tables: ~p", [Tables]), + %% 创建数据库表 + not lists:member(service_config, Tables) andalso service_config_model:create_table(), + ok. \ No newline at end of file diff --git a/apps/iot/src/mnesia/service_config_model.erl b/apps/iot/src/mnesia/service_config_model.erl new file mode 100644 index 0000000..e5ae11f --- /dev/null +++ b/apps/iot/src/mnesia/service_config_model.erl @@ -0,0 +1,103 @@ +%%%------------------------------------------------------------------- +%%% @author aresei +%%% @copyright (C) 2023, +%%% @doc +%%% +%%% @end +%%% Created : 04. 7月 2023 12:31 +%%%------------------------------------------------------------------- +-module(service_config_model). +-author("aresei"). +-include("iot_tables.hrl"). +-include_lib("stdlib/include/qlc.hrl"). + +-define(TAB, service_config). + +%% API +-export([create_table/0]). +-export([insert/3, update/3, get_config/1, delete/1]). +-export([as_map/1]). + +create_table() -> + %% id生成器 + mnesia:create_table(service_config, [ + {attributes, record_info(fields, service_config)}, + {record_name, service_config}, + {disc_copies, [node()]}, + {type, ordered_set} + ]). + +insert(ServiceId, ConfigJson, LastEditUser) when is_binary(ServiceId), is_binary(ConfigJson), is_integer(LastEditUser) -> + ServiceConfig = #service_config{ + service_id = ServiceId, + config_json = ConfigJson, + last_config_json = <<>>, + last_edit_user = LastEditUser, + create_ts = iot_util:current_time(), + update_ts = iot_util:current_time() + }, + case mnesia:transaction(fun() -> mnesia:write(?TAB, ServiceConfig, write) end) of + {'atomic', ok} -> + ok; + {'aborted', Reason} -> + {error, Reason} + end. + +update(ServiceId, ConfigJson, LastEditUser) when is_binary(ServiceId), is_binary(ConfigJson), is_integer(LastEditUser) -> + Fun = fun() -> + case mnesia:read(?TAB, ServiceId, write) of + [] -> + ServiceConfig = #service_config{ + service_id = ServiceId, + config_json = ConfigJson, + last_config_json = <<>>, + last_edit_user = LastEditUser, + create_ts = iot_util:current_time(), + update_ts = iot_util:current_time() + }, + mnesia:write(?TAB, ServiceConfig, write); + [ServiceConfig0 = #service_config{config_json = OldConfigJson}] -> + NServiceConfig = ServiceConfig0#service_config{ + config_json = ConfigJson, + last_config_json = OldConfigJson, + last_edit_user = LastEditUser, + update_ts = iot_util:current_time() + }, + mnesia:write(?TAB, NServiceConfig, write) + end + end, + + case mnesia:transaction(Fun) of + {'atomic', ok} -> + ok; + {'aborted', Reason} -> + {error, Reason} + end. + +-spec get_config(ServiceId :: any()) -> error | {ok, Config :: #service_config{}}. +get_config(ServiceId) when is_binary(ServiceId) -> + case mnesia:dirty_read(?TAB, ServiceId) of + [] -> + error; + [Config] -> + {ok, Config} + end. + +-spec delete(ServiceId :: binary()) -> ok | {error, Reason :: any()}. +delete(ServiceId) when is_binary(ServiceId) -> + case mnesia:transaction(fun() -> mnesia:delete(?TAB, ServiceId, write) end) of + {'atomic', ok} -> + ok; + {'aborted', Reason} -> + {error, Reason} + end. + +as_map(#service_config{service_id = ServiceId, config_json = ConfigJson, last_config_json = LastConfigJson, last_edit_user = LastEditUser, update_ts = UpdateTs, create_ts = CreateTs}) -> + #{ + <<"service_id">> => ServiceId, + <<"config_json">> => ConfigJson, + <<"last_config_json">> => LastConfigJson, + <<"last_edit_user">> => LastEditUser, + <<"update_ts">> => UpdateTs, + <<"create_ts">> => CreateTs + }. \ No newline at end of file