Files
ObsidianDragon/src/wallet/lite_client_bridge.cpp
DanS c676ec8287 refactor(lite): extract owned-string core, drop dead bridge-runtime scaffold
lite_bridge_runtime.{cpp,h} was ~25k lines of dry-dispatch / dynamic-loader
scaffolding that the shipping wallet never used: 0 of its 122 public types
reached the app binary. The only live code on the bridge path was the
owned-string memory-safety helper — LiteClientBridge::linkedSdxl() already
loads the backend via direct litelib_* externs in lite_client_bridge.cpp.

- Extract LiteBridgeOwnedString + liteBridgeRuntimeTakeOwnedString into
  src/wallet/lite_owned_string.{h,cpp} (the copy-before-free / free-once /
  wipe / "Error:"-classify boundary), with the runtime-friend coupling removed.
- Point lite_client_bridge.cpp at the new header.
- Delete lite_bridge_runtime.{cpp,h} and the 16 runtime-only tests +
  their fixtures/aliases in test_phase4.cpp; keep the 5 owned-string tests
  (retargeted) and restore testGeneratedResourceBehavior, which had been
  caught in the runtime-test line range.
- Swap the CMake source/header references.

Both variants build; full test suite passes; source-hygiene check clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 08:56:55 -05:00

186 lines
5.5 KiB
C++

// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#include "lite_client_bridge.h"
#include "lite_owned_string.h"
#ifndef DRAGONX_ENABLE_LITE_BACKEND
#define DRAGONX_ENABLE_LITE_BACKEND 0
#endif
#if DRAGONX_ENABLE_LITE_BACKEND
extern "C" {
bool litelib_wallet_exists(const char* chain_name);
char* litelib_initialize_new(bool dangerous, const char* server);
char* litelib_initialize_new_from_phrase(bool dangerous,
const char* server,
const char* seed,
unsigned long long birthday,
unsigned long long number,
bool overwrite);
char* litelib_initialize_existing(bool dangerous, const char* server);
char* litelib_execute(const char* command, const char* args);
void litelib_rust_free_string(char* value);
bool litelib_check_server_online(const char* server);
void litelib_shutdown();
}
#endif
#include <utility>
namespace dragonx {
namespace wallet {
namespace {
bool hasRequiredApi(const LiteClientBridgeApi& api)
{
return api.walletExists &&
api.initializeNew &&
api.initializeNewFromPhrase &&
api.initializeExisting &&
api.execute &&
api.freeString &&
api.checkServerOnline &&
api.shutdown;
}
#if DRAGONX_ENABLE_LITE_BACKEND
LiteClientBridgeApi linkedSdxlApi()
{
return LiteClientBridgeApi{
&litelib_wallet_exists,
&litelib_initialize_new,
&litelib_initialize_new_from_phrase,
&litelib_initialize_existing,
&litelib_execute,
&litelib_rust_free_string,
&litelib_check_server_online,
&litelib_shutdown
};
}
#endif
} // namespace
LiteClientBridge::LiteClientBridge(LiteClientBridgeApi api, std::string unavailableReason)
: api_(api), unavailableReason_(std::move(unavailableReason))
{
}
LiteClientBridge LiteClientBridge::unavailable(std::string reason)
{
return LiteClientBridge({}, std::move(reason));
}
LiteClientBridge LiteClientBridge::fromApi(LiteClientBridgeApi api)
{
if (!hasRequiredApi(api)) {
return unavailable("lite client bridge API is incomplete");
}
return LiteClientBridge(api, {});
}
LiteClientBridge LiteClientBridge::linkedSdxl()
{
#if DRAGONX_ENABLE_LITE_BACKEND
return fromApi(linkedSdxlApi());
#else
return unavailable("lite backend is not linked");
#endif
}
LiteClientBridge::LiteClientBridge(LiteClientBridge&& other) noexcept
: api_(other.api_),
unavailableReason_(std::move(other.unavailableReason_)),
shutdownCalled_(other.shutdownCalled_)
{
other.api_ = {};
other.shutdownCalled_ = true;
}
LiteClientBridge& LiteClientBridge::operator=(LiteClientBridge&& other) noexcept
{
if (this == &other) return *this;
shutdown();
api_ = other.api_;
unavailableReason_ = std::move(other.unavailableReason_);
shutdownCalled_ = other.shutdownCalled_;
other.api_ = {};
other.shutdownCalled_ = true;
return *this;
}
LiteClientBridge::~LiteClientBridge()
{
shutdown();
}
bool LiteClientBridge::available() const
{
return hasRequiredApi(api_);
}
bool LiteClientBridge::walletExists(const std::string& chainName) const
{
if (!available()) return false;
return api_.walletExists(chainName.c_str());
}
bool LiteClientBridge::checkServerOnline(const std::string& server) const
{
if (!available()) return false;
return api_.checkServerOnline(server.c_str());
}
LiteBridgeStringResult LiteClientBridge::initializeNew(bool dangerous, const std::string& server)
{
if (!available()) return unavailableResult();
return takeOwnedString(api_.initializeNew(dangerous, server.c_str()));
}
LiteBridgeStringResult LiteClientBridge::initializeNewFromPhrase(bool dangerous,
const std::string& server,
const std::string& seed,
unsigned long long birthday,
unsigned long long account,
bool overwrite)
{
if (!available()) return unavailableResult();
return takeOwnedString(api_.initializeNewFromPhrase(
dangerous, server.c_str(), seed.c_str(), birthday, account, overwrite));
}
LiteBridgeStringResult LiteClientBridge::initializeExisting(bool dangerous, const std::string& server)
{
if (!available()) return unavailableResult();
return takeOwnedString(api_.initializeExisting(dangerous, server.c_str()));
}
LiteBridgeStringResult LiteClientBridge::execute(const std::string& command, const std::string& args)
{
if (!available()) return unavailableResult();
if (command.empty()) return {false, {}, "lite command is empty"};
return takeOwnedString(api_.execute(command.c_str(), args.c_str()));
}
void LiteClientBridge::shutdown()
{
if (shutdownCalled_) return;
shutdownCalled_ = true;
if (available()) api_.shutdown();
}
LiteBridgeStringResult LiteClientBridge::unavailableResult() const
{
return {false, {}, unavailableReason_.empty() ? "lite backend is unavailable" : unavailableReason_};
}
LiteBridgeStringResult LiteClientBridge::takeOwnedString(char* rawValue) const
{
return liteBridgeRuntimeTakeOwnedString(rawValue, api_.freeString);
}
} // namespace wallet
} // namespace dragonx