feat(ui): say "Node busy" instead of "Launching dragonxd"; honest quit copy
A node rebuilding note witnesses for an hour was shown as "Starting DragonX node... Launching dragonxd", which invited closing it. - Overlay, a new NodeBusy banner and the status bar now say what the node is doing (rebuilding witnesses / catching up on blocks / up but not answering), with the elapsed time and Phase-1 block progress. A rebuild during startup warm-up replaces the stale "-28 Activating best chain" text, and the overlay re-applies its text once a second instead of only on a connect attempt (30s apart while the node is busy). - Quit prompt: elapsed time, "Keep node running & quit" is the default, "Stop anyway & quit" becomes "Stop node & wait" (it no longer kills). - A reinstall skipped because the node is still running now notifies. - Status bar: don't repeat the warm-up status on the right, and don't print "Connected" there in non-English locales. - i18n: 31 new keys in all 8 languages; 10 dead force-quit/old-modal keys removed; CJK subset rebuilt for the new glyphs. - Tests: chooseDaemonStatus, NodeBusy banner priority, and every new key present in all 8 JSONs with matching printf conversions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+51
-31
@@ -533,16 +533,7 @@ void App::tryConnect()
|
||||
// the UI shows status instead of a blocking overlay.
|
||||
state_.warming_up = true;
|
||||
if (connect_stall_since_ <= 0.0) connect_stall_since_ = ImGui::GetTime(); // start the "taking too long" clock
|
||||
auto wt = translateWarmup(warmupStatus);
|
||||
state_.warmup_status = wt.title;
|
||||
state_.warmup_description = wt.description;
|
||||
// Append current block height from daemon output
|
||||
if (daemon_controller_) {
|
||||
int h = daemon_controller_->lastBlockHeight();
|
||||
if (h > 0)
|
||||
state_.warmup_status += " (Block " + std::to_string(h) + ")";
|
||||
}
|
||||
connection_status_ = state_.warmup_status;
|
||||
applyWarmupText(warmupStatus);
|
||||
}
|
||||
} else {
|
||||
// HTTP 401 = authentication failure. The daemon is running
|
||||
@@ -594,7 +585,9 @@ void App::tryConnect()
|
||||
// a connect refusal means it hasn't bound the RPC port yet. Either way, show a
|
||||
// clear "node initializing" overlay (status + phase + block height from the
|
||||
// daemon's own console output) instead of a bare technical error.
|
||||
const bool reachableButBusy = rpc::isRpcTimeout(connectKind);
|
||||
// Reached the node but no answer (reply timeout / full queue / held back): up but busy.
|
||||
// A refusal or connect timeout means it hasn't bound (or has already unbound) RPC.
|
||||
const bool reachableButBusy = rpc::rpcKindMeansBusy(connectKind);
|
||||
applyDaemonInitStatus(reachableButBusy);
|
||||
const float retryIn = connect_backoff_.next(connectKind);
|
||||
VERBOSE_LOGF("[connect #%d] RPC connection failed (%s) — daemon still starting, retry in %.0fs\n",
|
||||
@@ -605,7 +598,7 @@ void App::tryConnect()
|
||||
// An external daemon is on the RPC port but not answering. A timeout means it's
|
||||
// up and busy initializing; surface that as the init overlay (we can't read its
|
||||
// console since we didn't launch it, so no phase line — just a clear message).
|
||||
if (rpc::isRpcTimeout(connectKind)) {
|
||||
if (rpc::rpcKindMeansBusy(connectKind)) {
|
||||
applyDaemonInitStatus(/*reachableButBusy=*/true);
|
||||
} else if (!connectErr.empty()) {
|
||||
char buf[256]; snprintf(buf, sizeof(buf), TR("sb_connecting_err"), connectErr.c_str());
|
||||
@@ -699,6 +692,7 @@ void App::onConnected()
|
||||
wallet_switch_phase_.store(static_cast<int>(WalletSwitchPhase::None));
|
||||
}
|
||||
state_.daemon_initializing = false; // RPC is answering now; clear the "initializing" overlay
|
||||
init_status_title_.clear();
|
||||
daemon_wait_attempts_ = 0; // re-arm the port-busy / start-failure notifications
|
||||
connect_stall_since_ = 0.0; // connected — clear the "taking too long" clock
|
||||
// A repair's rescan finished and connected — retire the recovery session so its crash-toast/error-card
|
||||
@@ -870,19 +864,33 @@ std::string App::applyDaemonInitStatus(bool reachableButBusy)
|
||||
}
|
||||
}
|
||||
|
||||
// Most specific first: the node's own log says it is rebuilding witnesses or replaying blocks (then
|
||||
// "Launching dragonxd…" over a node that has been busy for an hour invited closing it), else an init
|
||||
// phase line, else "reachable but busy", else not bound yet.
|
||||
const auto kind = daemon::chooseDaemonStatus(!phaseLine.empty(), reachableButBusy, daemon_busy_);
|
||||
std::string busyTitle, busyDetail;
|
||||
WarmupText wt;
|
||||
if (!phaseLine.empty()) {
|
||||
switch (kind) {
|
||||
case daemon::DaemonStatusKind::Rebuilding:
|
||||
case daemon::DaemonStatusKind::Replaying: {
|
||||
const NodeBusyText busy = nodeBusyText();
|
||||
busyTitle = busy.title;
|
||||
busyDetail = busy.detail;
|
||||
wt = {busyTitle.c_str(), busyDetail.c_str()};
|
||||
break;
|
||||
}
|
||||
case daemon::DaemonStatusKind::InitPhase:
|
||||
wt = translateWarmup(phaseLine);
|
||||
} else if (reachableButBusy) {
|
||||
// The probe connected but got no RPC reply within the timeout: the node is up but busy
|
||||
// initializing (it isn't printing a recognizable phase, or we didn't launch it).
|
||||
wt = {"Starting DragonX node…",
|
||||
"The node is reachable but still initializing and isn't answering yet. "
|
||||
"This is normal after an update or on first launch — it can take a few minutes."};
|
||||
} else {
|
||||
break;
|
||||
case daemon::DaemonStatusKind::Busy:
|
||||
// The probe reached the node but got no answer (a reply timeout or a full queue): it is up but
|
||||
// too busy to answer (it isn't printing a recognizable phase, or we didn't launch it).
|
||||
wt = {TR("node_starting_title"), TR("node_starting_busy_desc")};
|
||||
break;
|
||||
case daemon::DaemonStatusKind::Launching:
|
||||
// The daemon is launching but hasn't bound its RPC port yet.
|
||||
wt = {"Starting DragonX node…",
|
||||
"Launching dragonxd and waiting for it to come online…"};
|
||||
wt = {TR("node_starting_title"), TR("node_starting_launch_desc")};
|
||||
break;
|
||||
}
|
||||
|
||||
std::string title = wt.title;
|
||||
@@ -892,9 +900,29 @@ std::string App::applyDaemonInitStatus(bool reachableButBusy)
|
||||
state_.warmup_status = title;
|
||||
state_.warmup_description = wt.description ? wt.description : "";
|
||||
connection_status_ = title;
|
||||
init_status_title_ = title;
|
||||
init_status_busy_ = reachableButBusy;
|
||||
return title;
|
||||
}
|
||||
|
||||
void App::applyWarmupText(const std::string& rpcMessage)
|
||||
{
|
||||
warmup_rpc_message_ = rpcMessage;
|
||||
if (daemon_busy_.rebuilding()) {
|
||||
const NodeBusyText busy = nodeBusyText();
|
||||
state_.warmup_status = busy.title;
|
||||
state_.warmup_description = busy.detail;
|
||||
} else {
|
||||
const WarmupText wt = translateWarmup(rpcMessage);
|
||||
state_.warmup_status = wt.title;
|
||||
state_.warmup_description = wt.description;
|
||||
}
|
||||
// Append current block height from daemon output
|
||||
const int h = daemon_controller_ ? daemon_controller_->lastBlockHeight() : -1;
|
||||
if (h > 0) state_.warmup_status += " (Block " + std::to_string(h) + ")";
|
||||
connection_status_ = state_.warmup_status;
|
||||
}
|
||||
|
||||
void App::handleLostConnection(const std::string& reason)
|
||||
{
|
||||
DEBUG_LOGF("[Connection] %s — tearing down for reconnect\n", reason.c_str());
|
||||
@@ -1799,15 +1827,7 @@ void App::refreshCoreData()
|
||||
refreshData();
|
||||
} else {
|
||||
// Still warming up — update status
|
||||
auto wt = translateWarmup(result.errorMessage);
|
||||
state_.warmup_status = wt.title;
|
||||
state_.warmup_description = wt.description;
|
||||
if (daemon_controller_) {
|
||||
int h = daemon_controller_->lastBlockHeight();
|
||||
if (h > 0)
|
||||
state_.warmup_status += " (Block " + std::to_string(h) + ")";
|
||||
}
|
||||
connection_status_ = state_.warmup_status;
|
||||
applyWarmupText(result.errorMessage);
|
||||
VERBOSE_LOGF("[warmup] Still warming up: %s\n", result.errorMessage.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user