Files
ObsidianDragon/ObsidianDragon-agent/copilot-instructions.md
DanS 5ebccceffc 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
2026-04-04 11:29:12 -05:00

176 lines
7.1 KiB
Markdown

# 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