The Console could look empty if the wallet produced few events. Make it useful in every state and remove a cross-platform footgun: - Add a live status header read straight from the controller (connected / connecting / disconnected, sync %, and the last open error) — independent of the diagnostics event log, so the Console always shows the current connection + wallet-open state even when the log is sparse. - Move LiteDiagnostics::instance() into a single .cpp so there is exactly one instance across the binary, rather than relying on the linker folding an inline-function static across translation units (a known fragility, especially on mingw/Windows — the most likely cause of a stuck-empty event log there). Verified the writer and reader share one instance on Linux; builds clean for full-node, lite, and Windows cross-compile; tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
86 lines
2.6 KiB
C++
86 lines
2.6 KiB
C++
// DragonX Wallet - ImGui Edition
|
|
// Copyright 2024-2026 The Hush Developers
|
|
// Released under the GPLv3
|
|
//
|
|
// lite_diagnostics.h — a small, thread-safe in-memory log of lite-wallet diagnostic events
|
|
// (server connection attempts, wallet open/create/restore, sync milestones, errors). Written
|
|
// from the controller's background threads and the App; read by the lite Console tab. Bounded
|
|
// so it can't grow without limit. Header-only (a Meyers singleton) so both the wallet layer
|
|
// and the UI can use it with no extra link target.
|
|
|
|
#pragma once
|
|
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <ctime>
|
|
#include <deque>
|
|
#include <mutex>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace dragonx {
|
|
namespace wallet {
|
|
|
|
class LiteDiagnostics {
|
|
public:
|
|
// Defined in lite_diagnostics.cpp (a single TU) so there is exactly one instance across the
|
|
// whole binary — no reliance on the linker folding an inline-function static across TUs.
|
|
static LiteDiagnostics& instance();
|
|
|
|
// Append a timestamped line (thread-safe). Safe to call from background threads.
|
|
void log(const std::string& message) {
|
|
std::string line = timestamp();
|
|
line += message;
|
|
std::lock_guard<std::mutex> lk(mutex_);
|
|
lines_.push_back(std::move(line));
|
|
if (lines_.size() > kMaxLines) lines_.pop_front();
|
|
++generation_;
|
|
}
|
|
|
|
// Copy of the current lines (oldest first).
|
|
std::vector<std::string> snapshot() const {
|
|
std::lock_guard<std::mutex> lk(mutex_);
|
|
return std::vector<std::string>(lines_.begin(), lines_.end());
|
|
}
|
|
|
|
// Monotonic counter bumped on every change — lets readers re-snapshot only when it differs.
|
|
std::uint64_t generation() const {
|
|
std::lock_guard<std::mutex> lk(mutex_);
|
|
return generation_;
|
|
}
|
|
|
|
void clear() {
|
|
std::lock_guard<std::mutex> lk(mutex_);
|
|
lines_.clear();
|
|
++generation_;
|
|
}
|
|
|
|
private:
|
|
LiteDiagnostics() = default;
|
|
|
|
static std::string timestamp() {
|
|
std::time_t t = std::time(nullptr);
|
|
std::tm tmv{};
|
|
#ifdef _WIN32
|
|
localtime_s(&tmv, &t);
|
|
#else
|
|
localtime_r(&t, &tmv);
|
|
#endif
|
|
char buf[16];
|
|
std::snprintf(buf, sizeof(buf), "%02d:%02d:%02d ", tmv.tm_hour, tmv.tm_min, tmv.tm_sec);
|
|
return std::string(buf);
|
|
}
|
|
|
|
static constexpr std::size_t kMaxLines = 500;
|
|
mutable std::mutex mutex_;
|
|
std::deque<std::string> lines_;
|
|
std::uint64_t generation_ = 0;
|
|
};
|
|
|
|
// Convenience: append a lite diagnostic line.
|
|
inline void liteLog(const std::string& message) { LiteDiagnostics::instance().log(message); }
|
|
|
|
} // namespace wallet
|
|
} // namespace dragonx
|