feat(lite): ObsidianDragonLite Network tab — server browser
A lite-wallet-only "Network" tab (full-node keeps the Peers tab; exactly one shows per variant) to manage lightwalletd servers, replacing the basic selector that was in Settings. - Card list of servers with per-server latency + status dot, DNS host + resolved IP, and an Official/Custom pill. Official DragonX servers get a glowing outline. - Pick a server (Sticky) by clicking its card, or toggle "use a random server" (Random mode); selection applies immediately (App::rebuildLiteWallet(force=true) tears down + rebuilds the controller against the new server and resyncs — its dtor detaches the uninterruptible sync thread, so this doesn't block). - Add custom servers; hide/unhide servers (persisted set, revealed by a "Show hidden" toggle). - Latency/IP come from a new background probe (util/LiteServerProbe): libcurl CONNECT_ONLY does the TCP+TLS handshake (works for gRPC lightwalletd, no HTTP response needed), recording APPCONNECT_TIME as latency and CURLINFO_PRIMARY_IP. Auto-runs on tab open + a Refresh button. Wiring: WalletUiSurface::LiteNetwork (gated !fullNodePagesAvailable) + NavPage::LiteNetwork in the sidebar + app.cpp dispatch; settings gains a hidden-servers set; isOfficialLiteServer() added to lite_connection_service. The Settings page lite-server selector + its plumbing are removed (single source of truth = the tab). Reuses the existing server model (LiteServerPreference, Sticky/Random, selectLiteServer) and UI primitives (DrawGlassPanel, ThemeEffects glow, peers-tab ping-dot idiom). Unit-tested (liteServerHost, isOfficialLiteServer) + an env-gated live probe (verified vs lite.dragonx.is: online, latency, IP). Both variants + lite-backend build; suite passes; hygiene clean; GUI smoke-launched without crash. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,8 @@
|
||||
#include "util/amount_format.h"
|
||||
#include "util/payment_uri.h"
|
||||
#include "util/xmrig_updater.h"
|
||||
#include "util/lite_server_probe.h"
|
||||
#include "wallet/lite_connection_service.h"
|
||||
#include "wallet/lite_owned_string.h"
|
||||
#include "wallet/lite_rollout_policy.h"
|
||||
#include "wallet/lite_wallet_controller.h"
|
||||
@@ -4076,6 +4078,52 @@ void testXmrigPinnedKeyValidity()
|
||||
EXPECT_EQ(n, static_cast<std::size_t>(crypto_sign_PUBLICKEYBYTES));
|
||||
}
|
||||
|
||||
// Lite Network tab pure helpers.
|
||||
void testLiteServerHostParsing()
|
||||
{
|
||||
using dragonx::util::liteServerHost;
|
||||
EXPECT_EQ(liteServerHost("https://lite.dragonx.is"), std::string("lite.dragonx.is"));
|
||||
EXPECT_EQ(liteServerHost("https://lite.dragonx.is:443/path"), std::string("lite.dragonx.is:443"));
|
||||
EXPECT_EQ(liteServerHost("http://1.2.3.4:9067"), std::string("1.2.3.4:9067"));
|
||||
EXPECT_EQ(liteServerHost("https://user@host.example/x?y"), std::string("host.example"));
|
||||
EXPECT_EQ(liteServerHost("lite.dragonx.is"), std::string("lite.dragonx.is")); // no scheme
|
||||
}
|
||||
|
||||
void testLiteOfficialServerDetection()
|
||||
{
|
||||
using dragonx::wallet::isOfficialLiteServer;
|
||||
EXPECT_TRUE(isOfficialLiteServer("https://lite.dragonx.is"));
|
||||
EXPECT_TRUE(isOfficialLiteServer("https://lite3.dragonx.is"));
|
||||
EXPECT_TRUE(isOfficialLiteServer(" https://lite.dragonx.is ")); // trimmed
|
||||
EXPECT_FALSE(isOfficialLiteServer("https://my-custom-server.example"));
|
||||
EXPECT_FALSE(isOfficialLiteServer(""));
|
||||
}
|
||||
|
||||
// Live probe of a real lite server (env-gated). Validates CONNECT_ONLY latency + IP capture.
|
||||
void testLiteServerProbeLive()
|
||||
{
|
||||
if (!std::getenv("DRAGONX_TEST_NETWORK")) {
|
||||
std::printf("[skip] testLiteServerProbeLive (set DRAGONX_TEST_NETWORK=1 to run)\n");
|
||||
return;
|
||||
}
|
||||
using namespace dragonx::util;
|
||||
LiteServerProbe probe;
|
||||
probe.start({"https://lite.dragonx.is"});
|
||||
for (int i = 0; i < 150 && probe.busy(); ++i)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
const auto res = probe.results();
|
||||
const auto it = res.find("https://lite.dragonx.is");
|
||||
EXPECT_TRUE(it != res.end());
|
||||
if (it != res.end()) {
|
||||
EXPECT_TRUE(it->second.probed);
|
||||
if (it->second.online) { // reachable -> latency + IP captured
|
||||
EXPECT_TRUE(!it->second.ip.empty());
|
||||
std::printf("[live] lite.dragonx.is online %dms ip=%s\n",
|
||||
it->second.latencyMs, it->second.ip.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testXmrigSignatureVerify()
|
||||
{
|
||||
using namespace dragonx::util;
|
||||
@@ -4229,6 +4277,9 @@ int main()
|
||||
testXmrigSignatureAssetSelection();
|
||||
testXmrigPinnedKeyValidity();
|
||||
testXmrigSignatureVerify();
|
||||
testLiteServerHostParsing();
|
||||
testLiteOfficialServerDetection();
|
||||
testLiteServerProbeLive();
|
||||
testXmrigLiveInstall();
|
||||
testGeneratedResourceBehavior();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user