diff --git a/apps/iot/src/iot_app.erl b/apps/iot/src/iot_app.erl index c771355..c6f2e4b 100644 --- a/apps/iot/src/iot_app.erl +++ b/apps/iot/src/iot_app.erl @@ -16,6 +16,7 @@ start(_StartType, _StartArgs) -> mnesia:start(), Tables = mnesia:system_info(tables), iot_util:assert_exec(lists:member(router, [Tables]), fun() -> mnesia:wait_for_tables([router], infinity) end), + iot_util:assert_exec(lists:member(host, [Tables]), fun() -> mnesia:wait_for_tables([host], infinity) end), %% 加速内存的回收 erlang:system_flag(fullsweep_after, 16), diff --git a/apps/iot/src/iot_host.erl b/apps/iot/src/iot_host.erl new file mode 100644 index 0000000..d03f63b --- /dev/null +++ b/apps/iot/src/iot_host.erl @@ -0,0 +1,104 @@ +%%%------------------------------------------------------------------- +%%% @author aresei +%%% @copyright (C) 2023, +%%% @doc +%%% +%%% @end +%%% Created : 12. 3月 2023 21:27 +%%%------------------------------------------------------------------- +-module(iot_host). +-author("aresei"). +-include("iot.hrl"). + +-behaviour(gen_server). + +%% API +-export([start_link/2, get_name/1]). + +%% 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, { + host :: #host{} +}). + +%%%=================================================================== +%%% API +%%%=================================================================== + +get_name(HostId) when is_binary(HostId) -> + binary_to_atom(<<"iot_host:", HostId/binary>>). + +%% @doc Spawns the server and registers the local name (unique) +-spec(start_link(Name :: atom(), Host :: #host{}) -> + {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). +start_link(Name, Host = #host{}) -> + gen_server:start_link({local, Name}, ?MODULE, [Host], []). + +%%%=================================================================== +%%% 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([Host]) -> + lager:debug("[iot_host] host is: ~p", [Host]), + {ok, #state{host = Host}}. + +%% @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(_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_host_sup.erl b/apps/iot/src/iot_host_sup.erl new file mode 100644 index 0000000..8b0f028 --- /dev/null +++ b/apps/iot/src/iot_host_sup.erl @@ -0,0 +1,33 @@ +%%%------------------------------------------------------------------- +%%% @author aresei +%%% @copyright (C) 2023, +%%% @doc +%%% @end +%%%------------------------------------------------------------------- +-module(iot_host_sup). +-include("iot.hrl"). + +-behaviour(supervisor). + +-export([start_link/0, init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Specs = case host_model:get_all_hosts() of + {ok, Hosts} -> + lists:map(fun(Host = #host{host_id = HostId}) -> + Id = iot_host:get_name(HostId), + #{id => Id, + start => {iot_host, start_link, [Id, Host]}, + restart => permanent, + shutdown => 2000, + type => worker, + modules => ['iot_host']} + end, Hosts); + {error, _} -> + [] + end, + + {ok, {#{strategy => one_for_one, intensity => 1000, period => 3600}, Specs}}. \ No newline at end of file diff --git a/apps/iot/src/iot_sup.erl b/apps/iot/src/iot_sup.erl index 3cb80b4..87d955e 100644 --- a/apps/iot/src/iot_sup.erl +++ b/apps/iot/src/iot_sup.erl @@ -28,6 +28,15 @@ start_link() -> init([]) -> SupFlags = #{strategy => one_for_one, intensity => 1000, period => 3600}, ChildSpecs = [ + #{ + id => 'iot_host_sup', + start => {'iot_host_sup', start_link, []}, + restart => permanent, + shutdown => 2000, + type => supervisor, + modules => ['iot_host_sup'] + }, + #{ id => 'iot_router_sup', start => {'iot_router_sup', start_link, []}, diff --git a/apps/iot/src/model/host_model.erl b/apps/iot/src/model/host_model.erl index 284e281..9068abd 100644 --- a/apps/iot/src/model/host_model.erl +++ b/apps/iot/src/model/host_model.erl @@ -12,7 +12,7 @@ -include_lib("stdlib/include/qlc.hrl"). %% API --export([get_host/1, get_hosts/3, get_stat/0, add_host/1, change_status/2, delete/1, table_size/0, find_hosts/3, activate/1]). +-export([get_host/1, get_hosts/3, get_all_hosts/0, get_stat/0, add_host/1, change_status/2, delete/1, table_size/0, find_hosts/3, activate/1]). -export([to_map/1]). get_host(HostId) when is_binary(HostId) -> @@ -23,6 +23,18 @@ get_host(HostId) when is_binary(HostId) -> undefined end. +get_all_hosts() -> + Fun = fun() -> + Q = qlc:q([E || E <- mnesia:table(host), E#host.status == 1]), + qlc:e(Q) + end, + case mnesia:transaction(Fun) of + {atomic, Items} when is_list(Items) -> + {ok, Items}; + {aborted, Error} -> + {error, Error} + end. + %% 获取app信息 -spec get_hosts(Filter :: any(), Start :: integer(), Limit :: integer()) -> {ok, Items :: list(), TotalNum :: integer()} | diff --git a/rebar.lock b/rebar.lock index fc8b7b9..e5a63a0 100644 --- a/rebar.lock +++ b/rebar.lock @@ -49,7 +49,7 @@ {<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.6">>},1}, {<<"sync">>, {git,"https://github.com/rustyio/sync.git", - {ref,"aa27b66ccfbfc798b57288af4cf7dc386e205d68"}}, + {ref,"3f0049e809ffe303ae2cd395217a025ce6e758ae"}}, 0}, {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.5.0">>},2}]}. [