grrkek

Untitled

Jan 5th, 2026
1,128
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.36 KB | None | 0 0
  1. -module(ip_fetcher_app).
  2. -behaviour(application).
  3.  
  4. -export([start/2, stop/1]).
  5.  
  6. start(_StartType, _StartArgs) ->
  7. ip_fetcher_sup:start_link().
  8.  
  9. stop(_State) ->
  10. ok.
  11.  
  12. %% ===================================================================
  13. %% Supervisor
  14. %% ===================================================================
  15.  
  16. -module(ip_fetcher_sup).
  17. -behaviour(supervisor).
  18.  
  19. -export([start_link/0, init/1]).
  20.  
  21. start_link() ->
  22. supervisor:start_link({local, ?MODULE}, ?MODULE, []).
  23.  
  24. init([]) ->
  25. SupFlags = #{
  26. strategy => one_for_one,
  27. intensity => 3, % max restarts
  28. period => 5 % seconds
  29. },
  30.  
  31. ChildSpec = #{
  32. id => ip_fetcher,
  33. start => {ip_fetcher_worker, start_link, []},
  34. restart => transient, % only restart on abnormal exit
  35. shutdown => 5000, % 5 seconds graceful shutdown
  36. type => worker,
  37. modules => [ip_fetcher_worker]
  38. },
  39.  
  40. {ok, {SupFlags, [ChildSpec]}}.
  41.  
  42. %% ===================================================================
  43. %% Worker
  44. %% ===================================================================
  45.  
  46. -module(ip_fetcher_worker).
  47. -behaviour(gen_server).
  48.  
  49. -export([start_link/0]).
  50. -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
  51.  
  52. start_link() ->
  53. gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
  54.  
  55. init([]) ->
  56. % Start the work immediately
  57. self() ! fetch_ip,
  58. {ok, #{}}.
  59.  
  60. handle_call(_Request, _From, State) ->
  61. {reply, ok, State}.
  62.  
  63. handle_cast(_Msg, State) ->
  64. {noreply, State}.
  65.  
  66. handle_info(fetch_ip, State) ->
  67. case do_fetch_ip() of
  68. {ok, Ip} ->
  69. io:format("~s~n", [Ip]),
  70. % Normal exit — transient worker will NOT be restarted
  71. {stop, normal, State};
  72. {error, Reason} ->
  73. io:format("Failed to connect – will be restarted by supervisor: ~p~n", [Reason]),
  74. % Abnormal exit — supervisor WILL restart us (up to 3 times in 5s)
  75. {stop, {connect_failed, Reason}, State}
  76. end;
  77.  
  78. handle_info(_Info, State) ->
  79. {noreply, State}.
  80.  
  81. terminate(_Reason, _State) ->
  82. ok.
  83.  
  84. code_change(_OldVsn, State, _Extra) ->
  85. {ok, State}.
  86.  
  87. %% Internal function to fetch IP
  88. do_fetch_ip() ->
  89. Host = "icanhazip.com",
  90. Port = 80,
  91. Timeout = 10000,
  92.  
  93. case gen_tcp:connect(Host, Port, [binary, {active, false}], Timeout) of
  94. {ok, Socket} ->
  95. Request = "GET / HTTP/1.0\r\nHost: icanhazip.com\r\nConnection: close\r\n\r\n",
  96. ok = gen_tcp:send(Socket, Request),
  97.  
  98. case recv_all(Socket, <<>>) of
  99. {ok, Data} ->
  100. % Extract just the IP (last line)
  101. Lines = binary:split(Data, <<"\n">>, [global, trim]),
  102. Ip = lists:last(Lines),
  103. gen_tcp:close(Socket),
  104. {ok, binary_to_list(Ip)};
  105. Error ->
  106. gen_tcp:close(Socket),
  107. Error
  108. end;
  109. Error ->
  110. Error
  111. end.
  112.  
  113. recv_all(Socket, Acc) ->
  114. case gen_tcp:recv(Socket, 0, 10000) of
  115. {ok, Data} ->
  116. recv_all(Socket, <<Acc/binary, Data/binary>>);
  117. {error, closed} ->
  118. {ok, Acc};
  119. {error, _} = Err ->
  120. Err
  121. end.
Advertisement