diff --git a/apps/iot/src/iot_host.erl b/apps/iot/src/iot_host.erl index 2db924d..fc942a6 100644 --- a/apps/iot/src/iot_host.erl +++ b/apps/iot/src/iot_host.erl @@ -405,6 +405,10 @@ handle_event(cast, {handle, {ping, CipherMetric}}, ?STATE_ACTIVATED, State = #st case catch jiffy:decode(MetricsInfo, [return_maps]) of Metrics when is_map(Metrics) -> lager:debug("[iot_host] host_id uuid: ~p, get ping: ~p", [UUID, Metrics]), + %% 建立主机uuid和ip之间的对应关系 + Ips = maps:get(<<"ips">>, Metrics, []), + is_list(Ips) andalso iot_host_mapper:mapper(UUID, Ips), + %% 检测消息是否需要报警 iot_watchdog:detection(UUID, Name, Metrics), {keep_state, State#state{metrics = Metrics}}; diff --git a/apps/iot/src/iot_host_mapper.erl b/apps/iot/src/iot_host_mapper.erl new file mode 100644 index 0000000..f315436 --- /dev/null +++ b/apps/iot/src/iot_host_mapper.erl @@ -0,0 +1,120 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2025, +%%% @doc +%%% +%%% @end +%%% Created : 19. 2月 2025 11:20 +%%%------------------------------------------------------------------- +-module(iot_host_mapper). +-author("anlicheng"). + +-behaviour(gen_server). + +%% API +-export([start_link/0, mapper/2]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3]). + +-define(SERVER, ?MODULE). + +-record(state, { + mapper = #{} +}). + +%%%=================================================================== +%%% API +%%%=================================================================== + +-spec mapper(HostUUID :: binary(), Ips :: list()) -> no_return(). +mapper(HostUUID, Ips) when is_binary(HostUUID), is_list(Ips) -> + gen_server:cast(?SERVER, {ips, HostUUID, Ips}). + +%% @doc Spawns the server and registers the local name (unique) +-spec(start_link() -> + {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). +start_link() -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +%% @private +%% @doc Initializes the server +-spec(init(Args :: term()) -> + {ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} | + {stop, Reason :: term()} | ignore). +init([]) -> + {ok, #state{}}. + +%% @private +%% @doc Handling call messages +-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()}, + State :: #state{}) -> + {reply, Reply :: term(), NewState :: #state{}} | + {reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} | + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), Reply :: term(), NewState :: #state{}} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_call(_Request, _From, State = #state{}) -> + {reply, ok, State}. + +%% @private +%% @doc Handling cast messages +-spec(handle_cast(Request :: term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_cast({ips, HostUUID, Ips}, State = #state{mapper = Mapper}) -> + %% 有变化则重新写入到文件 + NMapper = maps:put(HostUUID, Ips, Mapper), + case Mapper =:= NMapper of + true -> + {noreply, State}; + false -> + %% 写入到文件 + Items = maps:to_list(NMapper), + Lines = lists:map(fun({HostUUID0, Ips0}) -> iolist_to_binary([HostUUID0, Ips0]) end, Items), + Content = iolist_to_binary(lists:join(<<"\n">>, Lines)), + Filename = code:root_dir() ++ "/log/host_mapper.txt", + ok = file:write_file(Filename, Content, [write]), + + {noreply, State#state{mapper = NMapper}} + end; +handle_cast(_Request, State = #state{}) -> + {noreply, State}. + +%% @private +%% @doc Handling all non call/cast messages +-spec(handle_info(Info :: timeout() | term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_info(_Info, State = #state{}) -> + {noreply, State}. + +%% @private +%% @doc This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any +%% necessary cleaning up. When it returns, the gen_server terminates +%% with Reason. The return value is ignored. +-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()), + State :: #state{}) -> term()). +terminate(_Reason, _State = #state{}) -> + ok. + +%% @private +%% @doc Convert process state when code is changed +-spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{}, + Extra :: term()) -> + {ok, NewState :: #state{}} | {error, Reason :: term()}). +code_change(_OldVsn, State = #state{}, _Extra) -> + {ok, State}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== diff --git a/apps/iot/src/iot_sup.erl b/apps/iot/src/iot_sup.erl index 87e00a9..8d7ab89 100644 --- a/apps/iot/src/iot_sup.erl +++ b/apps/iot/src/iot_sup.erl @@ -82,6 +82,15 @@ init([]) -> modules => ['iot_device_sup'] }, + #{ + id => 'iot_host_mapper', + start => {'iot_host_mapper', start_link, []}, + restart => permanent, + shutdown => 2000, + type => worker, + modules => ['iot_host_mapper'] + }, + #{ id => 'iot_host_sup', start => {'iot_host_sup', start_link, []},