diff --git a/src/host/iot_host.erl b/src/host/iot_host.erl index 9898c14..14e8d06 100644 --- a/src/host/iot_host.erl +++ b/src/host/iot_host.erl @@ -215,11 +215,12 @@ handle_event({call, From}, get_metric, _, State = #state{metrics = Metrics}) -> {keep_state, State, [{reply, From, {ok, Metrics}}]}; %% 获取主机的状态 -handle_event({call, From}, get_status, _, State = #state{channel_pid = ChannelPid, heartbeat_counter = HeartbeatCounter, metrics = Metrics, has_session = HasSession}) -> +handle_event({call, From}, get_status, _, State = #state{channel_pid = ChannelPid, heartbeat_counter = HeartbeatCounter, metrics = Metrics, has_session = HasSession, host_status = HostStatus}) -> HasChannel = (ChannelPid /= undefined), Reply = #{ <<"has_channel">> => HasChannel, <<"has_session">> => HasSession, + <<"host_status">> => HostStatus, <<"heartbeat_counter">> => HeartbeatCounter, <<"metrics">> => Metrics }, @@ -271,23 +272,21 @@ handle_event({call, From}, {activate, Auth}, _, State = #state{uuid = UUID}) -> {next_state, NStateName, State, [{reply, From, ok}]}; %% 绑定channel -handle_event({call, From}, {attach_channel, ChannelPid}, StateName, State = #state{uuid = UUID, channel_pid = OldChannelPid}) -> +handle_event({call, From}, {attach_channel, ChannelPid}, StateName, State = #state{uuid = UUID, channel_pid = OldChannelPid, host_status = HostStatus}) -> case OldChannelPid == undefined orelse OldChannelPid =:= ChannelPid of true -> case StateName of ?STATE_ACTIVATED -> erlang:monitor(process, ChannelPid), %% 更新主机为在线状态 - ChangeResult = iot_api_client:change_host_status(UUID, ?HOST_ONLINE), - logger:debug("[iot_host] host_id(attach_channel) uuid: ~p, will change status, result: ~p", [UUID, ChangeResult]), - {keep_state, State#state{channel_pid = ChannelPid, has_session = true}, [{reply, From, ok}]}; + NState = mark_host_online(UUID, HostStatus, State#state{channel_pid = ChannelPid, has_session = true}), + {keep_state, NState, [{reply, From, ok}]}; %% 主机未激活 ?STATE_DENIED -> logger:notice("[iot_host] attach_channel host_id uuid: ~p, channel: ~p, host denied locally", [UUID, ChannelPid]), erlang:monitor(process, ChannelPid), - ChangeResult = iot_api_client:change_host_status(UUID, ?HOST_ONLINE), - logger:debug("[iot_host] host_id(attach_channel) uuid: ~p, denied but online, change status result: ~p", [UUID, ChangeResult]), - {keep_state, State#state{channel_pid = ChannelPid, has_session = true}, [{reply, From, ok}]} + NState = mark_host_online(UUID, HostStatus, State#state{channel_pid = ChannelPid, has_session = true}), + {keep_state, NState, [{reply, From, ok}]} end; false -> logger:notice("[iot_host] attach_channel host_id uuid: ~p, old channel exists: ~p", [UUID, OldChannelPid]), @@ -313,12 +312,8 @@ handle_event(cast, {handle, {ping, Metrics}}, ?STATE_ACTIVATED, State = #state{u %% 心跳机制 handle_event(cast, heartbeat, _, State = #state{uuid = UUID, heartbeat_counter = HeartbeatCounter, host_status = HostStatus}) -> - case maybe_mark_host_online(UUID, HostStatus) of - keep_status -> - {keep_state, State#state{heartbeat_counter = HeartbeatCounter + 1}}; - {next_status, NStatus} -> - {keep_state, State#state{heartbeat_counter = HeartbeatCounter + 1, host_status = NStatus}} - end; + NState = mark_host_online(UUID, HostStatus, State#state{heartbeat_counter = HeartbeatCounter + 1}), + {keep_state, NState}; %% UDP 心跳丢失但 SSL channel 仍在时,不能把 host 标记为离线。 handle_event(info, {timeout, _, heartbeat_ticker}, _, @@ -326,24 +321,15 @@ handle_event(info, {timeout, _, heartbeat_ticker}, _, erlang:start_timer(?HEARTBEAT_INTERVAL, self(), heartbeat_ticker), logger:warning("[iot_host] uuid: ~p, udp heartbeat lost but ssl channel is alive: ~p", [UUID, ChannelPid]), - case maybe_mark_host_online(UUID, HostStatus) of - keep_status -> - {keep_state, State#state{heartbeat_counter = 0}}; - {next_status, NStatus} -> - {keep_state, State#state{heartbeat_counter = 0, host_status = NStatus}} - end; + NState = mark_host_online(UUID, HostStatus, State#state{heartbeat_counter = 0}), + {keep_state, NState}; %% 没有收到 UDP 心跳且没有 SSL channel,主机下线, 设备状态不变 handle_event(info, {timeout, _, heartbeat_ticker}, _, State = #state{uuid = UUID, heartbeat_counter = 0, host_status = HostStatus}) -> logger:warning("[iot_host] uuid: ~p, heartbeat lost, devices will unknown", [UUID]), erlang:start_timer(?HEARTBEAT_INTERVAL, self(), heartbeat_ticker), - case maybe_mark_host_offline(UUID, HostStatus) of - keep_status -> - {keep_state, State#state{channel_pid = undefined, has_session = false, heartbeat_counter = 0}}; - {next_status, NStatus} -> - {keep_state, State#state{channel_pid = undefined, host_status = NStatus, has_session = false, heartbeat_counter = 0}}; - - end; + NState = mark_host_offline(UUID, HostStatus, State#state{channel_pid = undefined, has_session = false, heartbeat_counter = 0}), + {keep_state, NState}; %% 其他情况下需要重置系统计数器 handle_event(info, {timeout, _, heartbeat_ticker}, _, State = #state{}) -> @@ -393,10 +379,11 @@ get_route_key(RouteKey) when is_binary(RouteKey) -> RouteKey. %% 将当前的state转换成map -state_map(#state{host_id = HostId, uuid = UUID, has_session = HasSession, heartbeat_counter = HeartbeatCounter, channel_pid = ChannelPid, metrics = Metrics}) -> +state_map(#state{host_id = HostId, uuid = UUID, host_status = HostStatus, has_session = HasSession, heartbeat_counter = HeartbeatCounter, channel_pid = ChannelPid, metrics = Metrics}) -> #{ host_id => HostId, uuid => UUID, + host_status => HostStatus, has_session => HasSession, heartbeat_counter => HeartbeatCounter, channel_pid => ChannelPid, @@ -415,12 +402,36 @@ flush_reply(Ref) -> request_ref() -> crypto:strong_rand_bytes(16). +-spec mark_host_online(binary(), integer(), #state{}) -> #state{}. +mark_host_online(UUID, HostStatus, State) -> + case maybe_mark_host_online(UUID, HostStatus) of + keep_status -> + State; + {next_status, NStatus} -> + State#state{host_status = NStatus} + end. + +-spec mark_host_offline(binary(), integer(), #state{}) -> #state{}. +mark_host_offline(UUID, HostStatus, State) -> + case maybe_mark_host_offline(UUID, HostStatus) of + keep_status -> + State; + {next_status, NStatus} -> + State#state{host_status = NStatus} + end. + -spec maybe_mark_host_online(binary(), integer()) -> {next_status, NStatus :: integer()} | keep_status. maybe_mark_host_online(UUID, HostStatus) -> case HostStatus of ?HOST_OFFLINE -> - _ = iot_api_client:change_host_status(UUID, ?HOST_ONLINE), - {next_status, ?HOST_ONLINE}; + case iot_api_client:change_host_status(UUID, ?HOST_ONLINE) of + {ok, Result} -> + logger:debug("[iot_host] uuid: ~p, change host status online success: ~p", [UUID, Result]), + {next_status, ?HOST_ONLINE}; + {error, Reason} -> + logger:warning("[iot_host] uuid: ~p, change host status online failed: ~p", [UUID, Reason]), + keep_status + end; _ -> keep_status end. @@ -429,8 +440,14 @@ maybe_mark_host_online(UUID, HostStatus) -> maybe_mark_host_offline(UUID, HostStatus) -> case HostStatus of ?HOST_ONLINE -> - _ = iot_api_client:change_host_status(UUID, ?HOST_OFFLINE), - {next_status, ?HOST_OFFLINE}; + case iot_api_client:change_host_status(UUID, ?HOST_OFFLINE) of + {ok, Result} -> + logger:debug("[iot_host] uuid: ~p, change host status offline success: ~p", [UUID, Result]), + {next_status, ?HOST_OFFLINE}; + {error, Reason} -> + logger:warning("[iot_host] uuid: ~p, change host status offline failed: ~p", [UUID, Reason]), + keep_status + end; _ -> keep_status - end. \ No newline at end of file + end.