refactor: move AI/agent files into ObsidianDragon-agent/
- copilot-instructions.md → ObsidianDragon-agent/copilot-instructions.md - ARCHITECTURE.md → ObsidianDragon-agent/ARCHITECTURE.md - Symlinks at original locations preserve Copilot auto-discovery
This commit is contained in:
175
.github/copilot-instructions.md
vendored
175
.github/copilot-instructions.md
vendored
@@ -1,175 +0,0 @@
|
|||||||
# ObsidianDragon — Coding Standards & Architecture
|
|
||||||
|
|
||||||
## Project Identity
|
|
||||||
|
|
||||||
ObsidianDragon is a native C++17 desktop wallet for the DragonX (DRGX) cryptocurrency.
|
|
||||||
It uses ImGui (immediate-mode GUI) with SDL3, ships an embedded full-node daemon (`dragonxd`),
|
|
||||||
and includes an integrated CPU miner (`xmrig-hac`). Licensed GPLv3.
|
|
||||||
|
|
||||||
Platforms: Linux (x86_64), Windows (x86_64, cross-compiled via MinGW), macOS (universal arm64+x86_64).
|
|
||||||
|
|
||||||
## Code Style
|
|
||||||
|
|
||||||
### Naming
|
|
||||||
- **Classes/structs/enums:** `CamelCase` — `RPCClient`, `WalletState`, `NavPage`
|
|
||||||
- **Member variables:** `snake_case_` with trailing underscore — `rpc_`, `connection_status_`, `fast_worker_`
|
|
||||||
- **Functions/methods:** `camelCase` — `tryConnect()`, `isConnected()`, `drainResults()`
|
|
||||||
- **Constants:** `UPPER_SNAKE` for macros, `camelCase` for const vars — `REFRESH_INTERVAL`, `DEFAULT_FEE`
|
|
||||||
- **Enum values:** `CamelCase` — `NavPage::Overview`, `State::Running`
|
|
||||||
- **Type aliases:** `using MainCb = std::function<void()>;`
|
|
||||||
|
|
||||||
### Formatting
|
|
||||||
- 4-space indentation, no tabs
|
|
||||||
- Opening brace on same line: `void foo() {`
|
|
||||||
- `#pragma once` (not include guards)
|
|
||||||
- Include order: self header, standard library, third-party, project headers
|
|
||||||
|
|
||||||
### Memory & Ownership
|
|
||||||
- `std::unique_ptr<T>` for ownership — never raw `new`/`delete`
|
|
||||||
- Raw pointers for non-owning references (e.g., function parameters)
|
|
||||||
- RAII for all resource management (threads, handles, mutexes)
|
|
||||||
|
|
||||||
### Documentation
|
|
||||||
- `///` Doxygen comments on public APIs in headers
|
|
||||||
- Implementation files: explain *why*, not *what*
|
|
||||||
- Use `DEBUG_LOGF()` for debug logging, not `printf`/`std::cout`
|
|
||||||
|
|
||||||
## Threading Model
|
|
||||||
|
|
||||||
**Main thread** — ImGui render loop (`App::update()`), all UI code, `drainResults()` callbacks.
|
|
||||||
Never block this thread with network I/O or disk I/O.
|
|
||||||
|
|
||||||
**`worker_`** (RPCWorker) — General-purpose background thread for batched RPC polling.
|
|
||||||
Executes the `refreshData()` cycle every 5 seconds.
|
|
||||||
|
|
||||||
**`fast_worker_`** (RPCWorker) — Fast-lane background thread for latency-sensitive operations:
|
|
||||||
console commands, mining hashrate polls. Avoids head-of-line blocking behind main refresh batch.
|
|
||||||
|
|
||||||
**Monitor threads** — `EmbeddedDaemon` and `XmrigManager` each spawn a monitor thread
|
|
||||||
to read stdout/stderr pipes from their child processes.
|
|
||||||
|
|
||||||
### Work Submission Pattern
|
|
||||||
```cpp
|
|
||||||
// Post work to background thread; return a callback for the main thread
|
|
||||||
worker_->post([this]() -> rpc::RPCWorker::MainCb {
|
|
||||||
json result = rpc_->call("getinfo"); // Runs on worker thread (blocking OK)
|
|
||||||
return [this, result]() {
|
|
||||||
state_.connected = true; // Runs on main thread via drainResults()
|
|
||||||
};
|
|
||||||
});
|
|
||||||
```
|
|
||||||
`drainResults()` is called each frame in `App::update()` to execute completed callbacks.
|
|
||||||
|
|
||||||
## RPC Architecture
|
|
||||||
|
|
||||||
**Dual-client design:**
|
|
||||||
- `rpc_` + `worker_` — main polling (balance, transactions, sync status)
|
|
||||||
- `fast_rpc_` + `fast_worker_` — console commands, mining stats
|
|
||||||
|
|
||||||
Both are `RPCClient` instances wrapping libcurl for JSON-RPC over HTTPS.
|
|
||||||
|
|
||||||
**Callback types:**
|
|
||||||
```cpp
|
|
||||||
using Callback = std::function<void(const json&)>;
|
|
||||||
using ErrorCallback = std::function<void(const std::string&)>;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Error flow:** RPC errors throw `std::runtime_error` → caught in `doRPC()` → invokes
|
|
||||||
`ErrorCallback` → surfaces via `Notifications::instance().error(msg)`.
|
|
||||||
|
|
||||||
**Connection state:** `state_.connected` (app-level, set in `onConnected()`) vs
|
|
||||||
`rpc_->isConnected()` (per-client, set after successful `getinfo()`). These can differ —
|
|
||||||
always check the right one for the context.
|
|
||||||
|
|
||||||
## Connection Lifecycle
|
|
||||||
|
|
||||||
```
|
|
||||||
[Disconnected] → tryConnect() every 5s
|
|
||||||
→ auto-detect DRAGONX.conf (host, port, rpcuser, rpcpassword)
|
|
||||||
→ if no config: start embedded daemon → retry
|
|
||||||
→ post async rpc_->connect() to worker_
|
|
||||||
→ success: onConnected() → state_.connected = true
|
|
||||||
→ auth 401: try .cookie auth → retry
|
|
||||||
→ failure: onDisconnected(reason) → may restart daemon
|
|
||||||
```
|
|
||||||
|
|
||||||
## UI Patterns
|
|
||||||
|
|
||||||
### Page Routing
|
|
||||||
`NavPage` enum in `src/ui/sidebar.h` defines all pages. `App::update()` dispatches
|
|
||||||
via switch on `current_page_` to render functions like `RenderBalanceTab(this)` or
|
|
||||||
`console_tab_.render(...)`.
|
|
||||||
|
|
||||||
### Dialogs
|
|
||||||
Modal dialogs use `show_*` boolean flags (e.g., `show_import_key_`, `show_backup_`).
|
|
||||||
Set the flag to `true` to open; the dialog renders in `App::update()` and clears
|
|
||||||
the flag when dismissed.
|
|
||||||
|
|
||||||
### Notifications
|
|
||||||
```cpp
|
|
||||||
Notifications::instance().success("Transaction sent");
|
|
||||||
Notifications::instance().error("Insufficient funds");
|
|
||||||
```
|
|
||||||
Toast-style popups in the bottom-right corner.
|
|
||||||
|
|
||||||
### Lock Screen & Loading Overlay
|
|
||||||
- Lock screen gates all interaction when `state_.isLocked()`
|
|
||||||
- Loading overlay shown while daemon isn't ready, gates all tabs except Peers, Console, Settings
|
|
||||||
|
|
||||||
## Platform Abstractions
|
|
||||||
|
|
||||||
Detection: `#ifdef _WIN32` / `#elif __APPLE__` / `#elif __linux__`
|
|
||||||
|
|
||||||
Platform-specific files live in `src/platform/` (Windows only: DX11 context, backdrop effects).
|
|
||||||
Shared platform utilities in `src/util/platform.h` — `openUrl()`, `getHomeDir()`, `getDragonXDataDir()`.
|
|
||||||
|
|
||||||
Rendering backends:
|
|
||||||
- Windows: DirectX 11 (`imgui_impl_dx11`)
|
|
||||||
- macOS/Linux: OpenGL 3 (`imgui_impl_opengl3`) + GLAD loader
|
|
||||||
|
|
||||||
## Build System
|
|
||||||
|
|
||||||
CMake 3.20+, C++17. Single `CMakeLists.txt` at root.
|
|
||||||
|
|
||||||
**FetchContent dependencies:** SDL3, nlohmann/json v3.11.3, toml++ v3.4.0, libcurl (Windows only)
|
|
||||||
**Bundled libraries:** ImGui, GLAD, miniz, libsodium (pre-built per platform), qrcode
|
|
||||||
|
|
||||||
**macOS:** Universal binary (arm64+x86_64), deployment target 11.0 (Big Sur+).
|
|
||||||
Set `CMAKE_OSX_DEPLOYMENT_TARGET` and `CMAKE_OSX_ARCHITECTURES` before `project()`.
|
|
||||||
|
|
||||||
**Build commands:**
|
|
||||||
```bash
|
|
||||||
./build.sh # Dev build
|
|
||||||
./build.sh --mac-release # macOS universal .app + DMG
|
|
||||||
./build.sh --linux-release # Linux AppImage + zip
|
|
||||||
./build.sh --win-release # Windows cross-compile
|
|
||||||
```
|
|
||||||
|
|
||||||
## Theme System
|
|
||||||
|
|
||||||
UI layout values are defined in `res/themes/ui.toml` and accessed via `schema::UI()` —
|
|
||||||
**never hardcode pixel sizes in C++ code**.
|
|
||||||
|
|
||||||
Skins are self-contained TOML files in `res/themes/` defining color palettes.
|
|
||||||
`scripts/expand_themes.py` merges layout sections from `ui.toml` into each skin at build time.
|
|
||||||
|
|
||||||
Colors support CSS-style variables: `--primary`, `--surface`, `--on-surface-medium`, resolved
|
|
||||||
by `ColorVarResolver` at runtime.
|
|
||||||
|
|
||||||
## Internationalization
|
|
||||||
|
|
||||||
All user-visible strings use `TR("key")` macro → `dragonx::util::tr()` → lookup in
|
|
||||||
`I18n` singleton. Never hardcode English strings in UI code.
|
|
||||||
|
|
||||||
Language files: `res/lang/{locale}.json` (runtime) with embedded fallback compiled into binary.
|
|
||||||
Supported: en, es, zh, ru, de, fr, pt, ja, ko.
|
|
||||||
|
|
||||||
## Key Rules
|
|
||||||
|
|
||||||
1. **Never block the main thread** — all network/disk I/O goes through `worker_->post()`
|
|
||||||
2. **Never hardcode pixel sizes** — use `ui.toml` schema values via `schema::UI()`
|
|
||||||
3. **Always use `TR()` for strings** — no hardcoded English in UI rendering code
|
|
||||||
4. **Use `ICON_MD_*` for icons** — Material Design icon font, never raw Unicode
|
|
||||||
5. **Use `std::unique_ptr`** — no raw `new`/`delete` in application code
|
|
||||||
6. **Check the right connection state** — `state_.connected` for app-level, `rpc_->isConnected()` for per-client
|
|
||||||
7. **Test all three platforms** — build must pass Linux; cross-compile test if touching platform code
|
|
||||||
1
.github/copilot-instructions.md
vendored
Symbolic link
1
.github/copilot-instructions.md
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../ObsidianDragon-agent/copilot-instructions.md
|
||||||
154
ObsidianDragon-agent/ARCHITECTURE.md
Normal file
154
ObsidianDragon-agent/ARCHITECTURE.md
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
# ObsidianDragon — Architecture Guide
|
||||||
|
|
||||||
|
A native C++17 desktop wallet for DragonX (DRGX), built with ImGui + SDL3.
|
||||||
|
|
||||||
|
## Directory Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── main.cpp Entry point, SDL3/backend init, render loop
|
||||||
|
├── app.h / app.cpp App class: init, shutdown, frame dispatch
|
||||||
|
├── app_network.cpp RPC connection, data refresh, mining ops
|
||||||
|
├── app_security.cpp Encryption, lock screen, PIN management
|
||||||
|
├── app_wizard.cpp First-run setup wizard
|
||||||
|
├── config/
|
||||||
|
│ └── settings.h/.cpp JSON settings persistence (~/.config/ObsidianDragon/)
|
||||||
|
├── daemon/
|
||||||
|
│ ├── embedded_daemon.h/.cpp dragonxd process lifecycle
|
||||||
|
│ └── xmrig_manager.h/.cpp xmrig-hac pool mining management
|
||||||
|
├── rpc/
|
||||||
|
│ ├── rpc_client.h/.cpp JSON-RPC over HTTPS (libcurl)
|
||||||
|
│ ├── rpc_worker.h/.cpp Background work queue + main-thread drain
|
||||||
|
│ ├── connection.h/.cpp DRAGONX.conf auto-detection
|
||||||
|
│ └── types.h Transaction, address data types
|
||||||
|
├── ui/
|
||||||
|
│ ├── sidebar.h NavPage enum, sidebar rendering
|
||||||
|
│ ├── notifications.h/.cpp Toast notification system
|
||||||
|
│ ├── schema/
|
||||||
|
│ │ ├── ui_schema.h/.cpp UISchema singleton (TOML → typed lookups)
|
||||||
|
│ │ ├── skin_manager.h/.cpp Skin enumeration, switching, import
|
||||||
|
│ │ └── color_var_resolver.h/.cpp CSS-style color resolution
|
||||||
|
│ └── windows/ Per-tab render functions (console, settings, etc.)
|
||||||
|
├── util/
|
||||||
|
│ ├── i18n.h/.cpp Internationalization (TR() macro, I18n singleton)
|
||||||
|
│ ├── platform.h/.cpp Cross-platform utilities (paths, URLs)
|
||||||
|
│ └── logger.h DEBUG_LOGF / VERBOSE_LOGF macros
|
||||||
|
├── platform/ Windows-specific (DX11 context, backdrop effects)
|
||||||
|
├── embedded/ Build-generated headers (embedded resources)
|
||||||
|
└── resources/ Runtime resource loading (fonts, images)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Threading Model
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ Main Thread (UI) │
|
||||||
|
│ • ImGui render loop (App::update()) │
|
||||||
|
│ • drainResults() each frame → executes completed callbacks │
|
||||||
|
│ • NEVER does blocking I/O │
|
||||||
|
└────────────┬────────────────────────┬───────────────────────┘
|
||||||
|
│ post() │ post()
|
||||||
|
▼ ▼
|
||||||
|
┌────────────────────┐ ┌────────────────────────────────┐
|
||||||
|
│ worker_ (RPCWorker)│ │ fast_worker_ (RPCWorker) │
|
||||||
|
│ General RPC polling│ │ Console commands, hashrate │
|
||||||
|
│ refreshData() 5s │ │ Avoids head-of-line blocking │
|
||||||
|
└────────────────────┘ └────────────────────────────────┘
|
||||||
|
|
||||||
|
┌────────────────────────────────────────────┐
|
||||||
|
│ Monitor Threads (per child process) │
|
||||||
|
│ • EmbeddedDaemon: reads dragonxd stdout │
|
||||||
|
│ • XmrigManager: reads xmrig-hac stdout │
|
||||||
|
└────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Work Submission Pattern
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
worker_->post([this]() -> rpc::RPCWorker::MainCb {
|
||||||
|
json result = rpc_->call("getinfo"); // Runs on worker thread
|
||||||
|
return [this, result]() {
|
||||||
|
state_.connected = true; // Runs on main thread
|
||||||
|
};
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## RPC Architecture
|
||||||
|
|
||||||
|
**Dual-client design** avoids head-of-line blocking:
|
||||||
|
|
||||||
|
| Client | Worker | Purpose |
|
||||||
|
|--------|--------|---------|
|
||||||
|
| `rpc_` | `worker_` | Main polling: balance, transactions, sync status |
|
||||||
|
| `fast_rpc_` | `fast_worker_` | Console commands, mining stats |
|
||||||
|
|
||||||
|
Both are `RPCClient` instances wrapping libcurl for JSON-RPC over HTTPS to `dragonxd`.
|
||||||
|
|
||||||
|
**Error flow:** `RPCClient::call()` throws `std::runtime_error` →
|
||||||
|
caught in worker lambda → error string captured → `MainCb` calls
|
||||||
|
`Notifications::instance().error(msg)` on main thread.
|
||||||
|
|
||||||
|
## Connection Lifecycle
|
||||||
|
|
||||||
|
```
|
||||||
|
[Disconnected] → tryConnect() every 5s
|
||||||
|
→ auto-detect DRAGONX.conf (host, port, rpcuser, rpcpassword)
|
||||||
|
→ if no config: start embedded daemon → retry
|
||||||
|
→ post async rpc_->connect() to worker_
|
||||||
|
→ success: onConnected() → state_.connected = true
|
||||||
|
→ auth 401: try .cookie auth → retry
|
||||||
|
→ failure: onDisconnected(reason) → may restart daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
## UI System
|
||||||
|
|
||||||
|
### Page Routing
|
||||||
|
`NavPage` enum defines all pages. `App::update()` dispatches via switch on
|
||||||
|
`current_page_` to render functions (e.g., `RenderBalanceTab(this)`).
|
||||||
|
|
||||||
|
### Theme System
|
||||||
|
- Layout defined in `res/themes/ui.toml`, accessed via `schema::UI()`
|
||||||
|
- Skins are TOML files in `res/themes/` defining color palettes
|
||||||
|
- `scripts/expand_themes.py` merges layout into skins at build time
|
||||||
|
- Colors support CSS-style variables resolved by `ColorVarResolver`
|
||||||
|
- Hot-reload: `UISchema::pollForChanges()` watches file mtime
|
||||||
|
|
||||||
|
### Internationalization
|
||||||
|
- All UI strings use `TR("key")` macro → `I18n` singleton lookup
|
||||||
|
- Language files: `res/lang/{locale}.json` with compiled-in fallbacks
|
||||||
|
- Supported: en, es, zh, ru, de, fr, pt, ja, ko
|
||||||
|
|
||||||
|
### Notifications
|
||||||
|
```cpp
|
||||||
|
Notifications::instance().success("Transaction sent");
|
||||||
|
Notifications::instance().error("Insufficient funds");
|
||||||
|
```
|
||||||
|
Toast-style popups, bottom-right corner, 5-second default duration.
|
||||||
|
|
||||||
|
## Build System
|
||||||
|
|
||||||
|
CMake 3.20+, C++17. FetchContent for SDL3, nlohmann/json, toml++.
|
||||||
|
Bundled: ImGui, GLAD, miniz, libsodium, qrcode.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build.sh # Dev build
|
||||||
|
./build.sh --mac-release # macOS universal .app + DMG
|
||||||
|
./build.sh --linux-release # Linux AppImage + zip
|
||||||
|
./build.sh --win-release # Windows cross-compile (MinGW)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Platform Backends
|
||||||
|
| Platform | Renderer | Notes |
|
||||||
|
|----------|----------|-------|
|
||||||
|
| Windows | DirectX 11 | `imgui_impl_dx11`, backdrop effects |
|
||||||
|
| macOS | OpenGL 3 | Universal binary (arm64+x86_64), target 11.0+ |
|
||||||
|
| Linux | OpenGL 3 | GLAD loader |
|
||||||
|
|
||||||
|
## Key Conventions
|
||||||
|
|
||||||
|
1. **Never block the main thread** — all I/O goes through `worker_->post()`
|
||||||
|
2. **Never hardcode pixel sizes** — use `schema::UI()` lookups from `ui.toml`
|
||||||
|
3. **Always use `TR()` for strings** — no hardcoded English in UI code
|
||||||
|
4. **Use `ICON_MD_*` for icons** — Material Design icon font
|
||||||
|
5. **`std::unique_ptr` for ownership** — no raw `new`/`delete`
|
||||||
|
6. **Check the right connection state** — `state_.connected` vs `rpc_->isConnected()`
|
||||||
175
ObsidianDragon-agent/copilot-instructions.md
Normal file
175
ObsidianDragon-agent/copilot-instructions.md
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
# ObsidianDragon — Coding Standards & Architecture
|
||||||
|
|
||||||
|
## Project Identity
|
||||||
|
|
||||||
|
ObsidianDragon is a native C++17 desktop wallet for the DragonX (DRGX) cryptocurrency.
|
||||||
|
It uses ImGui (immediate-mode GUI) with SDL3, ships an embedded full-node daemon (`dragonxd`),
|
||||||
|
and includes an integrated CPU miner (`xmrig-hac`). Licensed GPLv3.
|
||||||
|
|
||||||
|
Platforms: Linux (x86_64), Windows (x86_64, cross-compiled via MinGW), macOS (universal arm64+x86_64).
|
||||||
|
|
||||||
|
## Code Style
|
||||||
|
|
||||||
|
### Naming
|
||||||
|
- **Classes/structs/enums:** `CamelCase` — `RPCClient`, `WalletState`, `NavPage`
|
||||||
|
- **Member variables:** `snake_case_` with trailing underscore — `rpc_`, `connection_status_`, `fast_worker_`
|
||||||
|
- **Functions/methods:** `camelCase` — `tryConnect()`, `isConnected()`, `drainResults()`
|
||||||
|
- **Constants:** `UPPER_SNAKE` for macros, `camelCase` for const vars — `REFRESH_INTERVAL`, `DEFAULT_FEE`
|
||||||
|
- **Enum values:** `CamelCase` — `NavPage::Overview`, `State::Running`
|
||||||
|
- **Type aliases:** `using MainCb = std::function<void()>;`
|
||||||
|
|
||||||
|
### Formatting
|
||||||
|
- 4-space indentation, no tabs
|
||||||
|
- Opening brace on same line: `void foo() {`
|
||||||
|
- `#pragma once` (not include guards)
|
||||||
|
- Include order: self header, standard library, third-party, project headers
|
||||||
|
|
||||||
|
### Memory & Ownership
|
||||||
|
- `std::unique_ptr<T>` for ownership — never raw `new`/`delete`
|
||||||
|
- Raw pointers for non-owning references (e.g., function parameters)
|
||||||
|
- RAII for all resource management (threads, handles, mutexes)
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
- `///` Doxygen comments on public APIs in headers
|
||||||
|
- Implementation files: explain *why*, not *what*
|
||||||
|
- Use `DEBUG_LOGF()` for debug logging, not `printf`/`std::cout`
|
||||||
|
|
||||||
|
## Threading Model
|
||||||
|
|
||||||
|
**Main thread** — ImGui render loop (`App::update()`), all UI code, `drainResults()` callbacks.
|
||||||
|
Never block this thread with network I/O or disk I/O.
|
||||||
|
|
||||||
|
**`worker_`** (RPCWorker) — General-purpose background thread for batched RPC polling.
|
||||||
|
Executes the `refreshData()` cycle every 5 seconds.
|
||||||
|
|
||||||
|
**`fast_worker_`** (RPCWorker) — Fast-lane background thread for latency-sensitive operations:
|
||||||
|
console commands, mining hashrate polls. Avoids head-of-line blocking behind main refresh batch.
|
||||||
|
|
||||||
|
**Monitor threads** — `EmbeddedDaemon` and `XmrigManager` each spawn a monitor thread
|
||||||
|
to read stdout/stderr pipes from their child processes.
|
||||||
|
|
||||||
|
### Work Submission Pattern
|
||||||
|
```cpp
|
||||||
|
// Post work to background thread; return a callback for the main thread
|
||||||
|
worker_->post([this]() -> rpc::RPCWorker::MainCb {
|
||||||
|
json result = rpc_->call("getinfo"); // Runs on worker thread (blocking OK)
|
||||||
|
return [this, result]() {
|
||||||
|
state_.connected = true; // Runs on main thread via drainResults()
|
||||||
|
};
|
||||||
|
});
|
||||||
|
```
|
||||||
|
`drainResults()` is called each frame in `App::update()` to execute completed callbacks.
|
||||||
|
|
||||||
|
## RPC Architecture
|
||||||
|
|
||||||
|
**Dual-client design:**
|
||||||
|
- `rpc_` + `worker_` — main polling (balance, transactions, sync status)
|
||||||
|
- `fast_rpc_` + `fast_worker_` — console commands, mining stats
|
||||||
|
|
||||||
|
Both are `RPCClient` instances wrapping libcurl for JSON-RPC over HTTPS.
|
||||||
|
|
||||||
|
**Callback types:**
|
||||||
|
```cpp
|
||||||
|
using Callback = std::function<void(const json&)>;
|
||||||
|
using ErrorCallback = std::function<void(const std::string&)>;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error flow:** RPC errors throw `std::runtime_error` → caught in `doRPC()` → invokes
|
||||||
|
`ErrorCallback` → surfaces via `Notifications::instance().error(msg)`.
|
||||||
|
|
||||||
|
**Connection state:** `state_.connected` (app-level, set in `onConnected()`) vs
|
||||||
|
`rpc_->isConnected()` (per-client, set after successful `getinfo()`). These can differ —
|
||||||
|
always check the right one for the context.
|
||||||
|
|
||||||
|
## Connection Lifecycle
|
||||||
|
|
||||||
|
```
|
||||||
|
[Disconnected] → tryConnect() every 5s
|
||||||
|
→ auto-detect DRAGONX.conf (host, port, rpcuser, rpcpassword)
|
||||||
|
→ if no config: start embedded daemon → retry
|
||||||
|
→ post async rpc_->connect() to worker_
|
||||||
|
→ success: onConnected() → state_.connected = true
|
||||||
|
→ auth 401: try .cookie auth → retry
|
||||||
|
→ failure: onDisconnected(reason) → may restart daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
## UI Patterns
|
||||||
|
|
||||||
|
### Page Routing
|
||||||
|
`NavPage` enum in `src/ui/sidebar.h` defines all pages. `App::update()` dispatches
|
||||||
|
via switch on `current_page_` to render functions like `RenderBalanceTab(this)` or
|
||||||
|
`console_tab_.render(...)`.
|
||||||
|
|
||||||
|
### Dialogs
|
||||||
|
Modal dialogs use `show_*` boolean flags (e.g., `show_import_key_`, `show_backup_`).
|
||||||
|
Set the flag to `true` to open; the dialog renders in `App::update()` and clears
|
||||||
|
the flag when dismissed.
|
||||||
|
|
||||||
|
### Notifications
|
||||||
|
```cpp
|
||||||
|
Notifications::instance().success("Transaction sent");
|
||||||
|
Notifications::instance().error("Insufficient funds");
|
||||||
|
```
|
||||||
|
Toast-style popups in the bottom-right corner.
|
||||||
|
|
||||||
|
### Lock Screen & Loading Overlay
|
||||||
|
- Lock screen gates all interaction when `state_.isLocked()`
|
||||||
|
- Loading overlay shown while daemon isn't ready, gates all tabs except Peers, Console, Settings
|
||||||
|
|
||||||
|
## Platform Abstractions
|
||||||
|
|
||||||
|
Detection: `#ifdef _WIN32` / `#elif __APPLE__` / `#elif __linux__`
|
||||||
|
|
||||||
|
Platform-specific files live in `src/platform/` (Windows only: DX11 context, backdrop effects).
|
||||||
|
Shared platform utilities in `src/util/platform.h` — `openUrl()`, `getHomeDir()`, `getDragonXDataDir()`.
|
||||||
|
|
||||||
|
Rendering backends:
|
||||||
|
- Windows: DirectX 11 (`imgui_impl_dx11`)
|
||||||
|
- macOS/Linux: OpenGL 3 (`imgui_impl_opengl3`) + GLAD loader
|
||||||
|
|
||||||
|
## Build System
|
||||||
|
|
||||||
|
CMake 3.20+, C++17. Single `CMakeLists.txt` at root.
|
||||||
|
|
||||||
|
**FetchContent dependencies:** SDL3, nlohmann/json v3.11.3, toml++ v3.4.0, libcurl (Windows only)
|
||||||
|
**Bundled libraries:** ImGui, GLAD, miniz, libsodium (pre-built per platform), qrcode
|
||||||
|
|
||||||
|
**macOS:** Universal binary (arm64+x86_64), deployment target 11.0 (Big Sur+).
|
||||||
|
Set `CMAKE_OSX_DEPLOYMENT_TARGET` and `CMAKE_OSX_ARCHITECTURES` before `project()`.
|
||||||
|
|
||||||
|
**Build commands:**
|
||||||
|
```bash
|
||||||
|
./build.sh # Dev build
|
||||||
|
./build.sh --mac-release # macOS universal .app + DMG
|
||||||
|
./build.sh --linux-release # Linux AppImage + zip
|
||||||
|
./build.sh --win-release # Windows cross-compile
|
||||||
|
```
|
||||||
|
|
||||||
|
## Theme System
|
||||||
|
|
||||||
|
UI layout values are defined in `res/themes/ui.toml` and accessed via `schema::UI()` —
|
||||||
|
**never hardcode pixel sizes in C++ code**.
|
||||||
|
|
||||||
|
Skins are self-contained TOML files in `res/themes/` defining color palettes.
|
||||||
|
`scripts/expand_themes.py` merges layout sections from `ui.toml` into each skin at build time.
|
||||||
|
|
||||||
|
Colors support CSS-style variables: `--primary`, `--surface`, `--on-surface-medium`, resolved
|
||||||
|
by `ColorVarResolver` at runtime.
|
||||||
|
|
||||||
|
## Internationalization
|
||||||
|
|
||||||
|
All user-visible strings use `TR("key")` macro → `dragonx::util::tr()` → lookup in
|
||||||
|
`I18n` singleton. Never hardcode English strings in UI code.
|
||||||
|
|
||||||
|
Language files: `res/lang/{locale}.json` (runtime) with embedded fallback compiled into binary.
|
||||||
|
Supported: en, es, zh, ru, de, fr, pt, ja, ko.
|
||||||
|
|
||||||
|
## Key Rules
|
||||||
|
|
||||||
|
1. **Never block the main thread** — all network/disk I/O goes through `worker_->post()`
|
||||||
|
2. **Never hardcode pixel sizes** — use `ui.toml` schema values via `schema::UI()`
|
||||||
|
3. **Always use `TR()` for strings** — no hardcoded English in UI rendering code
|
||||||
|
4. **Use `ICON_MD_*` for icons** — Material Design icon font, never raw Unicode
|
||||||
|
5. **Use `std::unique_ptr`** — no raw `new`/`delete` in application code
|
||||||
|
6. **Check the right connection state** — `state_.connected` for app-level, `rpc_->isConnected()` for per-client
|
||||||
|
7. **Test all three platforms** — build must pass Linux; cross-compile test if touching platform code
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
# ObsidianDragon — Architecture Guide
|
|
||||||
|
|
||||||
A native C++17 desktop wallet for DragonX (DRGX), built with ImGui + SDL3.
|
|
||||||
|
|
||||||
## Directory Layout
|
|
||||||
|
|
||||||
```
|
|
||||||
src/
|
|
||||||
├── main.cpp Entry point, SDL3/backend init, render loop
|
|
||||||
├── app.h / app.cpp App class: init, shutdown, frame dispatch
|
|
||||||
├── app_network.cpp RPC connection, data refresh, mining ops
|
|
||||||
├── app_security.cpp Encryption, lock screen, PIN management
|
|
||||||
├── app_wizard.cpp First-run setup wizard
|
|
||||||
├── config/
|
|
||||||
│ └── settings.h/.cpp JSON settings persistence (~/.config/ObsidianDragon/)
|
|
||||||
├── daemon/
|
|
||||||
│ ├── embedded_daemon.h/.cpp dragonxd process lifecycle
|
|
||||||
│ └── xmrig_manager.h/.cpp xmrig-hac pool mining management
|
|
||||||
├── rpc/
|
|
||||||
│ ├── rpc_client.h/.cpp JSON-RPC over HTTPS (libcurl)
|
|
||||||
│ ├── rpc_worker.h/.cpp Background work queue + main-thread drain
|
|
||||||
│ ├── connection.h/.cpp DRAGONX.conf auto-detection
|
|
||||||
│ └── types.h Transaction, address data types
|
|
||||||
├── ui/
|
|
||||||
│ ├── sidebar.h NavPage enum, sidebar rendering
|
|
||||||
│ ├── notifications.h/.cpp Toast notification system
|
|
||||||
│ ├── schema/
|
|
||||||
│ │ ├── ui_schema.h/.cpp UISchema singleton (TOML → typed lookups)
|
|
||||||
│ │ ├── skin_manager.h/.cpp Skin enumeration, switching, import
|
|
||||||
│ │ └── color_var_resolver.h/.cpp CSS-style color resolution
|
|
||||||
│ └── windows/ Per-tab render functions (console, settings, etc.)
|
|
||||||
├── util/
|
|
||||||
│ ├── i18n.h/.cpp Internationalization (TR() macro, I18n singleton)
|
|
||||||
│ ├── platform.h/.cpp Cross-platform utilities (paths, URLs)
|
|
||||||
│ └── logger.h DEBUG_LOGF / VERBOSE_LOGF macros
|
|
||||||
├── platform/ Windows-specific (DX11 context, backdrop effects)
|
|
||||||
├── embedded/ Build-generated headers (embedded resources)
|
|
||||||
└── resources/ Runtime resource loading (fonts, images)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Threading Model
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────────┐
|
|
||||||
│ Main Thread (UI) │
|
|
||||||
│ • ImGui render loop (App::update()) │
|
|
||||||
│ • drainResults() each frame → executes completed callbacks │
|
|
||||||
│ • NEVER does blocking I/O │
|
|
||||||
└────────────┬────────────────────────┬───────────────────────┘
|
|
||||||
│ post() │ post()
|
|
||||||
▼ ▼
|
|
||||||
┌────────────────────┐ ┌────────────────────────────────┐
|
|
||||||
│ worker_ (RPCWorker)│ │ fast_worker_ (RPCWorker) │
|
|
||||||
│ General RPC polling│ │ Console commands, hashrate │
|
|
||||||
│ refreshData() 5s │ │ Avoids head-of-line blocking │
|
|
||||||
└────────────────────┘ └────────────────────────────────┘
|
|
||||||
|
|
||||||
┌────────────────────────────────────────────┐
|
|
||||||
│ Monitor Threads (per child process) │
|
|
||||||
│ • EmbeddedDaemon: reads dragonxd stdout │
|
|
||||||
│ • XmrigManager: reads xmrig-hac stdout │
|
|
||||||
└────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Work Submission Pattern
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
worker_->post([this]() -> rpc::RPCWorker::MainCb {
|
|
||||||
json result = rpc_->call("getinfo"); // Runs on worker thread
|
|
||||||
return [this, result]() {
|
|
||||||
state_.connected = true; // Runs on main thread
|
|
||||||
};
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## RPC Architecture
|
|
||||||
|
|
||||||
**Dual-client design** avoids head-of-line blocking:
|
|
||||||
|
|
||||||
| Client | Worker | Purpose |
|
|
||||||
|--------|--------|---------|
|
|
||||||
| `rpc_` | `worker_` | Main polling: balance, transactions, sync status |
|
|
||||||
| `fast_rpc_` | `fast_worker_` | Console commands, mining stats |
|
|
||||||
|
|
||||||
Both are `RPCClient` instances wrapping libcurl for JSON-RPC over HTTPS to `dragonxd`.
|
|
||||||
|
|
||||||
**Error flow:** `RPCClient::call()` throws `std::runtime_error` →
|
|
||||||
caught in worker lambda → error string captured → `MainCb` calls
|
|
||||||
`Notifications::instance().error(msg)` on main thread.
|
|
||||||
|
|
||||||
## Connection Lifecycle
|
|
||||||
|
|
||||||
```
|
|
||||||
[Disconnected] → tryConnect() every 5s
|
|
||||||
→ auto-detect DRAGONX.conf (host, port, rpcuser, rpcpassword)
|
|
||||||
→ if no config: start embedded daemon → retry
|
|
||||||
→ post async rpc_->connect() to worker_
|
|
||||||
→ success: onConnected() → state_.connected = true
|
|
||||||
→ auth 401: try .cookie auth → retry
|
|
||||||
→ failure: onDisconnected(reason) → may restart daemon
|
|
||||||
```
|
|
||||||
|
|
||||||
## UI System
|
|
||||||
|
|
||||||
### Page Routing
|
|
||||||
`NavPage` enum defines all pages. `App::update()` dispatches via switch on
|
|
||||||
`current_page_` to render functions (e.g., `RenderBalanceTab(this)`).
|
|
||||||
|
|
||||||
### Theme System
|
|
||||||
- Layout defined in `res/themes/ui.toml`, accessed via `schema::UI()`
|
|
||||||
- Skins are TOML files in `res/themes/` defining color palettes
|
|
||||||
- `scripts/expand_themes.py` merges layout into skins at build time
|
|
||||||
- Colors support CSS-style variables resolved by `ColorVarResolver`
|
|
||||||
- Hot-reload: `UISchema::pollForChanges()` watches file mtime
|
|
||||||
|
|
||||||
### Internationalization
|
|
||||||
- All UI strings use `TR("key")` macro → `I18n` singleton lookup
|
|
||||||
- Language files: `res/lang/{locale}.json` with compiled-in fallbacks
|
|
||||||
- Supported: en, es, zh, ru, de, fr, pt, ja, ko
|
|
||||||
|
|
||||||
### Notifications
|
|
||||||
```cpp
|
|
||||||
Notifications::instance().success("Transaction sent");
|
|
||||||
Notifications::instance().error("Insufficient funds");
|
|
||||||
```
|
|
||||||
Toast-style popups, bottom-right corner, 5-second default duration.
|
|
||||||
|
|
||||||
## Build System
|
|
||||||
|
|
||||||
CMake 3.20+, C++17. FetchContent for SDL3, nlohmann/json, toml++.
|
|
||||||
Bundled: ImGui, GLAD, miniz, libsodium, qrcode.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./build.sh # Dev build
|
|
||||||
./build.sh --mac-release # macOS universal .app + DMG
|
|
||||||
./build.sh --linux-release # Linux AppImage + zip
|
|
||||||
./build.sh --win-release # Windows cross-compile (MinGW)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Platform Backends
|
|
||||||
| Platform | Renderer | Notes |
|
|
||||||
|----------|----------|-------|
|
|
||||||
| Windows | DirectX 11 | `imgui_impl_dx11`, backdrop effects |
|
|
||||||
| macOS | OpenGL 3 | Universal binary (arm64+x86_64), target 11.0+ |
|
|
||||||
| Linux | OpenGL 3 | GLAD loader |
|
|
||||||
|
|
||||||
## Key Conventions
|
|
||||||
|
|
||||||
1. **Never block the main thread** — all I/O goes through `worker_->post()`
|
|
||||||
2. **Never hardcode pixel sizes** — use `schema::UI()` lookups from `ui.toml`
|
|
||||||
3. **Always use `TR()` for strings** — no hardcoded English in UI code
|
|
||||||
4. **Use `ICON_MD_*` for icons** — Material Design icon font
|
|
||||||
5. **`std::unique_ptr` for ownership** — no raw `new`/`delete`
|
|
||||||
6. **Check the right connection state** — `state_.connected` vs `rpc_->isConnected()`
|
|
||||||
1
docs/ARCHITECTURE.md
Symbolic link
1
docs/ARCHITECTURE.md
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../ObsidianDragon-agent/ARCHITECTURE.md
|
||||||
Reference in New Issue
Block a user