255 lines
7.5 KiB
Erlang
255 lines
7.5 KiB
Erlang
%%% @doc
|
|
%%% GajuMine Configuration GUI
|
|
%%% @end
|
|
|
|
-module(gmc_conf).
|
|
-vsn("0.2.5").
|
|
-author("Craig Everett <craigeverett@qpq.swiss>").
|
|
-copyright("QPQ AG <craigeverett@qpq.swiss>").
|
|
-license("GPL-3.0-or-later").
|
|
|
|
-behavior(wx_object).
|
|
-include_lib("wx/include/wx.hrl").
|
|
-export([to_front/0, trouble/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]).
|
|
-include("$zx_include/zx_logger.hrl").
|
|
|
|
|
|
-record(s,
|
|
{wx = none :: none | wx:wx_object(),
|
|
frame = none :: none | wx:wx_object(),
|
|
lang = en :: en | jp,
|
|
j = none :: none | fun(),
|
|
net = none :: none | wx:wx_object(),
|
|
acc = none :: none | wx:wx_object(),
|
|
keys = none :: none | wx:wx_object(),
|
|
cores = none :: none | wx:wx_object(),
|
|
memory = none :: none | wx:wx_object()}).
|
|
|
|
|
|
|
|
%%% Interface functions
|
|
|
|
|
|
-spec to_front() -> ok.
|
|
|
|
to_front() ->
|
|
wx_object:cast(?MODULE, to_front).
|
|
|
|
|
|
-spec trouble(term()) -> ok.
|
|
|
|
trouble(Info) ->
|
|
wx_object:cast(?MODULE, {trouble, Info}).
|
|
|
|
|
|
|
|
%%% Startup Functions
|
|
|
|
start_link(Prefs) ->
|
|
wx_object:start_link({local, ?MODULE}, ?MODULE, Prefs, []).
|
|
|
|
init({Prefs, {Net, Acc, Keys, {AProcs, AMem, MProcs, MMem}}}) ->
|
|
ok = log(info, "GUI starting..."),
|
|
Lang = maps:get(lang, Prefs, en_US),
|
|
Trans = gd_jt:read_translations(?MODULE),
|
|
J = gd_jt:j(Lang, Trans),
|
|
Label = J("Configure GajuMine"),
|
|
|
|
WX = wx:new(),
|
|
Frame = wxFrame:new(WX, ?wxID_ANY, Label),
|
|
MainSz = wxBoxSizer:new(?wxVERTICAL),
|
|
|
|
AccSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("GajuMining Account ID")}]),
|
|
AccTx = wxTextCtrl:new(Frame, ?wxID_ANY, [{value, acc(Acc)}]),
|
|
_ = wxStaticBoxSizer:add(AccSz, AccTx, wide(5)),
|
|
KeysSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Additional Account IDs (optional)")}]),
|
|
KeysTx = wxTextCtrl:new(Frame, ?wxID_ANY, [{style, ?wxTE_MULTILINE}, {value, keys(Keys)}]),
|
|
_ = wxStaticBoxSizer:add(KeysSz, KeysTx, wide(5)),
|
|
StatSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Max System Committment (optional)")}]),
|
|
AProcsS = i_to_l(AProcs),
|
|
MProcsS = i_to_l(MProcs),
|
|
AMemS = gigs(AMem),
|
|
MMemS = gigs(MMem),
|
|
Labels = [{J("HW Cores"), J("Max Cores"), AProcsS, MProcsS}, {J("Memory (GB)"), J("Max Memory"), AMemS, MMemS}],
|
|
{Grid, [CoresTx, MemoryTx]} = display_box(Frame, Labels),
|
|
Network = wxRadioBox:new(Frame, ?wxID_ANY, J("Network"), {0, 0}, {50, 50}, [J("Mainnet"), J("Testnet")]),
|
|
ok = wxRadioBox:setSelection(Network, net_num(Net)),
|
|
|
|
ButtSz = wxBoxSizer:new(?wxHORIZONTAL),
|
|
Affirm = wxButton:new(Frame, ?wxID_OK),
|
|
Cancel = wxButton:new(Frame, ?wxID_CANCEL),
|
|
_ = wxBoxSizer:add(StatSz, Grid, wide(5)),
|
|
_ = wxBoxSizer:add(ButtSz, Affirm, wide(5)),
|
|
_ = wxBoxSizer:add(ButtSz, Cancel, wide(5)),
|
|
_ = wxBoxSizer:add(MainSz, AccSz, base(5)),
|
|
_ = wxBoxSizer:add(MainSz, KeysSz, wide(5)),
|
|
_ = wxBoxSizer:add(MainSz, StatSz, base(5)),
|
|
_ = wxBoxSizer:add(MainSz, Network, base(5)),
|
|
_ = wxBoxSizer:add(MainSz, ButtSz, base(5)),
|
|
ok = wxFrame:setSizer(Frame, MainSz),
|
|
ok = wxBoxSizer:layout(MainSz),
|
|
ok = wxFrame:connect(Frame, command_button_clicked),
|
|
ok = wxFrame:connect(Frame, close_window),
|
|
ok = wxFrame:setSize(Frame, {500, 500}),
|
|
ok = wxFrame:center(Frame),
|
|
true = wxFrame:show(Frame),
|
|
State =
|
|
#s{wx = WX, frame = Frame,
|
|
lang = Lang, j = J,
|
|
net = Network, acc = AccTx, keys = KeysTx,
|
|
cores = CoresTx, memory = MemoryTx},
|
|
{Frame, State}.
|
|
|
|
|
|
i_to_l(none) -> "0";
|
|
i_to_l(N) when is_integer(N) -> integer_to_list(N).
|
|
|
|
|
|
base(Padding) -> [{proportion, 0}, {flag, ?wxEXPAND bor ?wxALL}, {border, Padding}].
|
|
|
|
wide(Padding) -> [{proportion, 1}, {flag, ?wxEXPAND bor ?wxALL}, {border, Padding}].
|
|
|
|
center() -> [{proportion, 0}, {flag, ?wxEXPAND bor ?wxALIGN_CENTER_VERTICAL}].
|
|
|
|
gigs(none) ->
|
|
"0";
|
|
gigs(Bytes) ->
|
|
float_to_list(Bytes / gig(), [{decimals, 2}, compact]).
|
|
|
|
gig() -> 1_073_741_824.
|
|
|
|
display_box(Parent, Labels) ->
|
|
Grid = wxFlexGridSizer:new(2, 4, 4),
|
|
ok = wxFlexGridSizer:setFlexibleDirection(Grid, ?wxHORIZONTAL),
|
|
ok = wxFlexGridSizer:addGrowableCol(Grid, 1),
|
|
Make =
|
|
fun({SO, SI, VS, VM}) ->
|
|
LO = [SO, ":"],
|
|
LI = [SI, ":"],
|
|
T_LO = wxStaticText:new(Parent, ?wxID_ANY, LO),
|
|
T_CO = wxStaticText:new(Parent, ?wxID_ANY, VS, [{style, ?wxALIGN_LEFT}]),
|
|
T_LI = wxStaticText:new(Parent, ?wxID_ANY, LI),
|
|
T_CI = wxTextCtrl:new(Parent, ?wxID_ANY, [{value, VM}]),
|
|
_ = wxFlexGridSizer:add(Grid, T_LO, center()),
|
|
_ = wxFlexGridSizer:add(Grid, T_CO, center()),
|
|
_ = wxFlexGridSizer:add(Grid, T_LI, center()),
|
|
_ = wxFlexGridSizer:add(Grid, T_CI, zxw:flags(wide)),
|
|
T_CI
|
|
end,
|
|
Controls = lists:map(Make, Labels),
|
|
{Grid, Controls}.
|
|
|
|
|
|
|
|
handle_call(Unexpected, From, State) ->
|
|
ok = log(warning, "Unexpected call from ~tp: ~tp~n", [From, Unexpected]),
|
|
{noreply, State}.
|
|
|
|
|
|
handle_cast(to_front, State = #s{frame = Frame}) ->
|
|
ok = wxFrame:raise(Frame),
|
|
{noreply, State};
|
|
handle_cast({trouble, Info}, State) ->
|
|
ok = handle_troubling(State, Info),
|
|
{noreply, State};
|
|
handle_cast(Unexpected, State) ->
|
|
ok = log(warning, "Unexpected cast: ~tp~n", [Unexpected]),
|
|
{noreply, State}.
|
|
|
|
|
|
handle_info(Unexpected, State) ->
|
|
ok = log(warning, "Unexpected info: ~tp~n", [Unexpected]),
|
|
{noreply, State}.
|
|
|
|
|
|
handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID}, State) ->
|
|
ok =
|
|
case ID of
|
|
?wxID_OK -> done(State);
|
|
?wxID_CANCEL -> buh_bye(State)
|
|
end,
|
|
{noreply, State};
|
|
handle_event(#wx{event = #wxClose{}}, State) ->
|
|
ok = buh_bye(State),
|
|
{noreply, State};
|
|
handle_event(Event, State) ->
|
|
ok = tell(info, "Unexpected event ~tp State: ~tp~n", [Event, State]),
|
|
{noreply, State}.
|
|
|
|
|
|
handle_troubling(#s{frame = Frame}, Info) ->
|
|
zxw:show_message(Frame, Info).
|
|
|
|
|
|
code_change(_, State, _) ->
|
|
{ok, State}.
|
|
|
|
|
|
terminate(Reason, State) ->
|
|
ok = log(info, "Reason: ~tp, State: ~tp", [Reason, State]),
|
|
wx:destroy().
|
|
|
|
buh_bye(#s{frame = Frame}) ->
|
|
wxWindow:destroy(Frame).
|
|
|
|
|
|
%%% Doers
|
|
|
|
done(State = #s{net = Network, acc = AccTx, keys = KeysTx, cores = CoresTx, memory = MemTx}) ->
|
|
Net =
|
|
case wxRadioBox:getSelection(Network) of
|
|
0 -> <<"mainnet">>;
|
|
1 -> <<"testnet">>;
|
|
_ -> <<"mainnet">>
|
|
end,
|
|
AccID = wxTextCtrl:getValue(AccTx),
|
|
MOAR_IDs = wxTextCtrl:getValue(KeysTx),
|
|
CoreS = wxTextCtrl:getValue(CoresTx),
|
|
GigsS = wxTextCtrl:getValue(MemTx),
|
|
ok = gmc_con:conf({Net, list_to_binary(AccID), binify_keys(MOAR_IDs), cores(CoreS), bytes(GigsS)}),
|
|
buh_bye(State).
|
|
|
|
cores("") ->
|
|
none;
|
|
cores(CoreS) ->
|
|
try
|
|
list_to_integer(CoreS)
|
|
catch
|
|
_:_ -> none
|
|
end.
|
|
|
|
bytes("") ->
|
|
none;
|
|
bytes(GigsS) ->
|
|
try
|
|
list_to_integer(GigsS) * gig()
|
|
catch
|
|
_:_ ->
|
|
try
|
|
trunc(list_to_float(GigsS) * gig())
|
|
catch
|
|
_:_ -> none
|
|
end
|
|
end.
|
|
|
|
|
|
% NOTE: 32 is space, 12288 is full-width space.
|
|
binify_keys(MOAR) ->
|
|
[list_to_binary(K) || K <- string:lexemes(MOAR, [$\r, $\n, 32, 12288, $\t, $,, $;])].
|
|
|
|
|
|
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.
|