159 lines
5.4 KiB
Erlang
159 lines
5.4 KiB
Erlang
-module(gmhc_eureka).
|
|
-vsn("0.4.8").
|
|
|
|
-export([get_pool_address/0]).
|
|
|
|
-include_lib("kernel/include/logger.hrl").
|
|
-include("gmhc_events.hrl").
|
|
|
|
get_pool_address() ->
|
|
case gmconfig:find_config([<<"pool_admin">>, <<"url">>], [user_config]) of
|
|
{ok, URL0} ->
|
|
case expand_url(URL0) of
|
|
<<"local">> ->
|
|
#{<<"address">> => <<"127.0.0.1">>,
|
|
<<"port">> => gmconfig:get_config(
|
|
[<<"pool">>, <<"port">>], [schema_default]),
|
|
<<"pool_id">> => gmhc_config:get_config([<<"pool">>, <<"id">>]) };
|
|
URL ->
|
|
?LOG_INFO("Trying to connect to ~p", [URL]),
|
|
connect1(URL)
|
|
end;
|
|
undefined ->
|
|
Network = gmconfig:get_config([<<"network">>]),
|
|
URL0 = gmconfig:get_config([ <<"pool_admin">>
|
|
, <<"default_per_network">>
|
|
, Network ],
|
|
[schema_default]),
|
|
URL = expand_url(URL0),
|
|
?LOG_INFO("Using default for ~p: ~p", [Network, URL]),
|
|
connect1(URL)
|
|
end.
|
|
|
|
connect1(URL0) ->
|
|
URL = binary_to_list(URL0),
|
|
Res = request(get, URL),
|
|
?LOG_DEBUG("Res = ~p", [Res]),
|
|
case Res of
|
|
{ok, Body} ->
|
|
try get_host_port(json:decode(iolist_to_binary(Body)))
|
|
catch
|
|
error:_ ->
|
|
gmhc_events:publish(error, ?ERR_EVT(#{error => invalid_json,
|
|
data => Body})),
|
|
{error, invalid_json}
|
|
end;
|
|
{error, _} = Error ->
|
|
gmhc_events:publish(error, ?ERR_EVT(#{error => connect_failure,
|
|
data => Error})),
|
|
Error
|
|
end.
|
|
|
|
get_host_port(Data) ->
|
|
?LOG_DEBUG("Data = ~p", [Data]),
|
|
maps:with([<<"address">>, <<"port">>, <<"pool_id">>], Data).
|
|
|
|
request(get, URL) ->
|
|
case request(get, URL, []) of
|
|
{ok, #{body := Body}} ->
|
|
{ok, Body};
|
|
Other ->
|
|
%% TODO: perhaps return a more informative reason?
|
|
gmhc_events:publish(error, ?ERR_EVT(#{error => get_failed,
|
|
url => URL,
|
|
data => Other })),
|
|
{error, failed}
|
|
end.
|
|
|
|
request(get, URL, []) ->
|
|
Headers = [],
|
|
HttpOpts = [{timeout, 15000}],
|
|
Opts = [],
|
|
Profile = default,
|
|
request_result(httpc:request(get, {URL, Headers}, HttpOpts, Opts, Profile)).
|
|
%% request(post, URL, Body) ->
|
|
%% post_request(URL, Body).
|
|
|
|
expand_url(URL) ->
|
|
case re:run(URL, <<"{[^}]+}">>, []) of
|
|
{match, _} ->
|
|
expand_vars(URL);
|
|
nomatch ->
|
|
URL
|
|
end.
|
|
|
|
expand_vars(S) ->
|
|
expand_vars(S, <<>>).
|
|
|
|
expand_vars(<<"{", Rest/binary>>, Acc) ->
|
|
{Var, Rest1} = get_var_name(Rest),
|
|
expand_vars(Rest1, <<Acc/binary, (expand_var(Var))/binary>>);
|
|
expand_vars(<<H, T/binary>>, Acc) ->
|
|
expand_vars(T, <<Acc/binary, H>>);
|
|
expand_vars(<<>>, Acc) ->
|
|
Acc.
|
|
|
|
expand_var(<<"CLIENT_ID">>) ->
|
|
gmhc_config:get_config([<<"pubkey">>]).
|
|
|
|
get_var_name(S) ->
|
|
get_var_name(S, <<>>).
|
|
|
|
get_var_name(<<"}", Rest/binary>>, Acc) ->
|
|
{Acc, Rest};
|
|
get_var_name(<<H, T/binary>>, Acc) ->
|
|
get_var_name(T, <<Acc/binary, H>>).
|
|
|
|
%% From hz.erl ==========================================================
|
|
|
|
% This is Bitcoin's variable-length unsigned integer encoding
|
|
% See: https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
|
|
%% vencode(N) when N =< 0 ->
|
|
%% {error, {non_pos_N, N}};
|
|
%% vencode(N) when N < 16#FD ->
|
|
%% {ok, <<N>>};
|
|
%% vencode(N) when N =< 16#FFFF ->
|
|
%% NBytes = eu(N, 2),
|
|
%% {ok, <<16#FD, NBytes/binary>>};
|
|
%% vencode(N) when N =< 16#FFFF_FFFF ->
|
|
%% NBytes = eu(N, 4),
|
|
%% {ok, <<16#FE, NBytes/binary>>};
|
|
%% vencode(N) when N < (2 bsl 64) ->
|
|
%% NBytes = eu(N, 8),
|
|
%% {ok, <<16#FF, NBytes/binary>>}.
|
|
|
|
|
|
% eu = encode unsigned (little endian with a given byte width)
|
|
% means add zero bytes to the end as needed
|
|
%% eu(N, Size) ->
|
|
%% Bytes = binary:encode_unsigned(N, little),
|
|
%% NExtraZeros = Size - byte_size(Bytes),
|
|
%% ExtraZeros = << <<0>> || _ <- lists:seq(1, NExtraZeros) >>,
|
|
%% <<Bytes/binary, ExtraZeros/binary>>.
|
|
|
|
%% ======================================================================
|
|
|
|
%% From gmplugin_web_demo_handler.erl ===================================
|
|
|
|
%% post_request(URL, Map) ->
|
|
%% ?LOG_DEBUG("Map = ~p", [Map]),
|
|
%% Body = json:encode(Map),
|
|
%% ?LOG_DEBUG("Body = ~s", [Body]),
|
|
%% PostRes = httpc:request(post, {URL, [], "application/json", Body}, [], []),
|
|
%% request_result(PostRes).
|
|
|
|
%% ======================================================================
|
|
|
|
request_result(Result) ->
|
|
?LOG_DEBUG("Request result: ~p", [Result]),
|
|
request_result_(Result).
|
|
|
|
request_result_({ok, {{_, C200, Ok}, _Hdrs, Body}}) when C200 >= 200, C200 < 300 ->
|
|
{ok, #{code => C200, msg => Ok, body => Body}};
|
|
request_result_({ok, {{_, C200, Ok}, Body}}) when C200 >= 200, C200 < 300 ->
|
|
{ok, #{code => C200, msg => Ok, body => Body}};
|
|
request_result_({ok, {{_, Code, Error}, _Hdrs, Body}}) ->
|
|
{error, #{code => Code, msg => Error, body => Body}};
|
|
request_result_(_) ->
|
|
{error, #{code => 500, msg => <<"Internal error">>, body => <<>>}}.
|