fix(ui): trim verbose startup notice; show daemon output on shutdown for external daemons
- Loading "taking longer than expected" notice: shorten the body + hint so the startup screen reads less wordy (same info, ~half the text). - Shutdown screen: when the wallet attached to an EXTERNAL daemon (no captured stdout — debug_log_path_ is only set when we spawn it), the "dragonxd output" panel was always empty, leaving just a spinner. Fall back to tailing the daemon's debug.log so the user can watch the node flush the block index and exit. Adds App::tailDaemonDebugLog() (best-effort, reads only the file tail). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
37
src/app.cpp
37
src/app.cpp
@@ -5742,6 +5742,39 @@ void App::beginShutdown()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> App::tailDaemonDebugLog(int maxLines) const
|
||||||
|
{
|
||||||
|
std::vector<std::string> out;
|
||||||
|
if (maxLines <= 0) return out;
|
||||||
|
const std::string path = util::Platform::getDataDir() + "debug.log";
|
||||||
|
std::error_code ec;
|
||||||
|
const auto sz = std::filesystem::file_size(path, ec);
|
||||||
|
if (ec || sz == 0) return out;
|
||||||
|
std::ifstream f(path, std::ios::binary);
|
||||||
|
if (!f) return out;
|
||||||
|
|
||||||
|
// Read only the last ~16 KB — plenty for a handful of lines, cheap even for a multi-GB log.
|
||||||
|
const std::uintmax_t kTailBytes = 16 * 1024;
|
||||||
|
const std::uintmax_t start = sz > kTailBytes ? sz - kTailBytes : 0;
|
||||||
|
f.seekg(static_cast<std::streamoff>(start), std::ios::beg);
|
||||||
|
std::string chunk(static_cast<std::size_t>(sz - start), '\0');
|
||||||
|
f.read(&chunk[0], static_cast<std::streamsize>(chunk.size()));
|
||||||
|
chunk.resize(static_cast<std::size_t>(f.gcount()));
|
||||||
|
|
||||||
|
std::vector<std::string> lines;
|
||||||
|
std::string cur;
|
||||||
|
for (char c : chunk) {
|
||||||
|
if (c == '\n') { if (!cur.empty()) lines.push_back(cur); cur.clear(); }
|
||||||
|
else if (c != '\r') cur.push_back(c);
|
||||||
|
}
|
||||||
|
if (!cur.empty()) lines.push_back(cur);
|
||||||
|
// When we seeked into the middle of the file the first line is a fragment — drop it.
|
||||||
|
if (start > 0 && !lines.empty()) lines.erase(lines.begin());
|
||||||
|
if (static_cast<int>(lines.size()) > maxLines)
|
||||||
|
lines.erase(lines.begin(), lines.end() - static_cast<std::ptrdiff_t>(maxLines));
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
void App::renderShutdownScreen()
|
void App::renderShutdownScreen()
|
||||||
{
|
{
|
||||||
using namespace ui::material;
|
using namespace ui::material;
|
||||||
@@ -5974,6 +6007,10 @@ void App::renderShutdownScreen()
|
|||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
if (daemon_controller_) {
|
if (daemon_controller_) {
|
||||||
auto lines = daemon_controller_->recentLines(8);
|
auto lines = daemon_controller_->recentLines(8);
|
||||||
|
// External daemon (attached, not spawned) has no captured stdout — tail its debug.log directly
|
||||||
|
// so the user can still watch the node flush the block index and exit.
|
||||||
|
if (lines.empty())
|
||||||
|
lines = tailDaemonDebugLog(8);
|
||||||
if (!lines.empty()) {
|
if (!lines.empty()) {
|
||||||
float panelW = vp_size.x * shutElem("panel-width-fraction", 0.70f);
|
float panelW = vp_size.x * shutElem("panel-width-fraction", 0.70f);
|
||||||
float panelX = cx - panelW * 0.5f;
|
float panelX = cx - panelW * 0.5f;
|
||||||
|
|||||||
@@ -175,6 +175,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
void renderShutdownScreen();
|
void renderShutdownScreen();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tail the last N lines of the daemon's debug.log (best-effort, reads only the file tail).
|
||||||
|
* Fallback for the shutdown screen when we have no captured stdout — e.g. an external daemon we
|
||||||
|
* attached to rather than spawned — so the user can still see the node flushing/exiting.
|
||||||
|
*/
|
||||||
|
std::vector<std::string> tailDaemonDebugLog(int maxLines) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Render loading overlay in content area while daemon is starting/syncing
|
* @brief Render loading overlay in content area while daemon is starting/syncing
|
||||||
* @param contentH Height of the content area child window
|
* @param contentH Height of the content area child window
|
||||||
|
|||||||
@@ -1456,8 +1456,8 @@ void I18n::loadBuiltinEnglish()
|
|||||||
strings_["sb_daemon_extract_failed"] = "Failed to write daemon files — check free disk space and permissions.";
|
strings_["sb_daemon_extract_failed"] = "Failed to write daemon files — check free disk space and permissions.";
|
||||||
strings_["sb_daemon_files_failed"] = "Failed to write daemon files to %s — check free disk space and permissions.";
|
strings_["sb_daemon_files_failed"] = "Failed to write daemon files to %s — check free disk space and permissions.";
|
||||||
strings_["loading_stall_title"] = "Taking longer than expected";
|
strings_["loading_stall_title"] = "Taking longer than expected";
|
||||||
strings_["loading_stall_body"] = "The daemon has been initializing for %.0fs. This can be normal after an update or on first launch (loading the block index or rescanning) — it will connect automatically once ready.";
|
strings_["loading_stall_body"] = "Initializing for %.0fs — normal after an update or first launch. Connects automatically when ready.";
|
||||||
strings_["loading_stall_hint"] = "Still stuck? Open Settings and use Restart Daemon, or check the Console for details.";
|
strings_["loading_stall_hint"] = "Stuck? Settings → Restart Daemon, or check the Console.";
|
||||||
strings_["sb_plaintext_remote_blocked"] = "Refusing to send RPC credentials over plaintext to a remote host. Add rpcallowplaintext=1 to DRAGONX.conf to allow it, or enable TLS with rpctls=1.";
|
strings_["sb_plaintext_remote_blocked"] = "Refusing to send RPC credentials over plaintext to a remote host. Add rpcallowplaintext=1 to DRAGONX.conf to allow it, or enable TLS with rpctls=1.";
|
||||||
strings_["rpc_plaintext_remote_warning"] = "Remote RPC is using plaintext HTTP. Add rpctls=1 to DRAGONX.conf if your daemon supports TLS.";
|
strings_["rpc_plaintext_remote_warning"] = "Remote RPC is using plaintext HTTP. Add rpctls=1 to DRAGONX.conf if your daemon supports TLS.";
|
||||||
strings_["settings_open_log_folder"] = "Open log folder";
|
strings_["settings_open_log_folder"] = "Open log folder";
|
||||||
|
|||||||
Reference in New Issue
Block a user