Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -module(ip_fetcher_app).
- -behaviour(application).
- -export([start/2, stop/1]).
- start(_StartType, _StartArgs) ->
- ip_fetcher_sup:start_link().
- stop(_State) ->
- ok.
- %% ===================================================================
- %% Supervisor
- %% ===================================================================
- -module(ip_fetcher_sup).
- -behaviour(supervisor).
- -export([start_link/0, init/1]).
- start_link() ->
- supervisor:start_link({local, ?MODULE}, ?MODULE, []).
- init([]) ->
- SupFlags = #{
- strategy => one_for_one,
- intensity => 3, % max restarts
- period => 5 % seconds
- },
- ChildSpec = #{
- id => ip_fetcher,
- start => {ip_fetcher_worker, start_link, []},
- restart => transient, % only restart on abnormal exit
- shutdown => 5000, % 5 seconds graceful shutdown
- type => worker,
- modules => [ip_fetcher_worker]
- },
- {ok, {SupFlags, [ChildSpec]}}.
- %% ===================================================================
- %% Worker
- %% ===================================================================
- -module(ip_fetcher_worker).
- -behaviour(gen_server).
- -export([start_link/0]).
- -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
- start_link() ->
- gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
- init([]) ->
- % Start the work immediately
- self() ! fetch_ip,
- {ok, #{}}.
- handle_call(_Request, _From, State) ->
- {reply, ok, State}.
- handle_cast(_Msg, State) ->
- {noreply, State}.
- handle_info(fetch_ip, State) ->
- case do_fetch_ip() of
- {ok, Ip} ->
- io:format("~s~n", [Ip]),
- % Normal exit — transient worker will NOT be restarted
- {stop, normal, State};
- {error, Reason} ->
- io:format("Failed to connect – will be restarted by supervisor: ~p~n", [Reason]),
- % Abnormal exit — supervisor WILL restart us (up to 3 times in 5s)
- {stop, {connect_failed, Reason}, State}
- end;
- handle_info(_Info, State) ->
- {noreply, State}.
- terminate(_Reason, _State) ->
- ok.
- code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
- %% Internal function to fetch IP
- do_fetch_ip() ->
- Host = "icanhazip.com",
- Port = 80,
- Timeout = 10000,
- case gen_tcp:connect(Host, Port, [binary, {active, false}], Timeout) of
- {ok, Socket} ->
- Request = "GET / HTTP/1.0\r\nHost: icanhazip.com\r\nConnection: close\r\n\r\n",
- ok = gen_tcp:send(Socket, Request),
- case recv_all(Socket, <<>>) of
- {ok, Data} ->
- % Extract just the IP (last line)
- Lines = binary:split(Data, <<"\n">>, [global, trim]),
- Ip = lists:last(Lines),
- gen_tcp:close(Socket),
- {ok, binary_to_list(Ip)};
- Error ->
- gen_tcp:close(Socket),
- Error
- end;
- Error ->
- Error
- end.
- recv_all(Socket, Acc) ->
- case gen_tcp:recv(Socket, 0, 10000) of
- {ok, Data} ->
- recv_all(Socket, <<Acc/binary, Data/binary>>);
- {error, closed} ->
- {ok, Acc};
- {error, _} = Err ->
- Err
- end.
Advertisement