From 61275a4183132442826900790c8d102a30c1ed99 Mon Sep 17 00:00:00 2001 From: anlicheng Date: Mon, 27 Feb 2023 00:53:03 +0800 Subject: [PATCH] fix model --- apps/iot/include/iot.hrl | 17 ++++---- apps/iot/src/http_host_handler.erl | 56 ++++++++++++++++--------- apps/iot/src/iot_message_handler.erl | 2 +- apps/iot/src/iot_mock.erl | 46 ++++++++++++++++++++- apps/iot/src/model/host_model.erl | 59 +++++++++++++++++---------- apps/iot/src/model/service_model.erl | 42 +++++++++++++++---- apps/iot/src/model/terminal_model.erl | 54 ++++++++++++++++-------- 7 files changed, 200 insertions(+), 76 deletions(-) diff --git a/apps/iot/include/iot.hrl b/apps/iot/include/iot.hrl index 7d3cf30..b167e37 100644 --- a/apps/iot/include/iot.hrl +++ b/apps/iot/include/iot.hrl @@ -46,10 +46,12 @@ -record(interface_metric, { %% 接口名称 name = <<>>, - %% 接口详情 + %% 接口描述 desc = <<>>, + %% 接口详情, 可以是元素的json + detail = <<>>, %% 接口状态 - status + status = 0 }). %% 微服务指标收集 @@ -63,7 +65,7 @@ %% 单位, 如电压: a、v unit :: any(), %% 历史值序列, 队列;保存最近的100数值, 格式为: [{ts, value}] - queue = [] :: queus:queue(), + queue = queue:new() :: queus:queue(), %% 最后更新时间 update_ts = 0 :: integer() }). @@ -116,14 +118,13 @@ %% 接入协议 access_protocol :: binary(), %% 产品ID,枚举类型 - product_id :: integer(), + product_id = 0 :: integer(), %% 厂商ID,枚举类型 - vendor_id :: integer(), + vendor_id = 0 :: integer(), %% 型号 - model :: binary(), + model = <<>> :: binary(), %% 所在单元ID,管理系统负责 - cell_id :: integer(), - + cell_id = 0 :: integer(), %% 终端状态 status = 0 :: integer(), %% 最后上线时间 diff --git a/apps/iot/src/http_host_handler.erl b/apps/iot/src/http_host_handler.erl index db51248..dcbe936 100644 --- a/apps/iot/src/http_host_handler.erl +++ b/apps/iot/src/http_host_handler.erl @@ -36,27 +36,25 @@ handle_request(_, "/host/list", Params, PostParams) -> 0 end, - %% 过滤函数 - Filter = fun(#host{model = Model0, cell_id = CellId0}) -> - lists:all(fun(E) -> - case E of - {model, M} -> - lager:debug("m: ~p, mid: ~p", [M, Model0]), - case M =/= <<"">> of - true -> M =:= Model0; - _ -> true - end; - {cell_id, C} -> - lager:debug("c: ~p, cid: ~p", [C, CellId0]), - case C > 0 of - true -> C == CellId0; - _ -> true - end - end - end, [{model, Model}, {cell_id, CellId1}]) + MatchHead = #host{model = '$1', cell_id = '$2', _ = '_'}, + Guard = [], + Guard1 = case Model =/= <<"">> of + true -> + [{'=:=', '$1', Model}|Guard]; + false -> + Guard end, - case host_model:get_hosts(Filter, Start, Size) of + Guard2 = case CellId1 > 0 of + true -> + [{'=:=', '$2', CellId1}|Guard1]; + false -> + Guard1 + end, + + Result = ['$_'], + + case host_model:get_hosts({MatchHead, Guard2, Result}, Start, Size) of {ok, Hosts, TotalNum} -> Response = #{ <<"hosts">> => lists:map(fun(Host) -> host_model:to_map(Host) end, Hosts), @@ -71,6 +69,26 @@ handle_request(_, "/host/list", Params, PostParams) -> lager:warning("[host_handler] get a error: ~p", [Reason]), {ok, 200, iot_util:json_error(404, <<"database error">>)} end; + +handle_request("GET", "/host/detail", #{<<"id">> := HostId}, _) -> + lager:debug("[host_handler] detail id is: ~p", [HostId]), + case host_model:get_host(HostId) of + undefined -> + {ok, 200, iot_util:json_error(404, <<"host not found">>)}; + {ok, Host} -> + HostInfo = host_model:to_map(Host), + %% 获取终端信息 + {ok, Terminals0} = terminal_model:get_host_terminals(HostId), + Terminals = lists:map(fun(E) -> terminal_model:to_map(E) end, Terminals0), + HostInfo1 = maps:put(<<"terminals">>, Terminals, HostInfo), + %% 获取微服务信息 + {ok, Services0} = service_model:get_host_services(HostId), + Services = lists:map(fun(S) -> service_model:to_map(S) end, Services0), + HostInfo2 = maps:put(<<"services">>, Services, HostInfo1), + + {ok, 200, iot_util:json_data(HostInfo2)} + end; + handle_request("POST", "/host/update", _, _Params) -> lager:debug("[host_handler] post params is: ~p", [_Params]), diff --git a/apps/iot/src/iot_message_handler.erl b/apps/iot/src/iot_message_handler.erl index 20408be..7c01562 100644 --- a/apps/iot/src/iot_message_handler.erl +++ b/apps/iot/src/iot_message_handler.erl @@ -81,7 +81,7 @@ handle(<<"server.register">>, Msg = #{<<"c_id">> := ClientId, <<"r">> := PubKey, handle(<<"server.data">>, #{<<"c_id">> := HostId, <<"d">> := Data}) -> case host_model:get_host(HostId) of {ok, #host{aes = Aes}} -> - Services = microservice_model:get_services(HostId), + Services = service_model:get_services(HostId), PlainData = iot_cipher_aes:decrypt(Aes, Aes, Data), case jiffy:decode(PlainData, [return_maps]) of Infos when is_list(Infos) -> diff --git a/apps/iot/src/iot_mock.erl b/apps/iot/src/iot_mock.erl index 145ab0e..381d15e 100644 --- a/apps/iot/src/iot_mock.erl +++ b/apps/iot/src/iot_mock.erl @@ -11,7 +11,7 @@ -include("iot.hrl"). %% API --export([insert_hosts/0]). +-export([insert_hosts/0, insert_services/1, insert_terminals/1]). -export([rsa_encode/1]). insert_hosts() -> @@ -27,6 +27,50 @@ insert_hosts() -> host_model:add_host(Host) end, lists:seq(1, 100)). +insert_services(HostId) -> + lists:foreach(fun(Id0) -> + Q0 = queue:new(), + Q = queue:in({1234, 21}, Q0), + Service = #service{ + service_id = integer_to_binary(Id0), + host_id = HostId, + name = <<"Service_0001">>, + category = <<"电器"/utf8>>, + %% 应用对象 + apply_object = <<"暂时不清楚"/utf8>>, + %% 版本 + version = <<"v1.1">>, + %% 执行次数 + execute_count = 10, + %% 部署时间 + deploy_ts = 0, + metrics = [#service_metric{symbol = <<"X10">>, name = <<"温度"/utf8>>, last_value = 10, unit = <<"E">>, queue = Q}], + status = 0 + }, + + service_model:add_service(Service) + end, lists:seq(1, 100)). + +insert_terminals(HostId) -> + lists:foreach(fun(Id0) -> + Q0 = queue:new(), + Q = queue:in({1234, 21}, Q0), + Terminal = #terminal{ + terminal_id = integer_to_binary(Id0), + host_id = HostId, + name = <<"Service_0001">>, + code = <<"1234">>, + access_protocol = <<"TCP/IP">>, + product_id = 12, + vendor_id = 13, + model = <<"1345">>, + cell_id = 12, + status = 0 + }, + + terminal_model:add_terminal(Terminal) + end, lists:seq(1, 100)). + rsa_encode(Data) when is_binary(Data) -> %% 读取相关配置 diff --git a/apps/iot/src/model/host_model.erl b/apps/iot/src/model/host_model.erl index 30fe9fe..bad464b 100644 --- a/apps/iot/src/model/host_model.erl +++ b/apps/iot/src/model/host_model.erl @@ -24,26 +24,14 @@ get_host(HostId) when is_binary(HostId) -> end. %% 获取app信息 --spec get_hosts(Filter :: fun(), Start :: integer(), Limit :: integer()) -> +-spec get_hosts(Filter :: any(), Start :: integer(), Limit :: integer()) -> {ok, Items :: list(), TotalNum :: integer()} | {error, Reason :: any()}. -get_hosts(Filter, Start, Limit) when is_function(Filter, 1), is_integer(Limit), is_integer(Start), Start >= 0, Limit > 0 -> - Fun = fun() -> - mnesia:foldl(fun(Host, Acc) -> - case Filter(Host) of - true -> [Host|Acc]; - false -> Acc - end - end, [], host) - end, - case mnesia:transaction(Fun) of - {atomic, Items0} when is_list(Items0) -> - Items = lists:reverse(Items0), - NItems = lists:sublist(Items, Start + 1, Limit), - {ok, NItems, length(Items)}; - {aborted, Error} -> - Error - end. +get_hosts(Spec, Start, Limit) when is_integer(Limit), is_integer(Start), Start >= 0, Limit > 0 -> + Items0 = mnesia:dirty_select(host, [Spec]), + Items = lists:reverse(Items0), + NItems = lists:sublist(Items, Start + 1, Limit), + {ok, NItems, length(Items)}. %% 按照状态分组统计 get_stat() -> @@ -126,9 +114,13 @@ table_size() -> %% helper methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -to_map(#host{host_id = HostId, name = Name, model = Model, cell_id = CellId, activated_ts = ActivatedTs, - update_ts = UpdateTs, status = Status}) -> - +to_map(#host{host_id = HostId, name = Name, model = Model, cell_id = CellId, activated_ts = ActivatedTs, update_ts = UpdateTs, status = Status, + metric = #host_metric{ + cpus = Cpus, + cpu_temperature = CpuTemperature, + memory = #memory_metric{used = MemoryUsed, total = MemoryTotal}, + disk = #disk_metric{used = DiskUsed, total = DiskTotal}, + interfaces = Interfaces}}) -> #{ <<"host_id">> => HostId, <<"name">> => Name, @@ -136,5 +128,28 @@ to_map(#host{host_id = HostId, name = Name, model = Model, cell_id = CellId, act <<"cell_id">> => CellId, <<"activated_ts">> => ActivatedTs, <<"update_ts">> => UpdateTs, - <<"status">> => Status + <<"status">> => Status, + <<"metric">> => #{ + <<"cpus">> => lists:map(fun(#cpu_metric{num = Num, load = Load}) -> + #{<<"num">> => Num, <<"load">> => Load } + end, + Cpus), + <<"cpu_temperature">> => CpuTemperature, + <<"memory">> => #{ + <<"used">> => MemoryUsed, + <<"total">> => MemoryTotal + }, + <<"disk">> => #{ + <<"used">> => DiskUsed, + <<"total">> => DiskTotal + }, + <<"interfaces">> => lists:map(fun(#interface_metric{name = IName, desc = IDesc, status = IStatus, detail = IDetail}) -> + #{ + <<"name">> => IName, + <<"desc">> => IDesc, + <<"status">> => IStatus, + <<"detatil">> => IDetail + } + end, Interfaces) + } }. \ No newline at end of file diff --git a/apps/iot/src/model/service_model.erl b/apps/iot/src/model/service_model.erl index 849b62e..52d5a30 100644 --- a/apps/iot/src/model/service_model.erl +++ b/apps/iot/src/model/service_model.erl @@ -12,8 +12,8 @@ -include_lib("stdlib/include/qlc.hrl"). %% API --export([get_services/1, get_service/2, add_service/1, change_status/2, delete/1, table_size/0]). --export([update_metric/2]). +-export([get_host_services/1, get_service/2, add_service/1, change_status/2, delete/1, table_size/0]). +-export([update_metric/2, to_map/1]). get_service(HostId, ServiceName) when is_binary(HostId), is_binary(ServiceName) -> Fun = fun() -> @@ -27,16 +27,16 @@ get_service(HostId, ServiceName) when is_binary(HostId), is_binary(ServiceName) undefined end. -get_services(HostId) when is_binary(HostId) -> +get_host_services(HostId) when is_binary(HostId) -> Fun = fun() -> Q = qlc:q([E || E <- mnesia:table(service), E#service.host_id =:= HostId]), qlc:e(Q) end, case mnesia:transaction(Fun) of - Services when is_list(Services) -> - Services; - _ -> - [] + {atomic, Services} when is_list(Services) -> + {ok, Services}; + {aborted, Error} -> + {error, Error} end. add_service(Service = #service{}) -> @@ -95,6 +95,34 @@ delete(ServiceId) when is_binary(ServiceId) -> table_size() -> mnesia:table_info(service, size). +to_map(#service{service_id = ServiceId, host_id = HostId, name = Name, category = Category, apply_object = ApplyObject, + version = Version, execute_count = ExecuteCount, deploy_ts = DeployTs, metrics = Metrics, status = Status}) -> + + Metrics1 = lists:map(fun(#service_metric{symbol = MetricSymbol, name = MetricName, last_value = LastValue, unit = Unit, queue = Queue, update_ts = UpdateTs}) -> + Q = lists:map(fun({Ts, Val}) -> #{<<"time">> => Ts, <<"value">> => Val} end, queue:to_list(Queue)), + #{ + <<"symbol">> => MetricSymbol, + <<"name">> => MetricName, + <<"last_value">> => LastValue, + <<"queue">> => Q, + <<"unit">> => Unit, + <<"update_ts">> => UpdateTs + } + end, Metrics), + + #{ + <<"service_id">> => ServiceId, + <<"host_id">> => HostId, + <<"name">> => Name, + <<"category">> => Category, + <<"apply_object">> => ApplyObject, + <<"version">> => Version, + <<"execute_count">> => ExecuteCount, + <<"deploy_ts">> => DeployTs, + <<"metrics">> => Metrics1, + <<"status">> => Status + }. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% helper methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/apps/iot/src/model/terminal_model.erl b/apps/iot/src/model/terminal_model.erl index b48bb40..73ad996 100644 --- a/apps/iot/src/model/terminal_model.erl +++ b/apps/iot/src/model/terminal_model.erl @@ -12,8 +12,8 @@ -include_lib("stdlib/include/qlc.hrl"). %% API --export([get_all_terminals/0, get_status_stat/0]). --export([change_status/2, delete/1]). +-export([get_all_terminals/0, get_host_terminals/1, get_status_stat/0, table_size/0]). +-export([change_status/2, delete/1, to_map/1, add_terminal/1]). %% 获取app信息 get_all_terminals() -> @@ -22,10 +22,22 @@ get_all_terminals() -> qlc:e(Q) end, case mnesia:transaction(Fun) of - Items when is_list(Items) -> + {atomic, Items} when is_list(Items) -> {ok, Items}; - {error, _, Reason} -> - {error, Reason} + {aborted, Error} -> + {error, Error} + end. + +get_host_terminals(HostId) when is_binary(HostId) -> + Fun = fun() -> + Q = qlc:q([E || E <- mnesia:table(terminal), E#terminal.host_id =:= HostId]), + qlc:e(Q) + end, + case mnesia:transaction(Fun) of + {atomic, Items} when is_list(Items) -> + {ok, Items}; + {aborted, Error} -> + {error, Error} end. %% 获取状态分组统计信息 @@ -45,19 +57,7 @@ get_status_stat() -> {error, Reason} end. -insert(Id, HostId, Name, ProductId, VendorId, Model, CellId) -> - Terminal = #terminal{ - terminal_id = Id, - name = Name, - product_id = ProductId, - vendor_id = VendorId, - model = Model, - cell_id = CellId, - host_id = HostId, - update_ts = 0, - status = ?HOST_STATUS_INACTIVE - }, - +add_terminal(Terminal = #terminal{}) -> case mnesia:transaction(fun() -> mnesia:write(terminal, Terminal, write) end) of {atomic, _} -> ok; @@ -94,6 +94,24 @@ delete(TerminalId) when is_binary(TerminalId) -> table_size() -> mnesia:table_info(host, size). +to_map(#terminal{terminal_id = TerminalId, host_id = HostId, name = Name, code = Code, access_protocol = AccessProtocol, + product_id = ProductId, vendor_id = VendorId, model = Model, cell_id = CellId, status = Status, update_ts = UpdateTs}) -> + #{ + <<"terminal_id">> => TerminalId, + <<"host_id">> => HostId, + <<"name">> => Name, + <<"code">> => Code, + <<"access_protocol">> => AccessProtocol, + <<"product_id">> => ProductId, + <<"vendor_id">> => VendorId, + <<"model">> => Model, + <<"cell_id">> => CellId, + <<"status">> => Status, + <<"update_ts">> => UpdateTs + }. + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% helper methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file