add terminal_handler
This commit is contained in:
parent
e25469d1c5
commit
2e2b0cab8b
@ -90,7 +90,7 @@
|
||||
|
||||
%% id生成器
|
||||
-record(id_generator, {
|
||||
name :: string(),
|
||||
name :: atom(),
|
||||
seq = 0 :: integer()
|
||||
}).
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ handle_request("POST", "/host/create", _, HostInfo) ->
|
||||
end;
|
||||
|
||||
%% 批量导入
|
||||
handle_request("POST", "/host/batch_create", _, HostInfos) ->
|
||||
handle_request("POST", "/host/batch_import", _, HostInfos) ->
|
||||
lager:debug("[host_handler] batch_create post params: ~p", [HostInfos]),
|
||||
|
||||
%% serial_number是必填项
|
||||
|
||||
206
apps/iot/src/http_handler/http_terminal_handler.erl
Normal file
206
apps/iot/src/http_handler/http_terminal_handler.erl
Normal file
@ -0,0 +1,206 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @author licheng5
|
||||
%%% @copyright (C) 2020, <COMPANY>
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% @end
|
||||
%%% Created : 26. 4月 2020 3:36 下午
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(http_terminal_handler).
|
||||
-author("licheng5").
|
||||
-include("iot.hrl").
|
||||
|
||||
%% API
|
||||
-export([handle_request/4]).
|
||||
|
||||
%% 添加终端
|
||||
handle_request("POST", "/terminal/create", _, TerminalInfo) ->
|
||||
lager:debug("[terminal_handler] create post params: ~p", [TerminalInfo]),
|
||||
|
||||
case valid_terminal_info(TerminalInfo) of
|
||||
true ->
|
||||
TerminalId = id_generator_model:new_terminal_id(),
|
||||
Terminal = convert_terminal_info(TerminalId, TerminalInfo),
|
||||
|
||||
case terminal_model:add_terminal(Terminal) of
|
||||
ok ->
|
||||
{ok, 200, iot_util:json_data(TerminalId)};
|
||||
{error, Reason} when is_binary(Reason) ->
|
||||
lager:warning("[host_handler] get a error: ~p", [Reason]),
|
||||
{ok, 200, iot_util:json_error(-1, Reason)};
|
||||
{error, Reason} when is_binary(Reason) ->
|
||||
{ok, 200, iot_util:json_error(-1, <<"database error">>)}
|
||||
end;
|
||||
false ->
|
||||
Error = terminal_error(TerminalInfo),
|
||||
{ok, 200, iot_util:json_error(-1, Error)}
|
||||
end;
|
||||
|
||||
%% 批量导入
|
||||
handle_request("POST", "/terminal/batch_import", _, TerminalInfos) ->
|
||||
lager:debug("[terminal_handler] batch_import post params: ~p", [TerminalInfos]),
|
||||
|
||||
%% serial_number是必填项
|
||||
case lists:any(fun(Info) -> not is_map_key(<<"serial_number">>, Info) orelse maps:get(<<"serial_number">>, Info) == <<"">> end, TerminalInfos) of
|
||||
true ->
|
||||
{ok, 200, iot_util:json_error(-1, <<"serial_number missed">>)};
|
||||
false ->
|
||||
case lists:all(fun valid_terminal_info/1, TerminalInfos) of
|
||||
true ->
|
||||
ImportResult = lists:map(fun(TerminalInfo = #{<<"serial_number">> := SerialNumber}) ->
|
||||
TerminalId = id_generator_model:new_terminal_id(),
|
||||
Terminal = convert_terminal_info(TerminalId, TerminalInfo),
|
||||
case terminal_model:add_terminal(Terminal) of
|
||||
ok ->
|
||||
{SerialNumber, TerminalId};
|
||||
{error, Reason} when is_binary(Reason) ->
|
||||
lager:debug("[host_handler] add_host get error: ~p", [Reason]),
|
||||
{SerialNumber, Reason};
|
||||
{error, Reason} ->
|
||||
{SerialNumber, <<"failed">>}
|
||||
end
|
||||
end, TerminalInfos),
|
||||
|
||||
{ok, 200, iot_util:json_data(ImportResult)};
|
||||
false ->
|
||||
%% 反馈错误信息
|
||||
InvalidTerminalInfos = lists:filter(fun(Info) -> not valid_terminal_info(Info) end, TerminalInfos),
|
||||
ErrorInfos = lists:map(fun(Info = #{<<"serial_number">> := SerialNumber}) -> {SerialNumber, terminal_error(Info)} end, InvalidTerminalInfos),
|
||||
{ok, 200, iot_util:json_error(-1, maps:from_list(ErrorInfos))}
|
||||
end
|
||||
end;
|
||||
|
||||
%% 获取终端的统计信息
|
||||
handle_request("GET", "/terminal/stat", _, _) ->
|
||||
case terminal_model:get_stat() of
|
||||
{ok, {TotalNum, Stat}} ->
|
||||
StatInfo = #{
|
||||
<<"total_num">> => TotalNum,
|
||||
<<"stat">> => lists:map(fun({Status, Num}) -> #{<<"status">> => Status, <<"num">> => Num} end, maps:to_list(Stat))
|
||||
},
|
||||
{ok, 200, iot_util:json_data(StatInfo)};
|
||||
{error, Reason} ->
|
||||
lager:warning("[host_handler] get a error: ~p", [Reason]),
|
||||
{ok, 200, iot_util:json_error(404, <<"database error">>)}
|
||||
end;
|
||||
|
||||
%% 获取终端的列表信息
|
||||
handle_request(_, "/terminal/list", GetParams, PostParams) ->
|
||||
Page0 = maps:get(<<"page">>, GetParams, <<"1">>),
|
||||
Size0 = maps:get(<<"size">>, GetParams, <<"10">>),
|
||||
Page = binary_to_integer(Page0),
|
||||
Size = binary_to_integer(Size0),
|
||||
|
||||
true = Page > 0 andalso Size > 0,
|
||||
Start = (Page - 1) * Size,
|
||||
|
||||
%% 处理查询条件
|
||||
Model = maps:get(<<"model">>, PostParams, <<"">>),
|
||||
CellId = maps:get(<<"cell_id">>, PostParams, <<"">>),
|
||||
CellId1 = case CellId =/= <<>> of
|
||||
true -> binary_to_integer(CellId);
|
||||
false -> 0
|
||||
end,
|
||||
|
||||
case terminal_model:find_terminals([{model, Model}, {cell, CellId1}], Start, Size) of
|
||||
{ok, Terminals, TotalNum} ->
|
||||
Response = #{
|
||||
<<"total_num">> => TotalNum,
|
||||
<<"terminals">> => lists:map(fun terminal_model:to_map/1, Terminals)
|
||||
},
|
||||
|
||||
lager:debug("resp is: ~p", [Response]),
|
||||
|
||||
{ok, 200, iot_util:json_data(Response)};
|
||||
{error, Reason} ->
|
||||
lager:warning("[host_handler] get a error: ~p", [Reason]),
|
||||
{ok, 200, iot_util:json_error(404, <<"database error">>)}
|
||||
end;
|
||||
|
||||
%% 获取终端详情
|
||||
handle_request("GET", "/terminal/detail", #{<<"terminal_id">> := TerminalId}, _) ->
|
||||
lager:debug("[terminal_handler] terminal detail id is: ~p", [TerminalId]),
|
||||
case terminal_model:get_terminal(TerminalId) of
|
||||
undefined ->
|
||||
{ok, 200, iot_util:json_error(404, <<"terminal not found">>)};
|
||||
{ok, Terminal} ->
|
||||
TerminalInfo = terminal_model:to_map(Terminal),
|
||||
%% TODO 获取终端的数据信息
|
||||
|
||||
{ok, 200, iot_util:json_data(TerminalInfo)}
|
||||
end;
|
||||
|
||||
%% 更新状态信息
|
||||
handle_request("POST", "/terminal/change_status", _, #{<<"terminal_id">> := TerminalId, <<"status">> := Status}) when is_integer(TerminalId), is_integer(Status) ->
|
||||
lager:debug("[terminal_handler] change_status id is: ~p", [TerminalId]),
|
||||
case terminal_model:change_status(TerminalId, Status) of
|
||||
{error, Reason} when is_binary(Reason) ->
|
||||
{ok, 200, iot_util:json_error(-1, Reason)};
|
||||
ok ->
|
||||
{ok, 200, iot_util:json_data(<<"success">>)}
|
||||
end;
|
||||
|
||||
%% 更新终端信息
|
||||
handle_request("POST", "/terminal/update", _, Fields0 = #{<<"terminal_id">> := TerminalId}) ->
|
||||
lager:debug("[terminal_handler] update terminal params is: ~p", [Fields0]),
|
||||
|
||||
Fields = maps:remove(<<"terminal_id">>, Fields0),
|
||||
case terminal_model:update_terminal(TerminalId, Fields) of
|
||||
ok ->
|
||||
{ok, 200, iot_util:json_data(<<"success">>)};
|
||||
{error, Reason} when is_binary(Reason) ->
|
||||
{ok, 200, iot_util:json_error(-1, Reason)}
|
||||
end;
|
||||
|
||||
handle_request(_, Path, _, _) ->
|
||||
Path1 = list_to_binary(Path),
|
||||
{ok, 200, iot_util:json_error(-1, <<"url: ", Path1/binary, " not found">>)}.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% helper methods
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
%% 将map转换成record
|
||||
convert_terminal_info(TerminalId, TerminalInfo) when is_integer(TerminalId), is_map(TerminalInfo) ->
|
||||
#terminal{
|
||||
terminal_id = TerminalId,
|
||||
%% 关联主机
|
||||
host_id = maps:get(<<"host_id">>, TerminalInfo, <<"">>),
|
||||
%% 序列号
|
||||
serial_number = maps:get(<<"serial_number">>, TerminalInfo, <<"">>),
|
||||
%% 名称
|
||||
name = maps:get(<<"name">>, TerminalInfo, <<"">>),
|
||||
%% 设备编码
|
||||
code = maps:get(<<"code">>, TerminalInfo, <<"">>),
|
||||
%% 接入协议
|
||||
access_protocol = maps:get(<<"access_protocol">>, TerminalInfo, <<"">>),
|
||||
%% 产品ID,枚举类型
|
||||
product_id = maps:get(<<"product_id">>, TerminalInfo, 0),
|
||||
%% 厂商ID,枚举类型
|
||||
vendor_id = maps:get(<<"vendor_id">>, TerminalInfo, 0),
|
||||
%% 型号
|
||||
model = maps:get(<<"model">>, TerminalInfo, <<"">>),
|
||||
%% 所在单元ID,管理系统负责
|
||||
cell_id = maps:get(<<"cell_id">>, TerminalInfo, 0),
|
||||
%% 终端状态
|
||||
status = ?TERMINAL_STATUS_OFFLINE,
|
||||
%% 最后上线时间
|
||||
update_ts = 0
|
||||
}.
|
||||
|
||||
%% 检查是否是合法的主机信息
|
||||
valid_terminal_info(#{<<"name">> := Name, <<"model">> := Model, <<"cell_id">> := CellId, <<"serial_number">> := SerialNumber}) ->
|
||||
Name =/= <<"">> andalso Model =/= <<"">> andalso CellId > 0 andalso SerialNumber =/= <<"">>.
|
||||
|
||||
%% 获取错误信息
|
||||
terminal_error(M) when is_map(M) ->
|
||||
if
|
||||
not is_map_key(<<"name">>, M) orelse map_get(<<"name">>, M) == <<>> ->
|
||||
<<"name is empty">>;
|
||||
not is_map_key(<<"model">>, M) orelse map_get(<<"model">>, M) == <<>> ->
|
||||
<<"model is empty">>;
|
||||
not is_map_key(<<"serial_number">>, M) orelse map_get(<<"serial_number">>, M) == <<>> ->
|
||||
<<"serial_number is empty">>;
|
||||
true ->
|
||||
<<"unknown error">>
|
||||
end.
|
||||
@ -11,14 +11,13 @@
|
||||
-include("iot.hrl").
|
||||
|
||||
%% API
|
||||
-export([generate/1]).
|
||||
-export([generate/1, new_terminal_id/0]).
|
||||
|
||||
%% 生成对应的自增id
|
||||
-spec generate(Name :: string()) -> {ok, Id :: integer()} | {error, Reason :: any()}.
|
||||
generate(Name) when is_list(Name) ->
|
||||
case mnesia:transaction(fun() -> mnesia:dirty_update_counter(id_generator, Name, 1) end) of
|
||||
{atomic, Id} ->
|
||||
{ok, Id};
|
||||
{aborted, Reason} ->
|
||||
{error, Reason}
|
||||
end.
|
||||
-spec generate(Name :: atom()) -> Id :: integer().
|
||||
generate(Name) when is_atom(Name) ->
|
||||
mnesia:dirty_update_counter(id_generator, Name, 1).
|
||||
|
||||
-spec new_terminal_id() -> Id :: integer().
|
||||
new_terminal_id() ->
|
||||
generate(terminal).
|
||||
@ -14,8 +14,17 @@
|
||||
-define(TAB_NAME, terminal).
|
||||
|
||||
%% API
|
||||
-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]).
|
||||
-export([get_terminal/1, get_all_terminals/0, get_host_terminals/1, find_terminals/3, get_stat/0, table_size/0, match_spec/1]).
|
||||
-export([change_status/2, delete/1, to_map/1, add_terminal/1, update_terminal/2]).
|
||||
|
||||
-spec get_terminal(TerminalId :: integer()) -> {ok, #terminal{}} | undefined.
|
||||
get_terminal(TerminalId) when is_integer(TerminalId) ->
|
||||
case mnesia:dirty_read(?TAB_NAME, TerminalId) of
|
||||
[Terminal] ->
|
||||
{ok, Terminal};
|
||||
_ ->
|
||||
undefined
|
||||
end.
|
||||
|
||||
%% 获取app信息
|
||||
-spec get_all_terminals() -> {ok, Terminals :: [#terminal{}]} | {error, Reason :: any()}.
|
||||
@ -44,14 +53,30 @@ get_host_terminals(HostId) when is_binary(HostId) ->
|
||||
{error, Error}
|
||||
end.
|
||||
|
||||
%% 获取app信息
|
||||
-spec find_terminals(Matches :: [{Name :: atom(), Val :: any()}], Start :: integer(), Limit :: integer()) ->
|
||||
{ok, Terminals :: list(), TotalNum :: integer()} |
|
||||
{error, Reason :: any()}.
|
||||
find_terminals(Matches, Start, Limit) when is_list(Matches), is_integer(Limit), is_integer(Start), Start >= 0, Limit > 0 ->
|
||||
MatchSpec = terminal_model:match_spec(Matches),
|
||||
Terminals0 = mnesia:dirty_select(?TAB_NAME, [MatchSpec]),
|
||||
Terminals = sort(Terminals0),
|
||||
Len = length(Terminals),
|
||||
case Len >= Start + 1 of
|
||||
true ->
|
||||
{ok, lists:sublist(Terminals, Start + 1, Limit), Len};
|
||||
false ->
|
||||
{ok, [], Len}
|
||||
end.
|
||||
|
||||
%% 获取状态分组统计信息
|
||||
-spec get_status_stat() -> {ok, Stat :: #{}} | {error, Reason :: any()}.
|
||||
get_status_stat() ->
|
||||
-spec get_stat() -> {ok, {Total :: integer(), Stat :: #{}}} | {error, Reason :: any()}.
|
||||
get_stat() ->
|
||||
Fun = fun() ->
|
||||
mnesia:foldl(fun(#terminal{status = Status}, Acc) ->
|
||||
mnesia:foldl(fun(#terminal{status = Status}, {Total, Acc}) ->
|
||||
Num = maps:get(Status, Acc, 0),
|
||||
Acc#{Status => Num + 1}
|
||||
end, #{}, ?TAB_NAME)
|
||||
{Total + 1, Acc#{Status => Num + 1}}
|
||||
end, {0, #{}}, ?TAB_NAME)
|
||||
end,
|
||||
|
||||
case mnesia:transaction(Fun) of
|
||||
@ -70,6 +95,46 @@ add_terminal(Terminal = #terminal{}) ->
|
||||
{error, Error}
|
||||
end.
|
||||
|
||||
-spec change_status(TerminalId :: integer(), Fields :: #{}) -> ok | {error, Reason :: any()}.
|
||||
update_terminal(TerminalId, Fields) when is_integer(TerminalId), is_map(Fields) ->
|
||||
Fun = fun() ->
|
||||
case mnesia:read(?TAB_NAME, TerminalId) of
|
||||
[] ->
|
||||
mnesia:abort(<<"terminal not found">>);
|
||||
[Terminal] ->
|
||||
NTerminal = lists:foldl(fun(E, Terminal0) ->
|
||||
case E of
|
||||
{<<"name">>, Name} when is_binary(Name) ->
|
||||
Terminal0#terminal{name = Name};
|
||||
{<<"serial_number">>, SerialNumber} when is_binary(SerialNumber) ->
|
||||
Terminal0#terminal{serial_number = SerialNumber};
|
||||
{<<"code">>, Code} when is_binary(Code) ->
|
||||
Terminal0#terminal{code = Code};
|
||||
{<<"access_protocol">>, AccessProtocol} when is_binary(AccessProtocol) ->
|
||||
Terminal0#terminal{access_protocol = AccessProtocol};
|
||||
{<<"product_id">>, ProductId} when is_integer(ProductId) ->
|
||||
Terminal0#terminal{product_id = ProductId};
|
||||
{<<"vendor_id">>, VendorId} when is_integer(VendorId) ->
|
||||
Terminal0#terminal{vendor_id = VendorId};
|
||||
{<<"model">>, Model} when is_binary(Model) ->
|
||||
Terminal0#terminal{model = Model};
|
||||
{<<"cell_id">>, CellId} when is_integer(CellId) ->
|
||||
Terminal0#terminal{cell_id = CellId};
|
||||
{Name, _} ->
|
||||
mnesia:abort(<<"invalid: ", Name/binary>>)
|
||||
end
|
||||
end, Terminal, maps:to_list(Fields)),
|
||||
|
||||
mnesia:write(?TAB_NAME, NTerminal, write)
|
||||
end
|
||||
end,
|
||||
case mnesia:transaction(Fun) of
|
||||
{atomic, ok} ->
|
||||
ok;
|
||||
{aborted, Reason} ->
|
||||
{error, Reason}
|
||||
end.
|
||||
|
||||
-spec change_status(TerminalId :: integer(), Status :: integer()) -> ok | {error, Reason :: any()}.
|
||||
change_status(TerminalId, Status) when is_integer(TerminalId), is_integer(Status) ->
|
||||
Fun = fun() ->
|
||||
@ -100,6 +165,24 @@ delete(TerminalId) when is_integer(TerminalId) ->
|
||||
table_size() ->
|
||||
mnesia:table_info(host, size).
|
||||
|
||||
%% 获取查询的过滤条件
|
||||
match_spec(Specs) when is_list(Specs) ->
|
||||
MatchHead = #host{model = '$1', cell_id = '$2', _ = '_'},
|
||||
Guard = guard(Specs),
|
||||
Result = ['$_'],
|
||||
{MatchHead, Guard, Result}.
|
||||
|
||||
guard(Specs) when is_list(Specs) ->
|
||||
guard(Specs, []).
|
||||
guard([], Guard) ->
|
||||
Guard;
|
||||
guard([{model, Model}|Tail], Guard) when Model =/= <<"">> ->
|
||||
guard(Tail, [{'=:=', '$1', Model}|Guard]);
|
||||
guard([{cell, CellId}|Tail], Guard) when CellId > 0 ->
|
||||
guard(Tail, [{'=:=', '$2', CellId}|Guard]);
|
||||
guard([_|Tail], Guard) ->
|
||||
guard(Tail, Guard).
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% helper methods
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user