This commit is contained in:
anlicheng 2023-06-15 14:58:55 +08:00
parent b68e1489dd
commit 42b3b8b2fa
4 changed files with 44 additions and 35 deletions

View File

@ -112,29 +112,26 @@ handle_request("POST", "/host/activate", _, #{<<"uuid">> := UUID, <<"auth">> :=
lager:debug("[host_handler] activate host_id: ~p, failed with reason: ~p", [UUID, Reason]),
{ok, 200, iot_util:json_error(400, <<"host not found">>)};
{ok, Pid} when is_pid(Pid) ->
lager:debug("[host_handler] activate host_id: ~p, start", [UUID]),
%%
{ok, Assoc, Aes} = iot_host:make_assoc(Pid),
ReplyTopic = iot_host:upstream_topic(UUID),
Reply = case Auth of
true ->
#{<<"auth">> => true, <<"aes">> => Aes, <<"reply">> => #{<<"topic">> => ReplyTopic, <<"assoc">> => Assoc}};
false ->
#{<<"auth">> => false, <<"aes">> => <<"">>, <<"reply">> => #{ <<"topic">> => ReplyTopic, <<"assoc">> => Assoc}}
end,
BinReply = jiffy:encode(Reply, [force_utf8]),
case iot_host:has_session(Pid) of
true ->
lager:debug("[host_handler] activate host_id: ~p, start", [UUID]),
{ok, Assoc} = iot_host:make_assoc(Pid),
ReplyTopic = iot_host:upstream_topic(UUID),
Reply = case Auth of
true ->
#{<<"auth">> => true, <<"reply">> => #{<<"topic">> => ReplyTopic, <<"assoc">> => Assoc}};
false ->
#{<<"auth">> => false, <<"reply">> => #{ <<"topic">> => ReplyTopic, <<"assoc">> => Assoc}}
end,
BinReply = jiffy:encode(Reply, [force_utf8]),
CommandType = 8,
case iot_host:rsa_encode(Pid, CommandType, BinReply) of
{error, Reason} when is_binary(Reason) ->
{ok, 200, iot_util:json_error(401, Reason)};
{ok, BinCommand} ->
CommandType = 8,
Topic = iot_host:downstream_topic(UUID),
case iot_mqtt_publisher:publish(Topic, BinCommand, 2) of
case iot_mqtt_publisher:publish(Topic, <<CommandType:8, BinReply/binary>>, 2) of
{ok, Ref} ->
receive
{ok, Ref, _PacketId} ->
%%
receive
{host_reply, Assoc, #{<<"code">> := 1}} ->
ok = iot_host:activate(Pid, Auth),
@ -151,7 +148,10 @@ handle_request("POST", "/host/activate", _, #{<<"uuid">> := UUID, <<"auth">> :=
{error, Reason} ->
lager:debug("[iot_host] host_id uuid: ~p, publish topic get error: ~p", [UUID, Reason]),
{ok, 200, iot_util:json_error(402, <<"发送命令到mqtt服务失败"/utf8>>)}
end
end;
false ->
ok = iot_host:activate(Pid, Auth),
{ok, 200, iot_util:json_data(<<"success">>)}
end
end;

View File

@ -19,6 +19,7 @@
%% API
-export([start_link/2, get_name/1, get_pid/1, handle/2, reload/1, activate/2]).
-export([get_metric/1, aes_encode/3, downstream_topic/1, upstream_topic/1, get_aes/1, make_assoc/1, rsa_encode/3]).
-export([has_session/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
@ -77,11 +78,6 @@ downstream_topic(UUID) when is_binary(UUID) ->
upstream_topic(UUID) when is_binary(UUID) ->
<<"host/upstream/", UUID/binary>>.
-spec rsa_encode(Pid :: pid(), CommandType :: integer(), PlainText :: binary()) ->
{ok, EncText :: binary()} | {error, Reason :: binary()}.
rsa_encode(Pid, CommandType, PlainText) when is_pid(Pid), is_integer(CommandType), is_binary(PlainText) ->
gen_server:call(Pid, {rsa_encode, CommandType, PlainText}).
%%
-spec handle(Pid :: pid(), Payload :: binary() | map()) -> no_return().
handle(Pid, Payload) when is_pid(Pid), is_binary(Payload); is_map(Payload) ->
@ -96,7 +92,7 @@ reload(Pid) when is_pid(Pid) ->
get_aes(Pid) when is_pid(Pid) ->
gen_server:call(Pid, get_aes).
-spec make_assoc(Pid :: pid()) -> {ok, Assoc :: binary(), Aes :: binary()}.
-spec make_assoc(Pid :: pid()) -> {ok, Assoc :: binary()}.
make_assoc(Pid) when is_pid(Pid) ->
gen_server:call(Pid, {make_assoc, self()}).
@ -109,6 +105,16 @@ activate(Pid, Auth) when is_pid(Pid), is_boolean(Auth) ->
get_metric(Pid) when is_pid(Pid) ->
gen_server:call(Pid, get_metric).
-spec has_session(Pid :: pid()) -> boolean().
has_session(Pid) when is_pid(Pid) ->
gen_server:call(Pid, has_session).
%% rsa加密的指令都是不需要会话存在的
-spec rsa_encode(Pid :: pid(), CommandType :: integer(), PlainText :: binary()) ->
{ok, EncText :: binary()} | {error, Reason :: binary()}.
rsa_encode(Pid, CommandType, PlainText) when is_pid(Pid), is_integer(CommandType), is_binary(PlainText) ->
gen_server:call(Pid, {rsa_encode, CommandType, PlainText}).
-spec aes_encode(Pid :: pid(), CommandType :: integer(), Params :: binary()) ->
{ok, Command :: binary()} | {error, Reason :: any()}.
aes_encode(Pid, CommandType, Params) when is_pid(Pid), is_integer(CommandType), is_binary(Params) ->
@ -160,7 +166,12 @@ handle_call(get_metric, _From, State) ->
handle_call(get_aes, _From, State = #state{aes = Aes}) ->
{reply, {ok, Aes}, State};
%%
handle_call(has_session, _From, State = #state{has_session = HasSession}) ->
{reply, HasSession, State};
%% rsa加密
%% rsa加密的指令都是不需要会话存在的
handle_call({rsa_encode, _, _}, _From, State = #state{has_session = false}) ->
{reply, {error, <<"会话未建立,发送命令失败"/utf8>>}, State};
handle_call({rsa_encode, CommandType, PlainText}, _From, State = #state{pub_key = PubKey}) ->
@ -168,11 +179,11 @@ handle_call({rsa_encode, CommandType, PlainText}, _From, State = #state{pub_key
{reply, {ok, <<CommandType:8, Reply/binary>>}, State};
handle_call({make_assoc, ReceivePid}, _From, State = #state{uuid = UUID, increment_id = IncrementId, assoc_map = AssocMap, aes = Aes}) ->
handle_call({make_assoc, ReceivePid}, _From, State = #state{uuid = UUID, increment_id = IncrementId, assoc_map = AssocMap}) ->
BinIncrementId = erlang:integer_to_binary(IncrementId),
Assoc = <<UUID/binary, ":assoc:", BinIncrementId/binary>>,
{reply, {ok, Assoc, Aes}, State#state{assoc_map = maps:put(Assoc, ReceivePid, AssocMap), increment_id = IncrementId + 1}};
{reply, {ok, Assoc}, State#state{assoc_map = maps:put(Assoc, ReceivePid, AssocMap), increment_id = IncrementId + 1}};
%%
handle_call(reload, _From, State = #state{uuid = UUID}) ->

View File

@ -200,11 +200,10 @@ handle_info({publish, #{payload := Payload, qos := Qos, topic := FromTopic}},
lager:debug("[host_mocker] auth failed")
end;
%% 8 rsa加密的数据aesaes加密的
<<8:8, Command0/binary>> ->
Command = iot_cipher_rsa:decode(Command0, PrivateKey),
%% t = 8
<<8:8, Command/binary>> ->
case jiffy:decode(Command, [return_maps]) of
#{<<"aes">> := Aes, <<"auth">> := true, <<"reply">> := #{<<"topic">> := Topic, <<"assoc">> := Assoc}} ->
#{<<"auth">> := true, <<"reply">> := #{<<"topic">> := Topic, <<"assoc">> := Assoc}} ->
Msg = jiffy:encode(#{
<<"code">> => 1,
<<"message">> => "",
@ -219,9 +218,9 @@ handle_info({publish, #{payload := Payload, qos := Qos, topic := FromTopic}},
lager:debug("[host_mocker] send reply failed, reason: ~p", [Reason])
end,
{noreply, State#state{aes = Aes}};
{noreply, State};
#{<<"aes">> := Aes, <<"auth">> := false, <<"reply">> := #{<<"topic">> := Topic, <<"assoc">> := Assoc}} ->
#{<<"auth">> := false, <<"reply">> := #{<<"topic">> := Topic, <<"assoc">> := Assoc}} ->
Msg = jiffy:encode(#{
<<"code">> => 1,
<<"message">> => "",

View File

@ -74,11 +74,10 @@ t = 8
```json
// 数据采用之前协商的aes加密
// 数据采用明文传输主机在收到通知后需要通过create_session操作重新协商aes
{
"auth": true/false, // true表示授权此时aes的值不为空false表示取消授权
"aes": "",
"reply": {
"topic": "", // 主机端操作成功后需要回写的topic名称
"assoc": "" // 关联的信息,回写的时候需要带上