-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, <>); expand_vars(<>, Acc) -> expand_vars(T, <>); 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(<>, Acc) -> get_var_name(T, <>). %% 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, <>}; %% 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) >>, %% <>. %% ====================================================================== %% 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 => <<>>}}.