WIP: Configuration interface
This commit is contained in:
parent
b0148289ca
commit
bccabcb1c0
@ -3,6 +3,6 @@
|
||||
{registered,[]},
|
||||
{included_applications,[]},
|
||||
{applications,[stdlib,kernel]},
|
||||
{vsn,"0.1.4"},
|
||||
{vsn,"0.2.0"},
|
||||
{modules,[gajumine,gmc_con,gmc_gui,gmc_setup,gmc_sup]},
|
||||
{mod,{gajumine,[]}}]}.
|
||||
|
@ -3,7 +3,7 @@
|
||||
%%% @end
|
||||
|
||||
-module(gajumine).
|
||||
-vsn("0.1.4").
|
||||
-vsn("0.2.0").
|
||||
-behavior(application).
|
||||
-author("Craig Everett <craigeverett@qpq.swiss>").
|
||||
-copyright("Craig Everett <craigeverett@qpq.swiss>").
|
||||
|
287
src/gmc_con.erl
287
src/gmc_con.erl
@ -3,14 +3,15 @@
|
||||
%%% @end
|
||||
|
||||
-module(gmc_con).
|
||||
-vsn("0.1.4").
|
||||
-vsn("0.2.0").
|
||||
-author("Craig Everett <craigeverett@qpq.swiss>").
|
||||
-copyright("Craig Everett <craigeverett@qpq.swiss>").
|
||||
-license("GPL-3.0-or-later").
|
||||
|
||||
-behavior(gen_server).
|
||||
-export([start_stop/0, gajudesk/0]).
|
||||
-export([unlock/1, make_key/2, load_key/3, end_setup/0, bin_dir/0]).
|
||||
-export([conf/0, conf/1]).
|
||||
-export([bin_dir/0]).
|
||||
-export([network/0]).
|
||||
-export([start_link/0, stop/0]).
|
||||
-export([init/1, terminate/2, code_change/3,
|
||||
@ -23,12 +24,14 @@
|
||||
|
||||
|
||||
-record(s,
|
||||
{version = 1 :: integer(),
|
||||
window = none :: none | wx:wx_object(),
|
||||
network = <<"testnet">> :: binary(), % <<"testnet">> | <<"mainnet">>
|
||||
exec_dir = platform_dir() :: file:filename(),
|
||||
key = none :: none | {blob, binary()} | #key{},
|
||||
pass = none :: none | binary()}).
|
||||
{version = 1 :: integer(),
|
||||
window = none :: none | wx:wx_object(),
|
||||
network = <<"mainnet">> :: binary(), % <<"testnet">> | <<"mainnet">>
|
||||
exec_dir = platform_dir() :: file:filename(),
|
||||
acc = none :: none | binary(),
|
||||
keys = [] :: [],
|
||||
mem_limit = 3550722201 :: pos_integer(),
|
||||
prefs = #{} :: #{}}).
|
||||
|
||||
-type state() :: #s{}.
|
||||
|
||||
@ -48,34 +51,22 @@ gajudesk() ->
|
||||
gen_server:cast(?MODULE, gajudesk).
|
||||
|
||||
|
||||
-spec unlock(Phrase) -> ok
|
||||
when Phrase :: string().
|
||||
-spec conf() -> {Account, Keys, Network}
|
||||
when Account :: none | binary(), % <<"ak_...">>
|
||||
Keys :: [binary()],
|
||||
Network :: binary(). % <<"mainnet">> | <<"testnet">> | <<"devnet">>
|
||||
|
||||
unlock(Phrase) ->
|
||||
gen_server:cast(?MODULE, {unlock, Phrase}).
|
||||
conf() ->
|
||||
gen_server:call(?MODULE, conf).
|
||||
|
||||
|
||||
-spec make_key(Phrase, Network) -> ok
|
||||
when Phrase :: string(),
|
||||
Network :: mainnet | testnet.
|
||||
-spec conf({Account, Keys, Network}) -> ok
|
||||
when Account :: none | binary(), % <<"ak_...">>
|
||||
Keys :: [binary()],
|
||||
Network :: binary(). % <<"mainnet">> | <<"testnet">> | <<"devnet">>
|
||||
|
||||
make_key(Phrase, Network) ->
|
||||
gen_server:cast(?MODULE, {make_key, Phrase, Network}).
|
||||
|
||||
|
||||
-spec load_key(Phrase, Mnemonic, Network) -> ok
|
||||
when Phrase :: string(),
|
||||
Mnemonic :: string(),
|
||||
Network :: mainnet | testnet.
|
||||
|
||||
load_key(Phrase, Mnemonic, Network) ->
|
||||
gen_server:cast(?MODULE, {load_key, Phrase, Mnemonic, Network}).
|
||||
|
||||
|
||||
-spec end_setup() -> ok.
|
||||
|
||||
end_setup() ->
|
||||
gen_server:call(?MODULE, end_setup).
|
||||
conf(Info) ->
|
||||
gen_server:cast(?MODULE, {conf, Info}).
|
||||
|
||||
|
||||
-spec bin_dir() -> file:filename().
|
||||
@ -118,43 +109,19 @@ start_link() ->
|
||||
init(none) ->
|
||||
ok = log(info, "Starting"),
|
||||
_ = process_flag(sensitive, true),
|
||||
case open_wallet() of
|
||||
{blob, Binary} ->
|
||||
NewState = start_gui(#s{key = {blob, Binary}}),
|
||||
ok = gmc_gui:ask_passphrase(),
|
||||
{ok, NewState};
|
||||
{ok, Wallet, NetworkID} ->
|
||||
NewState = start_gui(#s{key = Wallet, network = NetworkID}),
|
||||
{ok, NewState};
|
||||
error ->
|
||||
Window = gmc_setup:start_link(#{}),
|
||||
ok = log(info, "Window: ~p", [Window]),
|
||||
State = #s{window = Window},
|
||||
{ok, State}
|
||||
end.
|
||||
{Acc, Keys, Network, MemLimit} =
|
||||
case read_conf() of
|
||||
{ok, C} ->
|
||||
{maps:get(account, C, none),
|
||||
maps:get(keys, C, []),
|
||||
maps:get(network, C, <<"mainnet">>),
|
||||
maps:get(mem_limit, C, 3550722201)};
|
||||
none ->
|
||||
{none, [], <<"mainnet">>, 3550722201}
|
||||
end,
|
||||
State = #s{network = Network, acc = Acc, keys = Keys, mem_limit = MemLimit},
|
||||
{ok, start_gui(State)}.
|
||||
|
||||
open_wallet() ->
|
||||
GDPrefs = gd_read_prefs(),
|
||||
Wallets = gd_get_prefs(wallets, GDPrefs, []),
|
||||
case lists:keyfind(gm_name(), #wr.name, Wallets) of
|
||||
#wr{path = Path, pass = true} ->
|
||||
case file:read_file(Path) of
|
||||
{ok, Binary} -> {blob, Binary};
|
||||
Error -> Error
|
||||
end;
|
||||
#wr{path = Path, pass = false} ->
|
||||
case file:read_file(Path) of
|
||||
{ok, Binary} ->
|
||||
% TODO: Comply with GD's wallet upgrade system
|
||||
{ok, #wallet{keys = Keys, nets = [#net{id = NetID}]}} = zx_lib:b_to_t(Binary),
|
||||
Key = lists:keyfind(gm_name(), #key.name, Keys),
|
||||
{ok, Key, NetID};
|
||||
Error ->
|
||||
Error
|
||||
end;
|
||||
false ->
|
||||
error
|
||||
end.
|
||||
|
||||
platform_dir() ->
|
||||
#{deps := Deps} = zx_daemon:meta(),
|
||||
@ -173,9 +140,9 @@ platform_dir() ->
|
||||
filename:join(Priv, Dir).
|
||||
|
||||
|
||||
start_gui(State = #s{key = #key{id = ID}}) ->
|
||||
start_gui(State = #s{acc = none}) ->
|
||||
Window = gmc_gui:start_link(#{}),
|
||||
ok = gmc_gui:set_account(ID),
|
||||
ok = gmc_gui:ask_conf(),
|
||||
State#s{window = Window};
|
||||
start_gui(State) ->
|
||||
Window = gmc_gui:start_link(#{}),
|
||||
@ -185,11 +152,10 @@ start_gui(State) ->
|
||||
%%% gen_server Message Handling Callbacks
|
||||
|
||||
|
||||
handle_call(end_setup, _, State) ->
|
||||
NewState = end_setup(State),
|
||||
{reply, ok, NewState};
|
||||
handle_call(network, _, State = #s{network = Network}) ->
|
||||
{reply, Network, State};
|
||||
handle_call(conf, _, State = #s{acc = Acc, keys = Keys, network = Network}) ->
|
||||
{reply, {Acc, Keys, Network}, State};
|
||||
handle_call(bin_dir, _, State = #s{exec_dir = BinDir}) ->
|
||||
{reply, BinDir, State};
|
||||
handle_call(Unexpected, From, State) ->
|
||||
@ -197,15 +163,6 @@ handle_call(Unexpected, From, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
|
||||
handle_cast({unlock, Phrase}, State) ->
|
||||
NewState = unlock(Phrase, State),
|
||||
{noreply, NewState};
|
||||
handle_cast({make_key, Phrase, Network}, State) ->
|
||||
NewState = make_key(Phrase, Network, State),
|
||||
{noreply, NewState};
|
||||
handle_cast({load_key, Phrase, Mnemonic, Network}, State) ->
|
||||
NewState = load_key(Phrase, Mnemonic, Network, State),
|
||||
{noreply, NewState};
|
||||
handle_cast(start_stop, State) ->
|
||||
ok = do_start_stop(State),
|
||||
{noreply, State};
|
||||
@ -233,8 +190,9 @@ code_change(_, State, _) ->
|
||||
{ok, State}.
|
||||
|
||||
|
||||
terminate(Reason, _) ->
|
||||
terminate(Reason, State) ->
|
||||
ok = log(info, "Reason: ~p,", [Reason]),
|
||||
ok = persist(State),
|
||||
case whereis(gd_con) of
|
||||
undefined ->
|
||||
zx:stop();
|
||||
@ -253,92 +211,7 @@ do_stop() ->
|
||||
|
||||
%%% Doers
|
||||
|
||||
unlock(Phrase, State = #s{key = {blob, Cipher}}) ->
|
||||
Pass = pass(unicode:characters_to_binary(Phrase)),
|
||||
case decrypt(Pass, Cipher) of
|
||||
{ok, Binary} ->
|
||||
{ok, #wallet{keys = Keys}} = zx_lib:b_to_t(Binary),
|
||||
Name = gm_name(),
|
||||
Unlocked = #key{id = ID, pair = Pair} = lists:keyfind(Name, #key.name, Keys),
|
||||
#{secret := Secret} = Pair,
|
||||
Encrypted = Pair#{secret => encrypt(Pass, Secret)},
|
||||
ok = gmc_gui:set_account(ID),
|
||||
State#s{key = Unlocked#key{pair = Encrypted}, pass = Pass};
|
||||
{error, bad_password} ->
|
||||
ok = gmc_gui:ask_passphrase(),
|
||||
State
|
||||
end.
|
||||
|
||||
|
||||
make_key(Phrase, Network, State) ->
|
||||
{ID, Pair = #{secret := <<K:32/binary, _/binary>>}} = hz_key_master:make_key(<<>>),
|
||||
Mnemonic = hz_key_master:encode(K),
|
||||
ok = gmc_setup:done(Mnemonic),
|
||||
finalize_key(Phrase, ID, Pair, Network, State).
|
||||
|
||||
|
||||
load_key(Phrase, Mnemonic, Network, State) ->
|
||||
case hz_key_master:decode(Mnemonic) of
|
||||
{ok, Secret} ->
|
||||
{ID, Pair} = hz_key_master:make_key(Secret),
|
||||
ok = gmc_setup:done(),
|
||||
finalize_key(Phrase, ID, Pair, Network, State);
|
||||
Error ->
|
||||
ok = gmc_setup:trouble(Error),
|
||||
State
|
||||
end.
|
||||
|
||||
|
||||
finalize_key(Phrase, ID, Pair, Network, State) ->
|
||||
NetBin = atom_to_binary(Network),
|
||||
Pass =
|
||||
case Phrase =:= "" of
|
||||
false -> pass(unicode:characters_to_binary(Phrase));
|
||||
true -> none
|
||||
end,
|
||||
Key = #key{id = ID} = add_wallet(Pass, ID, Pair, NetBin),
|
||||
State#s{key = Key, pass = Pass, network = NetBin}.
|
||||
|
||||
|
||||
add_wallet(Pass, ID, Pair = #{secret := Secret}, Network) ->
|
||||
GDPrefsPath = gd_prefs_path(),
|
||||
GDPrefs =
|
||||
case file:consult(GDPrefsPath) of
|
||||
{ok, Prefs} -> proplists:to_map(Prefs);
|
||||
{error, enoent} -> #{}
|
||||
end,
|
||||
Wallets = gd_get_prefs(wallets, GDPrefs, []),
|
||||
WalletPath = gajumining_wallet(),
|
||||
Created = #key{name = gm_name(), id = ID, pair = Pair},
|
||||
Net = #net{id = Network},
|
||||
ChainID = <<"groot.", Network/binary>>,
|
||||
Node = #node{ip = unicode:characters_to_list(lists:join($., ["groot", Network, "gajumaru", "io"]))},
|
||||
New = #wallet{name = gm_name(),
|
||||
poas = [#poa{name = gm_name(), id = ID}],
|
||||
keys = [Created],
|
||||
chain_id = ChainID,
|
||||
endpoint = Node,
|
||||
nets = [Net]},
|
||||
{WalletBin, KeyPair, HasPass} =
|
||||
case Pass =:= none of
|
||||
false -> {encrypt(Pass, term_to_binary(New)), Pair#{secret => {cipher, encrypt(Pass, Secret)}}, true};
|
||||
true -> {term_to_binary(New), Pair, false}
|
||||
end,
|
||||
Entry = #wr{name = gm_name(), path = WalletPath, pass = HasPass},
|
||||
NewWallets = lists:keystore(gm_name(), #wr.name, Wallets, Entry),
|
||||
NewGDPrefs = gd_put_prefs(wallets, NewWallets, GDPrefs),
|
||||
ok = file:write_file(WalletPath, WalletBin),
|
||||
ok = zx_lib:write_terms(GDPrefsPath, proplists:from_map(NewGDPrefs)),
|
||||
Created#key{pair = KeyPair}.
|
||||
|
||||
|
||||
end_setup(State = #s{window = Window}) ->
|
||||
PID = wx_object:get_pid(Window),
|
||||
true = unlink(PID),
|
||||
start_gui(State#s{window = none}).
|
||||
|
||||
|
||||
do_start_stop(#s{key = #key{id = PubKey}, network = Network}) ->
|
||||
do_start_stop(#s{acc = PubKey, network = Network, mem_limit = MemLimit}) ->
|
||||
% smrt guy stuff happens here
|
||||
{Bits, Eureka} =
|
||||
case Network of
|
||||
@ -365,7 +238,7 @@ do_start_stop(#s{key = #key{id = PubKey}, network = Network}) ->
|
||||
end
|
||||
end,
|
||||
Miner = unicode:characters_to_binary([Fatness, Bits, "-", Type]),
|
||||
Count = optimize_count(),
|
||||
Count = optimize_count(MemLimit),
|
||||
Instance = #{<<"executable">> => Miner, <<"executable_group">> => <<"gajumine">>},
|
||||
Workers = lists:duplicate(Count, Instance),
|
||||
Profile =
|
||||
@ -387,7 +260,7 @@ do_start_stop(#s{key = #key{id = PubKey}, network = Network}) ->
|
||||
disconnected],
|
||||
lists:foreach(fun gmhc_events:ensure_subscribed/1, Events).
|
||||
|
||||
optimize_count() ->
|
||||
optimize_count(MemLimit) ->
|
||||
{Procs, Memory} =
|
||||
case os:type() of
|
||||
{unix, linux} ->
|
||||
@ -404,7 +277,7 @@ optimize_count() ->
|
||||
M = list_to_integer(string:strip(lists:nth(2, string:split(os:cmd("wmic computersystem get TotalPhysicalMemory"), "\r\r\n", all)))),
|
||||
{P, M}
|
||||
end,
|
||||
MeanMaps = Memory div 3550722201,
|
||||
MeanMaps = min(MemLimit, Memory) div 3550722201,
|
||||
Recommended = max(min(Procs, MeanMaps) - 1, 1),
|
||||
Notice = fun(F, A) -> gmc_gui:message({notice, io_lib:format(F, A)}) end,
|
||||
ok = Notice("Physical Processors: ~p", [Procs]),
|
||||
@ -436,60 +309,28 @@ run_gajudesk() ->
|
||||
|
||||
%%% Utils
|
||||
|
||||
%% Encryption stuff
|
||||
% TODO: Expose these from GD itself
|
||||
|
||||
encrypt(Pass, Binary) ->
|
||||
Flags = [{encrypt, true}, {padding, pkcs_padding}],
|
||||
crypto:crypto_one_time(aes_256_ecb, Pass, Binary, Flags).
|
||||
|
||||
|
||||
decrypt(Pass, Binary) ->
|
||||
Flags = [{encrypt, false}, {padding, pkcs_padding}],
|
||||
try
|
||||
{ok, crypto:crypto_one_time(aes_256_ecb, Pass, Binary, Flags)}
|
||||
catch
|
||||
error:{error, L, "Can't finalize"} ->
|
||||
ok = log(info, "Decrypt failed at ~p", [L]),
|
||||
{error, bad_password};
|
||||
E:R ->
|
||||
{E, R}
|
||||
end.
|
||||
|
||||
|
||||
pass(Phrase) ->
|
||||
crypto:hash(sha3_256, Phrase).
|
||||
|
||||
|
||||
%% Paths and Names
|
||||
|
||||
gm_name() ->
|
||||
"GajuMine".
|
||||
|
||||
gajumining_wallet() ->
|
||||
filename:join(zx_lib:path(var, "otpr", "gajudesk"), "gajumining.gaju").
|
||||
persist(#s{network = Network, acc = Acc, keys = Keys, mem_limit = MemLimit, prefs = Prefs}) ->
|
||||
Update = #{network => Network, account => Acc, keys => Keys, mem_limit => MemLimit},
|
||||
Conf = maps:to_list(maps:merge(Prefs, Update)),
|
||||
Path = gmc_prefs_path(),
|
||||
ok = filelib:ensure_dir(Path),
|
||||
zx_lib:write_terms(Path, Conf).
|
||||
|
||||
|
||||
gd_prefs_path() ->
|
||||
filename:join(zx_lib:path(etc, "otpr", "gajudesk"), "prefs.eterms").
|
||||
|
||||
|
||||
%% GajuDesk Prefs
|
||||
% TODO: Glob these into a gd_prefs module exposed from GD itself
|
||||
|
||||
gd_get_prefs(K, M, D) ->
|
||||
P = maps:get(gd_con, M, #{}),
|
||||
maps:get(K, P, D).
|
||||
|
||||
|
||||
gd_put_prefs(K, V, M) ->
|
||||
P = maps:get(gd_con, M, #{}),
|
||||
NewP = maps:put(K, V, P),
|
||||
maps:put(gd_con, NewP, M).
|
||||
|
||||
|
||||
gd_read_prefs() ->
|
||||
case file:consult(gd_prefs_path()) of
|
||||
{ok, Prefs} -> proplists:to_map(Prefs);
|
||||
{error, enoent} -> #{}
|
||||
read_conf() ->
|
||||
Path = gmc_prefs_path(),
|
||||
case file:consult(Path) of
|
||||
{ok, Conf} ->
|
||||
{ok, maps:from_list(Conf)};
|
||||
{error, enoent} ->
|
||||
none;
|
||||
{error, Other} ->
|
||||
ok = log(info, "Path ~p could not be read. Failed with ~p. Continuing.", [Path, Other]),
|
||||
none
|
||||
end.
|
||||
|
||||
gmc_prefs_path() ->
|
||||
filename:join(zx_lib:path(etc, "qpq", "gajumine"), "prefs.eterms").
|
||||
|
117
src/gmc_gui.erl
117
src/gmc_gui.erl
@ -3,14 +3,14 @@
|
||||
%%% @end
|
||||
|
||||
-module(gmc_gui).
|
||||
-vsn("0.1.4").
|
||||
-vsn("0.2.0").
|
||||
-author("Craig Everett <craigeverett@qpq.swiss>").
|
||||
-copyright("Craig Everett <craigeverett@qpq.swiss>").
|
||||
-license("GPL-3.0-or-later").
|
||||
|
||||
-behavior(wx_object).
|
||||
-include_lib("wx/include/wx.hrl").
|
||||
-export([ask_passphrase/0, set_account/1, difficulty/1, speed/1, candidate/1, message/1]).
|
||||
-export([ask_conf/0, set_account/1, difficulty/1, speed/1, candidate/1, message/1]).
|
||||
-export([start_link/1]).
|
||||
-export([init/1, terminate/2, code_change/3,
|
||||
handle_call/3, handle_cast/2, handle_info/2, handle_event/2]).
|
||||
@ -34,7 +34,7 @@
|
||||
candy = none :: none | wx:wx_object(),
|
||||
height = none :: none | wx:wx_object(),
|
||||
block = none :: none | wx:wx_object(),
|
||||
% solved = 0 :: non_neg_integer(), % Add a widget to show this. Maybe
|
||||
% solved = 0 :: non_neg_integer(), % TODO: Add a widget to show this. Maybe
|
||||
mess = none :: none | wx:wx_object(),
|
||||
buff = new_buff() :: buff(),
|
||||
buttons = [] :: [#w{}]}).
|
||||
@ -55,8 +55,8 @@ new_buff() ->
|
||||
|
||||
%%% Interface functions
|
||||
|
||||
ask_passphrase() ->
|
||||
wx_object:cast(?MODULE, ask_passphrase).
|
||||
ask_conf() ->
|
||||
wx_object:cast(?MODULE, ask_conf).
|
||||
|
||||
|
||||
set_account(ID) ->
|
||||
@ -102,7 +102,7 @@ init(Prefs) ->
|
||||
Labels = [J("ID"), J("Target"), J("Maps/s"), J("Candidate"), J("Height"), J("BlockHash")],
|
||||
{Grid, [ID_C, DiffC, PerfC, CandyC, HeightC, BlockC]} = display_box(Frame, Labels),
|
||||
|
||||
Style = ?wxTE_MULTILINE bor ?wxTE_READONLY,
|
||||
Style = ?wxDEFAULT bor ?wxTE_MULTILINE bor ?wxTE_READONLY,
|
||||
MessSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Messages")}]),
|
||||
MessC = wxTextCtrl:new(Frame, ?wxID_ANY, [{style, Style}]),
|
||||
_ = wxStaticBoxSizer:add(MessSz, MessC, zxw:flags(wide)),
|
||||
@ -111,7 +111,8 @@ init(Prefs) ->
|
||||
[{start_stop, J("Start")},
|
||||
{gajudesk, J("Open Wallet")},
|
||||
{eureka, J("GajuMining")},
|
||||
{explorer, J("ChainExplorer")}],
|
||||
{explorer, J("ChainExplorer")},
|
||||
{conf, J("Configure")}],
|
||||
|
||||
MakeButton =
|
||||
fun({Name, Label}) ->
|
||||
@ -167,8 +168,8 @@ handle_call(Unexpected, From, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
|
||||
handle_cast(ask_passphrase, State) ->
|
||||
ok = ask_passphrase(State),
|
||||
handle_cast(ask_conf, State) ->
|
||||
ok = conf(State),
|
||||
{noreply, State};
|
||||
handle_cast({set_account, ID}, State) ->
|
||||
ok = set_account(ID, State),
|
||||
@ -203,6 +204,7 @@ handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID},
|
||||
#w{name = gajudesk} -> gajudesk(State);
|
||||
#w{name = eureka} -> eureka(State);
|
||||
#w{name = explorer} -> explorer(State);
|
||||
#w{name = conf} -> conf(State);
|
||||
false -> State
|
||||
end,
|
||||
{noreply, NewState};
|
||||
@ -223,34 +225,6 @@ terminate(Reason, State) ->
|
||||
wx:destroy().
|
||||
|
||||
|
||||
ask_passphrase(#s{frame = Frame, j = J}) ->
|
||||
Label = J("Unlock Account"),
|
||||
Dialog = wxDialog:new(Frame, ?wxID_ANY, Label, [{size, {500, 115}}]),
|
||||
Sizer = wxBoxSizer:new(?wxVERTICAL),
|
||||
PassSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Password")}]),
|
||||
PassTx = wxTextCtrl:new(Dialog, ?wxID_ANY, [{style, ?wxTE_PASSWORD}]),
|
||||
_ = wxStaticBoxSizer:add(PassSz, PassTx, zxw:flags(wide)),
|
||||
ButtSz = wxBoxSizer:new(?wxHORIZONTAL),
|
||||
Affirm = wxButton:new(Dialog, ?wxID_OK),
|
||||
Cancel = wxButton:new(Dialog, ?wxID_CANCEL),
|
||||
_ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags(wide)),
|
||||
_ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags(wide)),
|
||||
_ = wxBoxSizer:add(Sizer, PassSz, zxw:flags(base)),
|
||||
_ = wxBoxSizer:add(Sizer, ButtSz, zxw:flags(wide)),
|
||||
ok = wxDialog:setSizer(Dialog, Sizer),
|
||||
ok = wxBoxSizer:layout(Sizer),
|
||||
ok = wxFrame:center(Dialog),
|
||||
ok =
|
||||
case wxDialog:showModal(Dialog) of
|
||||
?wxID_OK ->
|
||||
Phrase = wxTextCtrl:getValue(PassTx),
|
||||
gmc_con:unlock(Phrase);
|
||||
?wxID_CANCEL ->
|
||||
retire(Frame)
|
||||
end,
|
||||
wxDialog:destroy(Dialog).
|
||||
|
||||
|
||||
set_account(ID, #s{id = Widget}) ->
|
||||
wxStaticText:setLabel(Widget, ID).
|
||||
|
||||
@ -364,7 +338,9 @@ add_message2(Entry, {OMax, 0, IMax, 0, []}) ->
|
||||
{append, {OMax, 1, IMax, 1, [[Entry]]}}.
|
||||
|
||||
|
||||
start_stop(State) ->
|
||||
start_stop(State = #s{buttons = Buttons}) ->
|
||||
#w{wx = SSB} = lists:keyfind(start_stop, #w.name, Buttons),
|
||||
_ = wxButton:disable(SSB),
|
||||
ok = gmc_con:start_stop(),
|
||||
State.
|
||||
|
||||
@ -401,7 +377,70 @@ explorer_url() ->
|
||||
none -> "https://groot.mainnet.gajumaru.io";
|
||||
Network -> unicode:characters_to_list(["https://groot.", Network, ".gajumaru.io"])
|
||||
end.
|
||||
|
||||
|
||||
|
||||
conf(State = #s{frame = Frame, j = J}) ->
|
||||
Outcome = conf(Frame, J),
|
||||
ok = tell("Outcome: ~p", [Outcome]),
|
||||
State.
|
||||
|
||||
conf(Frame, J) ->
|
||||
{Acc, Keys, NetNum} = get_conf(),
|
||||
Label = J("Configure GajuMine"),
|
||||
Dialog = wxDialog:new(Frame, ?wxID_ANY, Label, [{size, {400, 400}}]),
|
||||
Sizer = wxBoxSizer:new(?wxVERTICAL),
|
||||
Network = wxRadioBox:new(Dialog, ?wxID_ANY, J("Network"), {0, 0}, {50, 50}, [J("Mainnet"), J("Testnet")]),
|
||||
ok = wxRadioBox:setSelection(Network, NetNum),
|
||||
GMAccSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("GajuMining Account ID")}]),
|
||||
GMAccTx = wxTextCtrl:new(Dialog, ?wxID_ANY, [{style, ?wxTE_PASSWORD}, {value, Acc}]),
|
||||
_ = wxStaticBoxSizer:add(GMAccSz, GMAccTx, zxw:flags(wide)),
|
||||
AccsSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Additional Account IDs (optional)")}]),
|
||||
AccsTx = wxTextCtrl:new(Dialog, ?wxID_ANY, [{style, ?wxTE_MULTILINE}, {value, Keys}]),
|
||||
_ = wxStaticBoxSizer:add(AccsSz, AccsTx, zxw:flags(wide)),
|
||||
ButtSz = wxBoxSizer:new(?wxHORIZONTAL),
|
||||
Affirm = wxButton:new(Dialog, ?wxID_OK),
|
||||
Cancel = wxButton:new(Dialog, ?wxID_CANCEL),
|
||||
_ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags(wide)),
|
||||
_ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags(wide)),
|
||||
_ = wxBoxSizer:add(Sizer, Network, zxw:flags(base)),
|
||||
_ = wxBoxSizer:add(Sizer, GMAccSz, zxw:flags(base)),
|
||||
_ = wxBoxSizer:add(Sizer, AccsSz, zxw:flags(base)),
|
||||
_ = wxBoxSizer:add(Sizer, ButtSz, zxw:flags(wide)),
|
||||
ok = wxDialog:setSizer(Dialog, Sizer),
|
||||
ok = wxBoxSizer:layout(Sizer),
|
||||
ok = wxFrame:center(Dialog),
|
||||
Outcome =
|
||||
case wxDialog:showModal(Dialog) of
|
||||
?wxID_OK ->
|
||||
Net =
|
||||
case wxRadioBox:getSelection(Network) of
|
||||
0 -> <<"mainnet">>;
|
||||
1 -> <<"testnet">>;
|
||||
_ -> <<"mainnet">>
|
||||
end,
|
||||
AccID = wxTextCtrl:getValue(GMAccTx),
|
||||
MOAR_IDs = wxTextCtrl:getValue(AccsTx),
|
||||
{Net, AccID, MOAR_IDs};
|
||||
?wxID_CANCEL ->
|
||||
cancel
|
||||
end,
|
||||
ok = wxDialog:destroy(Dialog),
|
||||
Outcome.
|
||||
|
||||
get_conf() ->
|
||||
{ID, List, Network} = gmc_con:conf(),
|
||||
{acc(ID), keys(List), net_num(Network)}.
|
||||
|
||||
acc(none) -> "";
|
||||
acc(AKID) -> AKID.
|
||||
|
||||
keys(List) ->
|
||||
unicode:characters_to_list(lists:join("\n", List)).
|
||||
|
||||
net_num(<<"mainnet">>) -> 0;
|
||||
net_num(<<"testnet">>) -> 1;
|
||||
net_num(_) -> 0.
|
||||
|
||||
|
||||
open_browser(Frame, J, URL) ->
|
||||
case wx_misc:launchDefaultBrowser(URL) of
|
||||
|
@ -12,7 +12,7 @@
|
||||
%%% @end
|
||||
|
||||
-module(gmc_setup).
|
||||
-vsn("0.1.4").
|
||||
-vsn("0.2.0").
|
||||
-author("Craig Everett <craigeverett@qpq.swiss>").
|
||||
-copyright("Craig Everett <craigeverett@qpq.swiss>").
|
||||
-license("GPL-3.0-or-later").
|
||||
@ -190,7 +190,7 @@ new_key(Frame, J) ->
|
||||
_ = wxBoxSizer:add(Sizer, PassSz2, zxw:flags(base)),
|
||||
_ = wxBoxSizer:add(Sizer, ButtSz, zxw:flags(wide)),
|
||||
ok = wxDialog:setSizer(Dialog, Sizer),
|
||||
ok = wxDialog:setSize(Dialog, {400, 250}),
|
||||
ok = wxDialog:setSize(Dialog, {400, 300}),
|
||||
ok = wxBoxSizer:layout(Sizer),
|
||||
ok = wxFrame:center(Dialog),
|
||||
Outcome =
|
||||
|
@ -12,7 +12,7 @@
|
||||
%%% @end
|
||||
|
||||
-module(gmc_sup).
|
||||
-vsn("0.1.4").
|
||||
-vsn("0.2.0").
|
||||
-behaviour(supervisor).
|
||||
-author("Craig Everett <craigeverett@qpq.swiss>").
|
||||
-copyright("Craig Everett <craigeverett@qpq.swiss>").
|
||||
|
@ -4,7 +4,7 @@
|
||||
{author,"Craig Everett"}.
|
||||
{prefix,"gmc"}.
|
||||
{desc,"Mining client for the Gajumaru Root"}.
|
||||
{package_id,{"qpq","gajumine",{0,1,4}}}.
|
||||
{package_id,{"qpq","gajumine",{0,2,0}}}.
|
||||
{deps,[{"uwiger","gmconfig",{0,1,2}},
|
||||
{"uwiger","gproc",{1,0,1}},
|
||||
{"uwiger","gmhive_client",{0,2,1}},
|
||||
|
Loading…
x
Reference in New Issue
Block a user