macOS moves "dangerous" applications into a read-only [/private]
filesystem. This messes up with the updater and default P2Pool and
XMRig paths.
If [/private] is detected, show a panic screen upon Gupax startup
telling the user to move it to [/Applications]. This _seems_ to
make macOS relax a little (after an arbitrary amount of time...)
Includes some small fixes:
- [localhost] will always be changed to [127.0.0.1] in the case
of XMRig (it doesn't understand localhost by itself)
- P2Pool/XMRig API path now checks for a [/] or [\]
and correctly applies the endpoint, e.g:
BASEPATH = "/home/hinto/p2pool"
ENDPOINT = "local/stats"
if BASEPATH doesn't end with '/' { BASEPATH.push('/') }
API_PATH = BASEPATH + ENDPOINT ("/home/hinto/p2pool/local/stats")
- P2Pool payout line got changed in: be18ad4177
The regex is now a more generic: [payout of [0-9].[0-9]+ XMR]
If user clicked the [X] or [ALT+F4] while on the [ask_before_quit]
screen, it'll actually exit now.
The [save_before_quit] option actually... saves before quitting now.
No cloning since we're exiting and no [ErrorState] setting on errors.
The console logs will show if a save error happens.
Keyboard shortcuts [Left] & [Right] were clobbering the
[TextEdit] left/right movement, so they are now [Z/X].
The shortcuts also look to make sure a TextEdit isn't
in focus so that [S/R/Z/X] can actually be typed.
P2Pool/XMRig now make sure the path ends with an [ACCEPTABLE_*]
value (e.g: P2pool, P2POOL) before enabling the [Start] UI.
In XMRig Advanced the color/checkmark code was being given [self.name]
instead of [self.rig] which caused them to be linked, e.g: you clear
"Name" and [Rig] goes red instead.
(Stupid) Problem (caused by me):
--------------------------------
Up to 56million bytes of P2Pool/XMRig output were being held in memory
so they could be parsed. P2Pool output is the only one that needs
parsing as well, so double bad.
(Obvious) Solution:
-------------------
For XMRig:
Just don't write to an extra [String] buffer.
For P2Pool:
Parse the output, then... toss it out? You don't need the output
anymore after you parsed the values out, e.g: `Payouts`, `XMR Mined`.
Once they are parsed, add them to the current values instead of
completely overwriting them and then toss out the log buffer.
Now Gupax doesn't use stupid amounts of memory holding what is
essentially dead logs we already parsed. The parsing will be a lot
cheaper too since we aren't parsing the entire thing over and over
again (it was already pretty fast though).
Fixes:
- Up/Down only work if UI is enabled
- Re-pushed [P2POOL_API_PATH] to popped relative path
but only after giving the popped path to P2Pool
1. [/tmp/gupax/p2pool/p2pool] -> [/tmp/gupax/p2pool]
2. Give that to P2Pool
3. [/tmp/gupax/p2pool] -> [/tmp/gupax/p2pool/local/stats]
4. Give that to the watchdog (so it can read it)
There was a deadlock happening between the [Helper]'s [gui_api_p2pool]
and the GUI's [gui_api_p2pool], since the locking order was different.
The watchdog loop locking order was fixed as well. This was a pain to
track down, better than a data race... I guess.
Oh and keyboard shortcuts were added in this commit too.
Comment from code:
// The ordering of these locks is _very_ important. They MUST be in sync
// with how the main GUI thread locks stuff or a deadlock will occur
// given enough time. They will eventually both want to lock the [Arc<Mutex>]
// the other thread is already locking. Yes, I figured this out the hard way,
// hence the vast amount of debug!() messages.
//
// Example of different order (BAD!):
//
// GUI Main -> locks [p2pool] first
// Helper -> locks [gui_api_p2pool] first
// GUI Status Tab -> trys to lock [gui_api_p2pool] -> CAN'T
// Helper -> trys to lock [p2pool] -> CAN'T
//
// These two threads are now in a deadlock because both
// are trying to access locks the other one already has.
//
// The locking order here must be in the same chronological
// order as the main GUI thread (top to bottom).
The entire codebase is now littered with [debug!()] messages.
Thankfully [log] has 0 cost if you aren't using them, so regular
users won't have a runtime penalty unless they specify RUST_LOG=debug.
Something todo with the height multiplier for [P2Pool Simple]'s
console was causing weird behavior when changing to other tabs.
With the console a bit bigger now, the scrollbar no longer shows
and there is less glitchy resizing when switching to other tabs.
Even with the parent-child relationship and direct process handle,
Gupax can't kill an XMRig spawned with [sudo] on macOS, even though
it can do it fine on Linux. So, on macOS, get the user's [sudo]
pass on the [Stop] button and summon a [sudo kill] on XMRig's PID.
This also complicates things since now we have to keep [SudoState]
somehow between a [Stop] and a [Start]. So there is macOS specific
code that now handles that.
Bare metal windows was complaining about this DLL, so it is now
included statically using [https://docs.rs/static_vcruntime/].
I tried statically linking everything for Windows but:
1. It's not necessary, pretty much all DLLs needed
(except this one) are included in Windows 7+ by default
2. It's a pain in the ass to build everything
statically, especially since Gupax needs OpenSSL.
(building OpenSSL on Windows == hell)
Windows/macOS were having console artifacts, escape codes and
random newlines would show up in P2Pool/XMRig output. After
thinking about it for a while, I realized I left the PTY
size to the default [24 rows/80 columns], hence the PTYs
prematurely inserting newlines and weird escape codes.
It works fine after setting it to [100/1000]. Interestingly,
Linux worked completely fine on 24/80, probably resizes internally.
This commit takes care of correctly starting [sudo] with XMRig as
a command argument. The frontend [restart_*] function is also
implemented. In XMRig's case, the threads will sleep [3/5 seconds]
before [starting/restarting] so that [sudo] has time to open its
STDIN. This prevents premature inputs and outputting the password
to the STDOUT.
Instead of cloning the entirety of the process's output, this
commit adds a sort of hierarchy of string buffers:
We need:
1. The full output for stat parsing (max 1 month/56m bytes)
2. GUI output to be lightweight (max 1-2 hours/1m bytes)
3. GUI output buffered so it's on a refresh tick of 1 second
------------------------------------------------------------------
So this is the new buffer hierarchy, from low to high level:
[Process] <-> [Watchdog] <-> [Helper] <-> [GUI]
------------------------------------------------------------------
Process: Writes to 2 buffers, a FULL (stores everything) and
a BUF which is exactly the same, except this gets [mem:take]n later
Stuff gets written immediately if there is output detected.
Watchdog: [std::mem::take]'s [Process]'s BUF for itself.
Both FULL and BUF output overflows are checked in this loop.
This is done on a slightly faster tick (900ms).
Helper: Appends watchdog's BUF to GUI's already existing [String]
on a 1-second tick.
GUI: Does nothing, only locks & reads.
------------------------------------------------------------------
This means Helper's buffer will be swapped out every second, meaning
it'll almost always be empty. Process's FULL output will be the
heaviest, but is only used for backend parsing. GUI will be in the
middle. This system of buffers makes it so not every thread has to
hold it's own FULL copy of the output, in particular the GUI thread
was starting to lag a little due to loading so much output.
Lots of stuff in this commit:
1. Implement [Start/Stop/Restart] and make it not possible for
the GUI to interact with that UI if [Helper] is doing stuff.
This prevents the obviously bad situation where [Helper] is in
the middle of spawning P2Pool, but the user is still allowed to
start it again, which would spawn another P2Pool. The main GUI
matches on the state and disables the appropriate UI so the
user can't do this.
2. Sync P2Pool's [Priv] and [Pub] output so that the GUI thread
is only rendering it once a second. All of Gupax also refreshes
at least once a second now as well.
3. Match the [ProcessState] with some colors in the GUI
4. GUI thread no longer directly starts/stops/restarts a process.
It will call a function in [Helper] that acts as a proxy.
5. The tokio [async_spawn_p2pool_watchdog()] function that was
a clone of the PTY version (but had async stuff) and all of the
related functions like the async STDOUT/STDERR reader is now
completely gone. It doesn't make sense to write the same code
twice, both [Simple] and [Advanced] will have a PTY, only
difference being the [Simple] UI won't have an input box.
6. P2Pool's exit code is now examined, either success or failure
7. Output was moved into it's own [Arc<Mutex>]. This allows for
more efficient writing/reading since before I had to lock all of
[Helper], which caused some noticable deadlocks in the GUI.
8. New [tab] field in [State<Gupax>], and GUI option to select
the tab that Gupax will start on.
This adds the basic wireframe of how processes will be handled.
The data/funcs in [command.rs] will be the API the main GUI thread
uses to talk to child processes. The process thread will loop
every 1 second to read/write the necessary data (stdout, stdin),
and handle signals from the GUI thread (kill, restart, etc).
This replaces the old mutable [TextEdit] with an immutable one
with a scroll area wrapped in a [Frame]. Passing a [&str] instead
of a [String] to [TextEdit] makes it auto-select only and not
mutable by the user. The background color is changed because the
immutable [TextEdit] has a hardcoded light gray color (same as the
general ui background).
A [must_resize] and [ctx.is_pointer_over_area()] is now used to
indicate we need a resizing. This makes it so when a user is
resizing the width of Gupax, the heavy [init_text_styles()] func
will only get called once when the user hovers over the GUI.
The button size is also now set in that function so it doesn't
have to be called in every separate tab.
Define a strict list [&str; 4] of valid path endings for p2pool/xmrig.
This prevents users (for some reason) inputting a path to some
other (maybe very important) file which Gupax would have completely
overridden with the update binary. Windows paths end with [.exe].
Cargo: Cleanup unused dependencies, enable some build optimizations
Tor: Arti doesn't seem to work on macOS
Even a bare Arti+Hyper request doesn't seem to work, so it's
probably not something to do with Gupax. A lot of issues only
seem to popup in a VM (OpenGL, TLS) even though on bare metal
Gupax runs fine, so Tor might work fine on real macOS but I don't
have real macOS to test it. VM macOS can't create a circuit, so,
disable by default and add a warning that it's unstable.
P2Pool: Let selected_index start at 0, and only +1 when printing
to the user, this makes the overflow math when adding/deleting a
lot more simple because selected_index will match the actual index
of the node vector
If the built-in compiled version of Gupax is the only version
getting compared when updating, an old Gupax instance will always
think there's a new version even if the user already updated and
the actual binaries are swapped. To prevent forcing users to
restart, the built-in compiled version gets compared as well as
the version stored in [Arc<Mutex<Version>>], which should get
updated in a successful Gupax update.
[og: State] is now completely wrapped in an [Arc<Mutex>] so that
when the update is done, it can [.lock()] the CURRENT runtime
settings of the user and save to [gupax.toml] instead of using an
old copy that was given to it at the beginning of the thread.
In practice, this means users can change settings around during
an update and the update finishing and saving to disk won't be
using their old settings, but the current ones. Wrapping all of
[og: State] within in [Arc<Mutex>] might be overkill compared to
message channels but [State] really is just a few [bool]'s, [u*],
and small [String]'s, so it's not much data.
To bypass a deadlock when comparing [og == state] every frame,
[og]'s struct fields get cloned every frame into separate
variables, then it gets compared. This is also pretty stupid, but
again, the data being cloned is so tiny that it doesn't seem to
slow anything down.