From 968f9d92f216f6790368e337fe72299d71c22bae Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Wed, 8 Oct 2025 15:39:48 +0200 Subject: [PATCH 1/6] Update README.md with latest json schema (automated) --- Makefile | 10 +++++++ README.md | 12 ++++++++- ebin/gmhive_client.app | 2 +- rebar.config | 2 ++ scripts/update_readme_json.sh | 51 +++++++++++++++++++++++++++++++++++ src/gmhc_config_schema.erl | 14 +++++++++- zomp.meta | 4 +-- zompify.sh | 7 +++++ 8 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 Makefile create mode 100755 scripts/update_readme_json.sh diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f7f9a5e --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ + +BUILD="_build/default/lib/gmhive_client" +SCHEMA_OUT=$(BUILD)/priv/gmhc_schema.json + +schema: + ERL_LIBS=_build/default/lib \ + erl -run gmhc_config_schema export $(SCHEMA_OUT) -run init stop + scripts/update_readme_json.sh README.md $(SCHEMA_OUT) + + diff --git a/README.md b/README.md index 49e6202..7df0c93 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,16 @@ server. (For `"testnet"` this will be `"test.gajumining.com"`.) "pattern": "^ak_[1-9A-HJ-NP-Za-km-z]*$", "type": "string" }, + "report": { + "default": "silent", + "description": "Progress reporting", + "enum": [ + "debug", + "progress", + "silent" + ], + "type": "string" + }, "type": { "default": "worker", "description": "monitor mode can be used to see if a pool is alive", @@ -174,7 +184,7 @@ server. (For `"testnet"` this will be `"test.gajumining.com"`.) "properties": { "executable": { "default": "mean29-generic", - "description": "Executable binary of the worker. Can be a fully qualified path, but the software may apply default logic to locate a plain basename.", + "description": "Executable binary of the worker. Can be a fully qualified path, \nbut the software may apply default logic to locate a plain basename.", "type": "string" }, "extra_args": { diff --git a/ebin/gmhive_client.app b/ebin/gmhive_client.app index 7b8902a..ffa31b4 100644 --- a/ebin/gmhive_client.app +++ b/ebin/gmhive_client.app @@ -1,6 +1,6 @@ {application,gmhive_client, [{description,"Gajumaru Hive Client"}, - {vsn,"0.6.2"}, + {vsn,"0.6.3"}, {registered,[]}, {applications,[kernel,stdlib,sasl,gproc,inets,ssl,enoise, gmconfig,gmhive_protocol,gmhive_worker]}, diff --git a/rebar.config b/rebar.config index 35abaf3..cbfeeeb 100644 --- a/rebar.config +++ b/rebar.config @@ -5,6 +5,8 @@ {erl_opts, [debug_info]}. {plugins, [rebar3_hex]}. +{post_hooks, [{compile, "make schema"}]}. + {deps, [ {enoise, {git, "https://git.qpq.swiss/QPQ-AG/enoise.git", {ref, "029292817e"}}}, {gmhive_protocol, diff --git a/scripts/update_readme_json.sh b/scripts/update_readme_json.sh new file mode 100755 index 0000000..f015c95 --- /dev/null +++ b/scripts/update_readme_json.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -euo pipefail + +README="$1" +SCHEMA="$2" + +if [[ ! -f "$README" || ! -f "$SCHEMA" ]]; then + echo "Usage: $0 README.md schema.json" + exit 1 +fi + +tmpfile=$(mktemp) + +awk -v schema_file="$SCHEMA" ' + BEGIN { + in_json_block = 0 + in_schema_section = 0 + } + + /^##[[:space:]]+JSON[[:space:]]+Schema/ { + in_schema_section = 1 + print + next + } + + /^##[[:space:]]+/ && in_schema_section { + # Another section starts, end the schema section + in_schema_section = 0 + } + + in_schema_section && /^```json/ { + print "```json" + while ((getline line < schema_file) > 0) print line + close(schema_file) + in_json_block = 1 + next + } + + in_json_block && /^```$/ { + print "```" + in_json_block = 0 + next + } + + !(in_schema_section && in_json_block) { + print + } +' "$README" > "$tmpfile" + +mv "$tmpfile" "$README" +echo "✅ Updated JSON schema block in $README" diff --git a/src/gmhc_config_schema.erl b/src/gmhc_config_schema.erl index f4d8883..7276efa 100644 --- a/src/gmhc_config_schema.erl +++ b/src/gmhc_config_schema.erl @@ -2,7 +2,8 @@ -vsn("0.6.1"). -export([ schema/0 - , to_json/0 ]). + , to_json/0 + , export/1 ]). -import(gmconfig_schema_helpers, [ str/1 @@ -22,6 +23,17 @@ to_json() -> json:encode(schema()). +export(ToFile) -> + case file:open(ToFile, [write]) of + {ok, Fd} -> + try ok = io:put_chars(Fd, json:format(schema(), #{indent => 4})) + after + file:close(Fd) + end; + {error, _} = Error -> + Error + end. + schema() -> obj(schema_init(), #{ diff --git a/zomp.meta b/zomp.meta index 0aa1e39..e467016 100644 --- a/zomp.meta +++ b/zomp.meta @@ -1,10 +1,10 @@ {name,"gmhive_client"}. {type,app}. {modules,[]}. -{author,"Ulf Wiger, QPQ AG"}. {prefix,"gmhc"}. {desc,"Gajumaru Hive Client"}. -{package_id,{"uwiger","gmhive_client",{0,6,2}}}. +{author,"Ulf Wiger, QPQ AG"}. +{package_id,{"uwiger","gmhive_client",{0,6,3}}}. {deps,[{"uwiger","gmhive_worker",{0,5,1}}, {"uwiger","gmcuckoo",{1,2,4}}, {"otpr","eblake2",{1,0,1}}, diff --git a/zompify.sh b/zompify.sh index 66aca1c..8ce3a4e 100755 --- a/zompify.sh +++ b/zompify.sh @@ -38,5 +38,12 @@ rm "$IGNORE_TEMP" cp "$PWD/zomp.meta" "$DST/" cp "$PWD/Emakefile" "$DST/" +# copy generated schema +SCHEMA="$SRC/priv/gmhc_schema.json" +if [ -e "$SCHEMA" ]; then + mkdir -p "$DST/priv" + cp -a "$SCHEMA" "$DST/priv/$(basename "$SCHEMA")" +fi + # Clean up beam files just in case [ -d "$DST/ebin" ] && find "$DST/ebin" -name '*.beam' -exec rm -f {} + || true -- 2.30.2 From 5eff27367d5277a46c517fab0e73faf0673d82fd Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Thu, 9 Oct 2025 20:17:27 +0200 Subject: [PATCH 2/6] Cache connection info --- .gitignore | 2 +- Makefile | 4 +- ebin/gmhive_client.app | 2 +- gmhc_config-testnet-local.eterm | 1 + gmhc_config.eterm | 2 +- priv/gmhc_schema.json | 135 ++++++++++++++++++++++++++++++++ src/gmhc_connector.erl | 66 +++++++++++----- src/gmhc_eureka.erl | 85 ++++++++++++++++++-- src/gmhc_server.erl | 31 +++++--- zomp.meta | 4 +- 10 files changed, 289 insertions(+), 43 deletions(-) create mode 100644 priv/gmhc_schema.json diff --git a/.gitignore b/.gitignore index 844107a..5fb29c9 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ VERSION *.aes~ *.config~ *.args~ -data/mnesia +data/* _checkouts*/ tmp/ rebar3.crashdump diff --git a/Makefile b/Makefile index f7f9a5e..0df1e96 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ -BUILD="_build/default/lib/gmhive_client" +BUILD=_build/default/lib/gmhive_client SCHEMA_OUT=$(BUILD)/priv/gmhc_schema.json schema: ERL_LIBS=_build/default/lib \ erl -run gmhc_config_schema export $(SCHEMA_OUT) -run init stop - scripts/update_readme_json.sh README.md $(SCHEMA_OUT) + scripts/update_readme_json.sh "README.md" "$(SCHEMA_OUT)" diff --git a/ebin/gmhive_client.app b/ebin/gmhive_client.app index ffa31b4..18ef1ab 100644 --- a/ebin/gmhive_client.app +++ b/ebin/gmhive_client.app @@ -1,6 +1,6 @@ {application,gmhive_client, [{description,"Gajumaru Hive Client"}, - {vsn,"0.6.3"}, + {vsn,"0.7.0"}, {registered,[]}, {applications,[kernel,stdlib,sasl,gproc,inets,ssl,enoise, gmconfig,gmhive_protocol,gmhive_worker]}, diff --git a/gmhc_config-testnet-local.eterm b/gmhc_config-testnet-local.eterm index 849f904..289d1f0 100644 --- a/gmhc_config-testnet-local.eterm +++ b/gmhc_config-testnet-local.eterm @@ -1,4 +1,5 @@ #{ pubkey => <<"ak_zjyvDmMbXafMADYrxDs4uMiYM5zEVJBqWgv619NUQ37Gkwt7z">> + , report => <<"progress">> , pool_admin => #{url => <<"local">>} , pool => #{id => <<"ct_26xqeE3YKmZV8jrks57JSgZRCHSuG4RGzpnvdz6AAiSSTVbJRM">>, host => <<"127.0.0.1">>} diff --git a/gmhc_config.eterm b/gmhc_config.eterm index aaff7ae..5c3ae7d 100644 --- a/gmhc_config.eterm +++ b/gmhc_config.eterm @@ -1,5 +1,5 @@ #{ pubkey => <<"ak_2KAcA2Pp1nrR8Wkt3FtCkReGzAi8vJ9Snxa4PcmrthVx8AhPe8">> , pool => #{id => <<"ct_LRbi65kmLtE7YMkG6mvG5TxAXTsPJDZjAtsPuaXtRyPA7gnfJ">>} - , mining => + , workers => [#{executable => <<"mean15-generic">>}] }. diff --git a/priv/gmhc_schema.json b/priv/gmhc_schema.json new file mode 100644 index 0000000..6c0371a --- /dev/null +++ b/priv/gmhc_schema.json @@ -0,0 +1,135 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "extra_pubkeys": { + "default": [], + "description": "Additional worker pubkeys, sharing rewards", + "items": { + "pattern": "^ak_[1-9A-HJ-NP-Za-km-z]*$", + "type": "string" + }, + "type": "array" + }, + "network": { + "default": "mainnet", + "type": "string" + }, + "pool": { + "additionalProperties": false, + "properties": { + "host": { + "default": "127.0.0.1", + "description": "Hostname of hive server", + "example": "0.0.0.0", + "type": "string" + }, + "id": { + "description": "Pool contract id", + "pattern": "^ct_[1-9A-HJ-NP-Za-km-z]*$", + "type": "string" + }, + "port": { + "default": 17888, + "description": "Hive server listen port", + "minimum": 1, + "type": "integer" + } + }, + "type": "object" + }, + "pool_admin": { + "additionalProperties": false, + "properties": { + "default_per_network": { + "additionalProperties": false, + "properties": { + "mainnet": { + "default": "https://gajumining.com/api/workers/{CLIENT_ID}", + "type": "string" + }, + "testnet": { + "default": "https://test.gajumining.com/api/workers/{CLIENT_ID}", + "type": "string" + } + }, + "type": "object" + }, + "url": { + "default": "https://test.gajumining.com/api/workers/{CLIENT_ID}", + "description": "URL of Eureka worker api", + "type": "string" + } + }, + "type": "object" + }, + "pubkey": { + "description": "Primary client pubkey", + "pattern": "^ak_[1-9A-HJ-NP-Za-km-z]*$", + "type": "string" + }, + "report": { + "default": "silent", + "description": "Progress reporting", + "enum": [ + "debug", + "progress", + "silent" + ], + "type": "string" + }, + "type": { + "default": "worker", + "description": "monitor mode can be used to see if a pool is alive", + "enum": [ + "worker", + "monitor" + ], + "type": "string" + }, + "workers": { + "default": [ + { "executable": "mean29-generic" } + ], + "description": "Definitions of workers' configurations. If no worker are configured one worker is used as default, i.e. 'mean29-generic' executable without any extra args.", + "items": { + "additionalProperties": false, + "properties": { + "executable": { + "default": "mean29-generic", + "description": "Executable binary of the worker. Can be a fully qualified path, \nbut the software may apply default logic to locate a plain basename.", + "type": "string" + }, + "extra_args": { + "default": "", + "description": "Extra arguments to pass to the worker executable binary. The safest choice is specifying no arguments i.e. empty string.", + "type": "string" + }, + "hex_encoded_header": { + "default": false, + "description": "Hexadecimal encode the header argument that is send to the worker executable. CUDA executables expect hex encoded header.", + "type": "boolean" + }, + "instances": { + "description": "Instances used by the worker in case of Multi-GPU mining. Numbers on the configuration list represent GPU devices that are to be addressed by the worker.", + "example": [0,1,2,3], + "items": { "type": "integer" }, + "minItems": 1, + "type": "array" + }, + "repeats": { + "default": 1, + "description": "Number of tries to do in each worker context - WARNING: it should be set so the worker process runs for 3-5s or else the node risk missing out on new micro blocks.", + "type": "integer" + } + }, + "required": [ + "executable" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" +} diff --git a/src/gmhc_connector.erl b/src/gmhc_connector.erl index c59f2cc..d111671 100644 --- a/src/gmhc_connector.erl +++ b/src/gmhc_connector.erl @@ -56,7 +56,9 @@ id :: non_neg_integer() , auto_connect = true :: boolean() , econn + , connected = false :: boolean() , reconnect_timer :: timer_ref() | 'undefined' + , recache_timer :: reference() | 'undefined' , awaiting_connect = [] :: list() , protocol :: binary() | 'undefined' , version :: binary() | 'undefined' @@ -239,12 +241,22 @@ handle_info({timeout, TRef, {reconnect, Opts}}, #st{ reconnect_timer = {TRef, _, end; handle_info({tcp_closed, _Port}, #st{} = S) -> ?LOG_DEBUG("got tcp_closed", []), - disconnected(S#st.id), - S1 = case S#st.auto_connect of - true -> start_reconnect_timer(S#st{econn = undefined}); - false -> S#st{econn = undefined} + S1 = disconnected(S#st.id, S), + S2 = case S1#st.auto_connect of + true -> start_reconnect_timer(S1#st{econn = undefined}); + false -> S1#st{econn = undefined} end, - {noreply, S1}; + {noreply, S2}; +handle_info({timeout, _, recache}, #st{opts = Opts, econn = EConn} = S0) -> + S = S0#st{recache_timer = undefined}, + case (EConn =/= undefined) andalso S#st.connected of + false -> + {noreply, S}; + true -> + ?LOG_NOTICE("Recaching eureka info", []), + cache_eureka_info(Opts), + {noreply, ensure_recache_timer(S)} + end; handle_info(Msg, S) -> ?LOG_DEBUG("Discarding msg (auto_connect=~p): ~p", [S#st.auto_connect, Msg]), {noreply, S}. @@ -286,12 +298,12 @@ try_connect_(Opts0, S) -> eureka_get_host_port() -> case gmhc_eureka:get_pool_address() of - #{<<"address">> := Host, - <<"port">> := Port, - <<"pool_id">> := PoolId} -> - #{host => binary_to_list(Host), + {ok, #{host := Host, + port := Port, + pool_id := PoolId}} -> + #{host => unicode:characters_to_list(Host), port => Port, - pool_id => binary_to_list(PoolId)}; + pool_id => unicode:characters_to_list(PoolId)}; {error, _} = Error -> Error end. @@ -348,6 +360,7 @@ start_reconnect_timer(#st{} = S, Opts) -> end. restart_reconnect_timer(#st{reconnect_timer = {_, 0, T, Opts}} = S) -> + gmhc_eureka:invalidate_cache(), NewT = max(T * 2, ?MAX_RETRY_INTERVAL), TRef = start_timer(NewT, Opts), S#st{reconnect_timer = {TRef, 10, NewT, Opts}}; @@ -373,11 +386,24 @@ notify_deadline(D, #st{awaiting_connect = Waiters} = S) -> end, [], Waiters), S#st{awaiting_connect = Waiters1}. -notify_connected(#st{id = Id, awaiting_connect = Waiters} = S) -> +cache_eureka_info(Opts) -> + gmhc_eureka:cache_good_address(maps:with([host, port, pool_id], Opts)). + +notify_connected(#st{id = Id, awaiting_connect = Waiters, opts = Opts} = S) -> gmhc_events:publish(connected, #{id => Id}), [gen_server:reply(From, ok) || {From, _} <- Waiters], gmhc_handler:pool_connected(S#st.id, S#st.opts), - S#st{awaiting_connect = []}. + cache_eureka_info(Opts), + ensure_recache_timer(S#st{awaiting_connect = []}). + +ensure_recache_timer(#st{recache_timer = T} = S) -> + case T of + undefined -> + TRef = erlang:start_timer(1*60*1000, self(), recache), + S#st{recache_timer = TRef}; + _ when is_reference(T) -> + S + end. cancel_reconnect_timer(#st{reconnect_timer = T} = S) -> case T of @@ -420,17 +446,19 @@ protocol_connect(Opts, #st{econn = EConn} = S) -> , result := #{connect_ack := #{ protocol := P , version := V }} }} -> - connected(S#st.id, Type), + S1 = connected(S#st.id, Type, S), Opts1 = Opts#{ pubkey => Pubkey , extra => Extra , pool_id => PoolId , type => Type }, - notify_connected(S#st{protocol = P, version = V, opts = Opts1}); + notify_connected(S1#st{protocol = P, version = V, opts = Opts1}); #{error := #{message := Msg}} -> ?LOG_ERROR("Connect error: ~s", [Msg]), + gmhc_eureka:invalidate_cache(), error(protocol_connect) end after 10000 -> + gmhc_eureka:invalidate_cache(), error(protocol_connect_timeout) end. @@ -443,12 +471,14 @@ to_atom(A) when is_atom(A) -> A; to_atom(S) -> binary_to_existing_atom(iolist_to_binary(S), utf8). -connected(Id, Type) when Type==worker; Type==monitor -> - gmhc_server:connected(Id, Type). +connected(Id, Type, S) when Type==worker; Type==monitor -> + gmhc_server:connected(Id, Type), + S#st{connected = true}. -disconnected(Id) -> +disconnected(Id, S) -> gmhc_events:publish(disconnected, #{id => Id}), - gmhc_server:disconnected(Id). + gmhc_server:disconnected(Id), + S#st{connected = false}. opt_autoconnect(#{auto_connect := Bool}) when is_boolean(Bool) -> Bool; diff --git a/src/gmhc_eureka.erl b/src/gmhc_eureka.erl index 14b9e05..b263b09 100644 --- a/src/gmhc_eureka.erl +++ b/src/gmhc_eureka.erl @@ -2,19 +2,88 @@ -vsn("0.6.1"). -export([get_pool_address/0]). +-export([cache_good_address/1, + invalidate_cache/0]). -include_lib("kernel/include/logger.hrl"). -include("gmhc_events.hrl"). get_pool_address() -> + case cached_address() of + {ok, _} = Ok -> Ok; + {error, _} -> + get_pool_address_() + end. + +cached_address() -> + CacheF = cache_filename(), + ?LOG_DEBUG("Eureka cache filename: ~p", [CacheF]), + case file:read_file(CacheF) of + {ok, Bin} -> + NowTS = erlang:system_time(seconds), + OldestTS = NowTS - 24*60*60, + try binary_to_term(Bin) of + #{ ts := TS + , host := _ + , port := _ + , pool_id := _} = Map -> + if TS >= OldestTS -> + Result = maps:remove(ts, Map), + ?LOG_DEBUG("Cached eureka info: ~p", [Result]), + {ok, Result}; + true -> + {error, outdated} + end; + Other -> + {error, {invalid_cache_term, Other}} + catch + error:E -> + {error, {invalid_cache_data, E}} + end; + {error, _} = Err -> + Err + end. + +cache_good_address(#{host := Addr, + port := Port, + pool_id := PoolId}) -> + CacheF = cache_filename(), + ToCache = #{ host => unicode:characters_to_binary(Addr) + , port => Port + , pool_id => unicode:characters_to_binary(PoolId) + , ts => erlang:system_time(seconds)}, + case file:write_file(CacheF, term_to_binary(ToCache)) of + ok -> + ?LOG_DEBUG("Cached eureka info in: ~p", [CacheF]), + {ok, ToCache}; + {error, _} = Err -> + ?LOG_DEBUG("Couldn't cache eureka in ~p: ~p", [CacheF, Err]), + Err + end. + +invalidate_cache() -> + CacheF = cache_filename(), + case file:delete_file(CacheF) of + ok -> + ?LOG_DEBUG("Eureka cache file removed (~p)", [CacheF]), + ok; + {error, _} = Err -> + ?LOG_DEBUG("Couldn't remove Eureka cache (~p): ~p", [CacheF, Err]), + Err + end. + +cache_filename() -> + filename:join(setup:data_dir(), "gmhc_eureka.cache"). + +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">>]) }; + #{host => <<"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) @@ -49,9 +118,13 @@ connect1(URL0) -> Error end. -get_host_port(Data) -> +get_host_port(#{ <<"address">> := Addr + , <<"port">> := Port + , <<"pool_id">> := PoolId } = Data) -> ?LOG_DEBUG("Data = ~p", [Data]), - maps:with([<<"address">>, <<"port">>, <<"pool_id">>], Data). + {ok, #{ host => Addr + , port => Port + , pool_id => PoolId }}. request(get, URL) -> case request(get, URL, []) of diff --git a/src/gmhc_server.erl b/src/gmhc_server.erl index a3856ed..67ccece 100644 --- a/src/gmhc_server.erl +++ b/src/gmhc_server.erl @@ -162,16 +162,11 @@ handle_info({'EXIT', Pid, Reason}, #st{ workers = Workers {noreply, S} end; handle_info({timeout, _, check_workers}, #st{workers = Workers} = S) -> - case [W || #worker{cand = undefined} = W <- Workers] of - [] -> - {noreply, S}; - Idle -> - S1 = maybe_request_nonces(S), - S2 = lists:foldl(fun(W, Sx) -> - maybe_restart_worker(W, Sx) - end, S1, Idle), - {noreply, S2} - end; + S1 = maybe_request_nonces(S), + S2 = lists:foldl(fun(W, Sx) -> + maybe_restart_worker(W, Sx) + end, S1, Workers), + {noreply, S2}; handle_info(Msg, St) -> ?LOG_DEBUG("Unknown msg: ~p", [Msg]), {noreply, St}. @@ -216,7 +211,6 @@ maybe_request_nonces(#st{ candidate = #{via := Via, seq := Seq, nonces := Nonces , nonces = N} = S) when ?CONNECTED(S) -> case Nonces == [] of true -> - %% ?LOG_DEBUG("Request more nonces, Seq = ~p, N = ~p", [Seq, N]), Res = gmhc_handler:call(#{via => Via, get_nonces => #{ seq => Seq , n => N }}), @@ -230,7 +224,6 @@ maybe_request_nonces(S) -> nonces_result(#{nonces := #{seq := Seq, nonces := Nonces}}, Seq0, S) -> case Seq == Seq0 of true -> - %% ?LOG_DEBUG("Got nonces = ~p", [Nonces]), #st{candidate = Cand} = S, S#st{candidate = Cand#{nonces => Nonces}}; false -> @@ -240,8 +233,22 @@ nonces_result(#{nonces := #{seq := Seq, nonces := Nonces}}, Seq0, S) -> nonces_result({error, Reason}, Seq0, S) -> ?LOG_DEBUG("Got error on nonce request: ~p", [Reason]), Workers = stop_workers_for_seq(Seq0, S#st.workers), + case Reason of + {timeout, _} -> + Timeout = retry_timeout(1000, 3000), + erlang:start_timer(Timeout, self(), check_workers); + _ -> + ok + end, S#st{workers = Workers}. +retry_timeout(Floor, Range) -> + Floor + rand(Range). + +rand(Range) -> + <> = crypto:strong_rand_bytes(4), + Range - (Rx rem Range). + handle_worker_result({worker_result, Result}, W, S) -> %% ?LOG_DEBUG("worker result: ~p", [Result]), case Result of diff --git a/zomp.meta b/zomp.meta index e467016..962e204 100644 --- a/zomp.meta +++ b/zomp.meta @@ -2,9 +2,9 @@ {type,app}. {modules,[]}. {prefix,"gmhc"}. -{desc,"Gajumaru Hive Client"}. {author,"Ulf Wiger, QPQ AG"}. -{package_id,{"uwiger","gmhive_client",{0,6,3}}}. +{desc,"Gajumaru Hive Client"}. +{package_id,{"uwiger","gmhive_client",{0,7,0}}}. {deps,[{"uwiger","gmhive_worker",{0,5,1}}, {"uwiger","gmcuckoo",{1,2,4}}, {"otpr","eblake2",{1,0,1}}, -- 2.30.2 From cb0d8f3689c97a84158bcd1c23581fc41a1f4633 Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Sun, 12 Oct 2025 19:58:22 +0200 Subject: [PATCH 3/6] Account-specific cache file, bugfixes, better error info add gmhc_lib.erl --- ebin/gmhive_client.app | 2 +- rebar.config | 2 +- rebar.lock | 2 +- src/gmhc_connector.erl | 33 ++++++++++++++++++++++++++------- src/gmhc_eureka.erl | 13 +++++++------ src/gmhc_lib.erl | 8 ++++++++ src/gmhc_server.erl | 6 +----- zomp.meta | 8 ++++---- 8 files changed, 49 insertions(+), 25 deletions(-) create mode 100644 src/gmhc_lib.erl diff --git a/ebin/gmhive_client.app b/ebin/gmhive_client.app index 18ef1ab..4af5114 100644 --- a/ebin/gmhive_client.app +++ b/ebin/gmhive_client.app @@ -1,6 +1,6 @@ {application,gmhive_client, [{description,"Gajumaru Hive Client"}, - {vsn,"0.7.0"}, + {vsn,"0.8.0"}, {registered,[]}, {applications,[kernel,stdlib,sasl,gproc,inets,ssl,enoise, gmconfig,gmhive_protocol,gmhive_worker]}, diff --git a/rebar.config b/rebar.config index cbfeeeb..0e2aa69 100644 --- a/rebar.config +++ b/rebar.config @@ -11,7 +11,7 @@ {enoise, {git, "https://git.qpq.swiss/QPQ-AG/enoise.git", {ref, "029292817e"}}}, {gmhive_protocol, {git, "https://git.qpq.swiss/QPQ-AG/gmhive_protocol.git", - {ref, "818ce33"}}}, + {ref, "8d4652a"}}}, {gmhive_worker, {git, "https://git.qpq.swiss/QPQ-AG/gmhive_worker", {ref, "cabd104114"}}}, {gmconfig, {git, "https://git.qpq.swiss/QPQ-AG/gmconfig.git", {ref, "38620ff9e2"}}}, diff --git a/rebar.lock b/rebar.lock index bd78cfe..50980b1 100644 --- a/rebar.lock +++ b/rebar.lock @@ -25,7 +25,7 @@ 1}, {<<"gmhive_protocol">>, {git,"https://git.qpq.swiss/QPQ-AG/gmhive_protocol.git", - {ref,"818ce33cc1dec74c020515be48fb548a5207befd"}}, + {ref,"8d4652a79a2ad8f51e1fe560c15c698d4c92485c"}}, 0}, {<<"gmhive_worker">>, {git,"https://git.qpq.swiss/QPQ-AG/gmhive_worker", diff --git a/src/gmhc_connector.erl b/src/gmhc_connector.erl index d111671..904bd7b 100644 --- a/src/gmhc_connector.erl +++ b/src/gmhc_connector.erl @@ -57,6 +57,7 @@ , auto_connect = true :: boolean() , econn , connected = false :: boolean() + , reconnect = true :: boolean() , reconnect_timer :: timer_ref() | 'undefined' , recache_timer :: reference() | 'undefined' , awaiting_connect = [] :: list() @@ -143,6 +144,9 @@ init(#{id := Id} = Opts) when is_map(Opts) -> {ok, S} -> ?LOG_DEBUG("Initial connect succeeded", []), S; + {error, rejected} -> + ?LOG_WARNING("Connection rejected; will not retry", []), + S0#st{econn = undefined, reconnect = false}; {error, _} = Error -> ?LOG_WARNING("Could not connect to core server: ~p", [Error]), start_reconnect_timer(S0#st{econn = undefined}) @@ -181,6 +185,7 @@ handle_call({connect, Opts}, From, #st{awaiting_connect = Waiters} = S) -> end, S1 = start_reconnect_timer( S#st{ auto_connect = true + , reconnect = true , awaiting_connect = Waiters1 }, Opts), {noreply, S1}; false -> @@ -276,6 +281,8 @@ code_change(_FromVsn, S, _Extra) -> try_connect(Opts, S) -> try try_connect_(Opts, S) catch + error:rejected:_ -> + {error, rejected}; error:E:T -> ?LOG_ERROR("Unexpected error connecting: ~p / ~p", [E, T]), {error, E} @@ -345,6 +352,8 @@ default_tcp_opts() -> enoise_opts() -> [{noise, <<"Noise_NN_25519_ChaChaPoly_BLAKE2b">>}]. +start_reconnect_timer(#st{reconnect = false} = S) -> + S; start_reconnect_timer(#st{} = S) -> start_reconnect_timer(S, #{}). @@ -356,12 +365,18 @@ start_reconnect_timer(#st{} = S, Opts) -> false -> ?LOG_DEBUG("starting reconnect timer ...", []), TRef = start_timer(1000, Opts), - S#st{reconnect_timer = {TRef, 10, 1000, Opts}} + S#st{reconnect_timer = {TRef, 10, 8000 + gmhc_lib:rand(3000), Opts}} end. +restart_reconnect_timer(#st{reconnect = false} = S) -> + cancel_reconnect_timer(S); restart_reconnect_timer(#st{reconnect_timer = {_, 0, T, Opts}} = S) -> - gmhc_eureka:invalidate_cache(), - NewT = max(T * 2, ?MAX_RETRY_INTERVAL), + NewT = max(T + 5000 + gmhc_lib:rand(1000), ?MAX_RETRY_INTERVAL), + if (NewT > T andalso NewT =:= ?MAX_RETRY_INTERVAL) -> + gmhc_eureka:invalidate_cache(); + true -> + ok + end, TRef = start_timer(NewT, Opts), S#st{reconnect_timer = {TRef, 10, NewT, Opts}}; restart_reconnect_timer(#st{reconnect_timer = {_, N, T, Opts}} = S) -> @@ -452,10 +467,11 @@ protocol_connect(Opts, #st{econn = EConn} = S) -> , pool_id => PoolId , type => Type }, notify_connected(S1#st{protocol = P, version = V, opts = Opts1}); - #{error := #{message := Msg}} -> - ?LOG_ERROR("Connect error: ~s", [Msg]), + #{error := #{code := _, message := ErrMsg}} = ErrReply -> + ?LOG_ERROR("Connect error: ~s", [ErrMsg]), + disconnected(S#st.id, ErrReply, S), gmhc_eureka:invalidate_cache(), - error(protocol_connect) + error(rejected) end after 10000 -> gmhc_eureka:invalidate_cache(), @@ -476,7 +492,10 @@ connected(Id, Type, S) when Type==worker; Type==monitor -> S#st{connected = true}. disconnected(Id, S) -> - gmhc_events:publish(disconnected, #{id => Id}), + disconnected(Id, #{}, S). + +disconnected(Id, Msg, S) -> + gmhc_events:publish(disconnected, Msg#{id => Id}), gmhc_server:disconnected(Id), S#st{connected = false}. diff --git a/src/gmhc_eureka.erl b/src/gmhc_eureka.erl index b263b09..a9ee860 100644 --- a/src/gmhc_eureka.erl +++ b/src/gmhc_eureka.erl @@ -63,7 +63,7 @@ cache_good_address(#{host := Addr, invalidate_cache() -> CacheF = cache_filename(), - case file:delete_file(CacheF) of + case file:delete(CacheF) of ok -> ?LOG_DEBUG("Eureka cache file removed (~p)", [CacheF]), ok; @@ -73,17 +73,18 @@ invalidate_cache() -> end. cache_filename() -> - filename:join(setup:data_dir(), "gmhc_eureka.cache"). + <<"ak_", PKShort:8/binary, _/binary>> = gmhc_config:get_config([<<"pubkey">>]), + filename:join(setup:data_dir(), "gmhc_eureka." ++ binary_to_list(PKShort) ++ ".cache"). get_pool_address_() -> case gmconfig:find_config([<<"pool_admin">>, <<"url">>], [user_config]) of {ok, URL0} -> case expand_url(URL0) of <<"local">> -> - #{host => <<"127.0.0.1">>, - port => gmconfig:get_config( - [<<"pool">>, <<"port">>], [schema_default]), - pool_id => gmhc_config:get_config([<<"pool">>, <<"id">>]) }; + {ok, #{host => <<"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) diff --git a/src/gmhc_lib.erl b/src/gmhc_lib.erl new file mode 100644 index 0000000..48ecf92 --- /dev/null +++ b/src/gmhc_lib.erl @@ -0,0 +1,8 @@ +-module(gmhc_lib). + +-export([ rand/1 ]). + + +rand(Range) -> + <> = crypto:strong_rand_bytes(4), + Range - (Rx rem Range). diff --git a/src/gmhc_server.erl b/src/gmhc_server.erl index 67ccece..a9efc33 100644 --- a/src/gmhc_server.erl +++ b/src/gmhc_server.erl @@ -243,11 +243,7 @@ nonces_result({error, Reason}, Seq0, S) -> S#st{workers = Workers}. retry_timeout(Floor, Range) -> - Floor + rand(Range). - -rand(Range) -> - <> = crypto:strong_rand_bytes(4), - Range - (Rx rem Range). + Floor + gmhc_lib:rand(Range). handle_worker_result({worker_result, Result}, W, S) -> %% ?LOG_DEBUG("worker result: ~p", [Result]), diff --git a/zomp.meta b/zomp.meta index 962e204..5a7c7d4 100644 --- a/zomp.meta +++ b/zomp.meta @@ -2,15 +2,15 @@ {type,app}. {modules,[]}. {prefix,"gmhc"}. -{author,"Ulf Wiger, QPQ AG"}. {desc,"Gajumaru Hive Client"}. -{package_id,{"uwiger","gmhive_client",{0,7,0}}}. -{deps,[{"uwiger","gmhive_worker",{0,5,1}}, +{author,"Ulf Wiger, QPQ AG"}. +{package_id,{"uwiger","gmhive_client",{0,8,0}}}. +{deps,[{"uwiger","gmhive_protocol",{0,2,0}}, + {"uwiger","gmhive_worker",{0,5,1}}, {"uwiger","gmcuckoo",{1,2,4}}, {"otpr","eblake2",{1,0,1}}, {"otpr","base58",{0,1,1}}, {"otpr","gmserialization",{0,1,3}}, - {"uwiger","gmhive_protocol",{0,1,1}}, {"uwiger","setup",{2,2,4}}, {"uwiger","gproc",{1,0,1}}, {"uwiger","gmconfig",{0,1,2}}, -- 2.30.2 From 570f31ab3c189af00268d9e0bb52e7dfe546eb57 Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Mon, 13 Oct 2025 13:57:34 +0200 Subject: [PATCH 4/6] Network specific cache filename + more sanity checks --- README.md | 14 ++++++++++ ebin/gmhive_client.app | 2 +- src/gmhc_eureka.erl | 59 ++++++++++++++++++++++++++++++------------ zomp.meta | 2 +- 4 files changed, 59 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 7df0c93..1f61351 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,20 @@ only does this inform the client of the network for which the client should mine, but it also changes what URL the client will use to find the hive server. (For `"testnet"` this will be `"test.gajumining.com"`.) +### Caching of connection data + +The client retrieves the Hive Server connection info from gajumining.com. +This information is account-specific, and may change over time. + +To speed up the reconnecting process, should the Hive Server restart, +this connection information is cached locally for up to 24 hours. +The normal place for the cached data would be +`$ZOMP_DIR//var/uwiger/gmhive_client/Vsn/setup.data/mainnet/gmhc_eureka.XXXXXXXX.cache`, +where `Vsn` is the current version of `gmhive_client`, and `XXXXXXXX` is a fragment +of the current account ID. The data location can be changed with the command-line +option `-setup data_dir Dir`. + + ## JSON Schema ```json diff --git a/ebin/gmhive_client.app b/ebin/gmhive_client.app index 4af5114..8b15bbc 100644 --- a/ebin/gmhive_client.app +++ b/ebin/gmhive_client.app @@ -1,6 +1,6 @@ {application,gmhive_client, [{description,"Gajumaru Hive Client"}, - {vsn,"0.8.0"}, + {vsn,"0.8.1"}, {registered,[]}, {applications,[kernel,stdlib,sasl,gproc,inets,ssl,enoise, gmconfig,gmhive_protocol,gmhive_worker]}, diff --git a/src/gmhc_eureka.erl b/src/gmhc_eureka.erl index a9ee860..dafdf17 100644 --- a/src/gmhc_eureka.erl +++ b/src/gmhc_eureka.erl @@ -16,7 +16,8 @@ get_pool_address() -> end. cached_address() -> - CacheF = cache_filename(), + I0 = cache_info(), + CacheF = cache_filename(I0), ?LOG_DEBUG("Eureka cache filename: ~p", [CacheF]), case file:read_file(CacheF) of {ok, Bin} -> @@ -24,9 +25,12 @@ cached_address() -> OldestTS = NowTS - 24*60*60, try binary_to_term(Bin) of #{ ts := TS + , network := N + , pubkey := PK , host := _ , port := _ - , pool_id := _} = Map -> + , pool_id := _} = Map when N == map_get(network, I0), + PK == map_get(pubkey, I0) -> if TS >= OldestTS -> Result = maps:remove(ts, Map), ?LOG_DEBUG("Cached eureka info: ~p", [Result]), @@ -44,20 +48,25 @@ cached_address() -> Err end. -cache_good_address(#{host := Addr, - port := Port, - pool_id := PoolId}) -> - CacheF = cache_filename(), - ToCache = #{ host => unicode:characters_to_binary(Addr) - , port => Port - , pool_id => unicode:characters_to_binary(PoolId) - , ts => erlang:system_time(seconds)}, - case file:write_file(CacheF, term_to_binary(ToCache)) of +cache_good_address(#{host := _, + port := _, + pool_id := _} = I0) -> + CacheInfo = cache_info(I0), + CacheF = cache_filename(CacheInfo), + + ToCache = CacheInfo#{ts => erlang:system_time(seconds)}, + case filelib:ensure_dir(CacheF) of ok -> - ?LOG_DEBUG("Cached eureka info in: ~p", [CacheF]), - {ok, ToCache}; + case file:write_file(CacheF, term_to_binary(ToCache)) of + ok -> + ?LOG_DEBUG("Cached eureka info in: ~p", [CacheF]), + {ok, ToCache}; + {error, _} = Err -> + ?LOG_DEBUG("Couldn't cache eureka in ~p: ~p", [CacheF, Err]), + Err + end; {error, _} = Err -> - ?LOG_DEBUG("Couldn't cache eureka in ~p: ~p", [CacheF, Err]), + ?LOG_ERROR("Cannot save cached info to ~s", [CacheF]), Err end. @@ -72,9 +81,27 @@ invalidate_cache() -> Err end. +cache_info(#{ host := Addr + , port := Port + , pool_id := PoolId }) -> + I0 = cache_info(), + I0#{ host => unicode:characters_to_binary(Addr) + , port => Port + , pool_id => unicode:characters_to_binary(PoolId)}. + +cache_info() -> + Pubkey = gmhc_config:get_config([<<"pubkey">>]), + Network = gmhc_config:get_config([<<"network">>]), + #{ pubkey => Pubkey + , network => Network }. + cache_filename() -> - <<"ak_", PKShort:8/binary, _/binary>> = gmhc_config:get_config([<<"pubkey">>]), - filename:join(setup:data_dir(), "gmhc_eureka." ++ binary_to_list(PKShort) ++ ".cache"). + cache_filename(cache_info()). + +cache_filename(#{network := Network, pubkey := Pubkey}) -> + Path = filename:join(setup:data_dir(), Network), + <<"ak_", PKShort:8/binary, _/binary>> = Pubkey, + filename:join(Path, "gmhc_eureka." ++ binary_to_list(PKShort) ++ ".cache"). get_pool_address_() -> case gmconfig:find_config([<<"pool_admin">>, <<"url">>], [user_config]) of diff --git a/zomp.meta b/zomp.meta index 5a7c7d4..4fe9103 100644 --- a/zomp.meta +++ b/zomp.meta @@ -4,7 +4,7 @@ {prefix,"gmhc"}. {desc,"Gajumaru Hive Client"}. {author,"Ulf Wiger, QPQ AG"}. -{package_id,{"uwiger","gmhive_client",{0,8,0}}}. +{package_id,{"uwiger","gmhive_client",{0,8,1}}}. {deps,[{"uwiger","gmhive_protocol",{0,2,0}}, {"uwiger","gmhive_worker",{0,5,1}}, {"uwiger","gmcuckoo",{1,2,4}}, -- 2.30.2 From 1e60f35dd3e38d46b464434d7a3d681b9d7e0770 Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Tue, 14 Oct 2025 13:02:38 +0200 Subject: [PATCH 5/6] Handle case where connection meta-data are faulty --- ebin/gmhive_client.app | 2 +- src/gmhc_connector.erl | 15 ++++++++++++++- zomp.meta | 4 ++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/ebin/gmhive_client.app b/ebin/gmhive_client.app index 8b15bbc..50b9d5b 100644 --- a/ebin/gmhive_client.app +++ b/ebin/gmhive_client.app @@ -1,6 +1,6 @@ {application,gmhive_client, [{description,"Gajumaru Hive Client"}, - {vsn,"0.8.1"}, + {vsn,"0.8.2"}, {registered,[]}, {applications,[kernel,stdlib,sasl,gproc,inets,ssl,enoise, gmconfig,gmhive_protocol,gmhive_worker]}, diff --git a/src/gmhc_connector.erl b/src/gmhc_connector.erl index 904bd7b..7c28d9b 100644 --- a/src/gmhc_connector.erl +++ b/src/gmhc_connector.erl @@ -452,7 +452,20 @@ protocol_connect(Opts, #st{econn = EConn} = S) -> , nonces => gmhc_server:total_nonces() , signature => ""}, ?LOG_DEBUG("ConnectReq = ~p", [ConnectReq]), - Msg = gmhp_msgs:encode_connect(ConnectReq, RId), + try gmhp_msgs:encode_connect(ConnectReq, RId) of + Msg -> + send_connect(EConn, RId, Msg, ConnectReq, Opts, S) + catch error:Error -> + ErrMsg = unicode:characters_to_binary(io_lib:fwrite("~p", [Error])), + disconnected(S#st.id, #{error => + #{code => gmhp_msgs:error_code(invalid_input), + message => ErrMsg}}, S) + end. + +send_connect(EConn, RId, Msg, #{pubkey := Pubkey, + extra_pubkeys := Extra, + pool_id := PoolId, + type := Type}, Opts, S) -> enoise:send(EConn, Msg), receive {noise, EConn, Data} -> diff --git a/zomp.meta b/zomp.meta index 4fe9103..0641e5f 100644 --- a/zomp.meta +++ b/zomp.meta @@ -2,9 +2,9 @@ {type,app}. {modules,[]}. {prefix,"gmhc"}. -{desc,"Gajumaru Hive Client"}. {author,"Ulf Wiger, QPQ AG"}. -{package_id,{"uwiger","gmhive_client",{0,8,1}}}. +{desc,"Gajumaru Hive Client"}. +{package_id,{"uwiger","gmhive_client",{0,8,2}}}. {deps,[{"uwiger","gmhive_protocol",{0,2,0}}, {"uwiger","gmhive_worker",{0,5,1}}, {"uwiger","gmcuckoo",{1,2,4}}, -- 2.30.2 From 847ffc810afa4ab27a48b4de6431bd440a8affa7 Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Wed, 15 Oct 2025 12:41:00 +0200 Subject: [PATCH 6/6] Fix cache_dir() problem, made it configurable --- README.md | 4 ++++ ebin/gmhive_client.app | 2 +- priv/gmhc_schema.json | 4 ++++ src/gmhc_app.erl | 2 +- src/gmhc_config.erl | 2 +- src/gmhc_config_schema.erl | 3 ++- src/gmhc_connector.erl | 2 +- src/gmhc_connectors_sup.erl | 2 +- src/gmhc_counters.erl | 2 +- src/gmhc_eureka.erl | 26 +++++++++++++++++++++++--- src/gmhc_events.erl | 2 +- src/gmhc_handler.erl | 2 +- src/gmhc_lib.erl | 1 + src/gmhc_server.erl | 2 +- src/gmhc_sup.erl | 2 +- src/gmhc_workers.erl | 2 +- src/gmhive_client.erl | 2 +- zomp.meta | 4 ++-- 18 files changed, 48 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 1f61351..7389829 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,10 @@ option `-setup data_dir Dir`. "$schema": "http://json-schema.org/draft-04/schema#", "additionalProperties": false, "properties": { + "cache_dir": { + "description": "Location of cache, default is 'setup:data_dir()'", + "type": "string" + }, "extra_pubkeys": { "default": [], "description": "Additional worker pubkeys, sharing rewards", diff --git a/ebin/gmhive_client.app b/ebin/gmhive_client.app index 50b9d5b..7fb10f6 100644 --- a/ebin/gmhive_client.app +++ b/ebin/gmhive_client.app @@ -1,6 +1,6 @@ {application,gmhive_client, [{description,"Gajumaru Hive Client"}, - {vsn,"0.8.2"}, + {vsn,"0.8.3"}, {registered,[]}, {applications,[kernel,stdlib,sasl,gproc,inets,ssl,enoise, gmconfig,gmhive_protocol,gmhive_worker]}, diff --git a/priv/gmhc_schema.json b/priv/gmhc_schema.json index 6c0371a..99fbab4 100644 --- a/priv/gmhc_schema.json +++ b/priv/gmhc_schema.json @@ -2,6 +2,10 @@ "$schema": "http://json-schema.org/draft-04/schema#", "additionalProperties": false, "properties": { + "cache_dir": { + "description": "Location of cache, default is 'setup:data_dir()'", + "type": "string" + }, "extra_pubkeys": { "default": [], "description": "Additional worker pubkeys, sharing rewards", diff --git a/src/gmhc_app.erl b/src/gmhc_app.erl index f5e98a1..51fe8f9 100644 --- a/src/gmhc_app.erl +++ b/src/gmhc_app.erl @@ -1,6 +1,6 @@ %% -*- mode: erlang; erlang-indent-level: 4; indent-tabs-mode: nil -*- -module(gmhc_app). --vsn("0.6.1"). +-vsn("0.8.3"). -behaviour(application). diff --git a/src/gmhc_config.erl b/src/gmhc_config.erl index 19b0623..f05c1bd 100644 --- a/src/gmhc_config.erl +++ b/src/gmhc_config.erl @@ -1,5 +1,5 @@ -module(gmhc_config). --vsn("0.6.1"). +-vsn("0.8.3"). -export([ load_config/0 , get_config/1 diff --git a/src/gmhc_config_schema.erl b/src/gmhc_config_schema.erl index 7276efa..c8e2d4e 100644 --- a/src/gmhc_config_schema.erl +++ b/src/gmhc_config_schema.erl @@ -1,5 +1,5 @@ -module(gmhc_config_schema). --vsn("0.6.1"). +-vsn("0.8.3"). -export([ schema/0 , to_json/0 @@ -51,6 +51,7 @@ schema() -> , pool => pool() , pool_admin => pool_admin() , workers => workers() + , cache_dir => str(#{description => <<"Location of cache, default is 'setup:data_dir()'">>}) , report => str(#{ enum => [<<"debug">>, <<"progress">>, <<"silent">>] , default => <<"silent">> , description => <<"Progress reporting">> }) diff --git a/src/gmhc_connector.erl b/src/gmhc_connector.erl index 7c28d9b..294d6c9 100644 --- a/src/gmhc_connector.erl +++ b/src/gmhc_connector.erl @@ -1,5 +1,5 @@ -module(gmhc_connector). --vsn("0.6.1"). +-vsn("0.8.3"). -behaviour(gen_server). diff --git a/src/gmhc_connectors_sup.erl b/src/gmhc_connectors_sup.erl index b94b8a9..3996d71 100644 --- a/src/gmhc_connectors_sup.erl +++ b/src/gmhc_connectors_sup.erl @@ -1,5 +1,5 @@ -module(gmhc_connectors_sup). --vsn("0.6.1"). +-vsn("0.8.3"). -behavior(supervisor). -export([ start_link/0 diff --git a/src/gmhc_counters.erl b/src/gmhc_counters.erl index d7210ba..270e6e8 100644 --- a/src/gmhc_counters.erl +++ b/src/gmhc_counters.erl @@ -1,5 +1,5 @@ -module(gmhc_counters). --vsn("0.6.1"). +-vsn("0.8.3"). -export([ initialize/0 ]). diff --git a/src/gmhc_eureka.erl b/src/gmhc_eureka.erl index dafdf17..9059ed7 100644 --- a/src/gmhc_eureka.erl +++ b/src/gmhc_eureka.erl @@ -1,9 +1,12 @@ -module(gmhc_eureka). --vsn("0.6.1"). +-vsn("0.8.3"). -export([get_pool_address/0]). -export([cache_good_address/1, - invalidate_cache/0]). + invalidate_cache/0, + cached_address/0, + cache_filename/0, + cache_dir/0]). -include_lib("kernel/include/logger.hrl"). -include("gmhc_events.hrl"). @@ -99,10 +102,27 @@ cache_filename() -> cache_filename(cache_info()). cache_filename(#{network := Network, pubkey := Pubkey}) -> - Path = filename:join(setup:data_dir(), Network), + Path = filename:join(cache_dir(), Network), <<"ak_", PKShort:8/binary, _/binary>> = Pubkey, filename:join(Path, "gmhc_eureka." ++ binary_to_list(PKShort) ++ ".cache"). +cache_dir() -> + case gmconfig:find_config([<<"cache_dir">>]) of + {ok, D} -> + D; + undefined -> + case setup_zomp:is_zomp_context() of + true -> + cache_dir_zomp(); + false -> + filename:join(setup:data_dir(), "gmhive.cache") + end + end. + +cache_dir_zomp() -> + #{package_id := {Realm, App, _}} = zx_daemon:meta(), + filename:join(zx_lib:ppath(var, {Realm, App}), "gmhive.cache"). + get_pool_address_() -> case gmconfig:find_config([<<"pool_admin">>, <<"url">>], [user_config]) of {ok, URL0} -> diff --git a/src/gmhc_events.erl b/src/gmhc_events.erl index ffbd6da..55cc220 100644 --- a/src/gmhc_events.erl +++ b/src/gmhc_events.erl @@ -1,5 +1,5 @@ -module(gmhc_events). --vsn("0.6.1"). +-vsn("0.8.3"). -export([subscribe/1, ensure_subscribed/1, diff --git a/src/gmhc_handler.erl b/src/gmhc_handler.erl index de44e68..f32bcd9 100644 --- a/src/gmhc_handler.erl +++ b/src/gmhc_handler.erl @@ -1,5 +1,5 @@ -module(gmhc_handler). --vsn("0.6.1"). +-vsn("0.8.3"). -behavior(gen_server). -export([ start_link/0 diff --git a/src/gmhc_lib.erl b/src/gmhc_lib.erl index 48ecf92..131dde1 100644 --- a/src/gmhc_lib.erl +++ b/src/gmhc_lib.erl @@ -1,4 +1,5 @@ -module(gmhc_lib). +-vsn("0.8.3"). -export([ rand/1 ]). diff --git a/src/gmhc_server.erl b/src/gmhc_server.erl index a9efc33..ae51c57 100644 --- a/src/gmhc_server.erl +++ b/src/gmhc_server.erl @@ -1,5 +1,5 @@ -module(gmhc_server). --vsn("0.6.1"). +-vsn("0.8.3"). -behaviour(gen_server). diff --git a/src/gmhc_sup.erl b/src/gmhc_sup.erl index 7504a16..a2723bf 100644 --- a/src/gmhc_sup.erl +++ b/src/gmhc_sup.erl @@ -1,6 +1,6 @@ %% -*- mode: erlang; erlang-indent-level: 4; indent-tabs-mode: nil -*- -module(gmhc_sup). --vsn("0.6.1"). +-vsn("0.8.3"). -behaviour(supervisor). diff --git a/src/gmhc_workers.erl b/src/gmhc_workers.erl index 3b026ee..b89df0a 100644 --- a/src/gmhc_workers.erl +++ b/src/gmhc_workers.erl @@ -8,7 +8,7 @@ %%%------------------------------------------------------------------- -module(gmhc_workers). --vsn("0.6.1"). +-vsn("0.8.3"). -export([ get_worker_configs/0 diff --git a/src/gmhive_client.erl b/src/gmhive_client.erl index 7779d26..0696120 100644 --- a/src/gmhive_client.erl +++ b/src/gmhive_client.erl @@ -1,5 +1,5 @@ -module(gmhive_client). --vsn("0.6.1"). +-vsn("0.8.3"). -export([ connect/1 , disconnect/1 diff --git a/zomp.meta b/zomp.meta index 0641e5f..2f3f445 100644 --- a/zomp.meta +++ b/zomp.meta @@ -2,9 +2,9 @@ {type,app}. {modules,[]}. {prefix,"gmhc"}. -{author,"Ulf Wiger, QPQ AG"}. {desc,"Gajumaru Hive Client"}. -{package_id,{"uwiger","gmhive_client",{0,8,2}}}. +{author,"Ulf Wiger, QPQ AG"}. +{package_id,{"uwiger","gmhive_client",{0,8,3}}}. {deps,[{"uwiger","gmhive_protocol",{0,2,0}}, {"uwiger","gmhive_worker",{0,5,1}}, {"uwiger","gmcuckoo",{1,2,4}}, -- 2.30.2