Commit 8687234
feat(phase15): complete WRAITH Transfer desktop application (Phase 15)
Implements the complete WRAITH Transfer Tauri desktop application with
React/TypeScript frontend and Rust backend, enabling secure peer-to-peer
file transfers through the WRAITH Protocol.
## Sprint 15.1: FFI Core Library Bindings (wraith-ffi crate)
### C-Compatible FFI Layer (crates/wraith-ffi/ - 1,683 lines)
**lib.rs (180 lines) - Core FFI Infrastructure:**
- Opaque handle types: WraithNode, WraithConfig, WraithSession, WraithTransfer
- NodeHandle struct wrapping Arc<Node> + Arc<Runtime> for thread-safe access
- ConfigHandle for mutable configuration before node creation
- ffi_try! and ffi_try_ptr! macros for consistent error handling
- from_c_string helper for safe null-terminated string conversion
- Global tokio Runtime initialization with lazy_static
**node.rs (241 lines) - Node Lifecycle Management:**
- wraith_node_new() - Create node with random Ed25519 identity
- wraith_node_new_with_config() - Create with custom NodeConfig
- wraith_node_start() / wraith_node_stop() - Lifecycle control
- wraith_node_is_running() - State query
- wraith_node_get_id() - Get 32-byte node ID with caller-owned buffer
- wraith_node_free() - Clean resource deallocation
- All functions return WraithErrorCode with optional error_out parameter
**session.rs (203 lines) - Session Management:**
- wraith_session_establish() - Noise_XX handshake with peer
- wraith_session_close() - Graceful session termination
- wraith_session_get_peer_id() - Get 32-byte peer ID
- wraith_session_is_active() - Check session state
- wraith_session_free() - Session cleanup
- Proper Arc reference counting for session handles
**transfer.rs (249 lines) - File Transfer Operations:**
- wraith_transfer_send_file() - Initiate chunked file transfer
- wraith_transfer_get_progress() - Query TransferProgress struct
- wraith_transfer_cancel() - Abort active transfer
- wraith_transfer_wait() - Block until completion/failure
- wraith_transfer_free() - Transfer handle cleanup
- TransferProgress with bytes_sent/total, progress %, ETA, rate
**config.rs (299 lines) - Configuration API:**
- wraith_config_new() / wraith_config_free() - Lifecycle
- wraith_config_set_bind_address() - Network binding
- wraith_config_set_worker_threads() - Thread pool size
- wraith_config_set_connection_timeout() - Timeout in seconds
- wraith_config_set_chunk_size() - Transfer chunk size (bytes)
- wraith_config_enable_af_xdp() / enable_io_uring() - Kernel bypass
- All setters validate input and return appropriate error codes
**error.rs (230 lines) - Error Handling:**
- WraithErrorCode enum (20 codes): Success, InvalidArgument, NodeNotRunning,
SessionNotFound, TransferFailed, Timeout, CryptoError, TransportError, etc.
- WraithError struct with code, message, source for error chains
- From<NodeError> implementation mapping all 15 NodeError variants
- Thread-safe error propagation via optional error_out parameter
**types.rs (224 lines) - Type Definitions:**
- TransferProgress: bytes_sent, bytes_total, progress, eta_seconds, rate
- SessionInfo: peer_id, bytes_sent, bytes_received
- ConnectionHealth: rtt_ms, loss_rate, status
- All types #[repr(C)] for ABI compatibility
- Unit tests for struct sizes and alignment
**Build System:**
- build.rs with cbindgen integration for C header generation
- cbindgen.toml with C-style output, include guards, documentation
- Cargo.toml with cdylib + staticlib crate types
## Sprint 15.2: Tauri Desktop Shell
### Backend Implementation (clients/wraith-transfer/src-tauri/)
**lib.rs (83 lines) - Application Entry Point:**
- tracing_subscriber initialization with env-filter
- Tauri::Builder with plugin registration:
- tauri_plugin_log for structured logging
- tauri_plugin_dialog for native file dialogs
- tauri_plugin_fs for file system access
- tauri_plugin_shell for shell commands
- AppState managed state with Arc<RwLock<Option<Node>>>
- 10 IPC command handlers registered via generate_handler!
**commands.rs (326 lines) - IPC Command Handlers:**
- get_node_status() - NodeStatus with running, node_id, session/transfer counts
- start_node() - Create Node::new_with_config(), start(), store in state
- stop_node() - Graceful node.stop() and state cleanup
- get_node_id() - Hex-encoded 32-byte node identifier
- get_sessions() - List active SessionInfo with peer_id, timestamps, bytes
- close_session(peer_id) - Terminate specific peer session
- send_file(peer_id, file_path) - Initiate transfer, return transfer_id
- get_transfers() - List TransferInfo with progress, status, direction
- get_transfer_progress(transfer_id) - Detailed single transfer progress
- cancel_transfer(transfer_id) - Abort and cleanup transfer
**state.rs (62 lines) - Application State:**
- AppState with Arc<RwLock<Option<Node>>> for thread-safe node access
- HashMap<String, TransferInfo> for local transfer tracking
- Helper methods: is_node_running(), get_node_id_hex(), active_*_count()
**error.rs (53 lines) - Error Types:**
- AppError enum: Node, Session, Transfer, FileNotFound, InvalidPeerId, NodeNotRunning
- Serialize implementation for frontend consumption
- Into<InvokeError> for Tauri error propagation
**Configuration (tauri.conf.json):**
- App identifier: io.wraith.transfer
- Window: 1200x800 default, 800x600 minimum, centered, titlebar
- CSP: strict default-src, connect-src for localhost
- Tray icon support enabled
- Bundle: Windows (msi, nsis), macOS (dmg, app), Linux (deb, rpm, appimage)
## Sprint 15.3: React UI Foundation
### Frontend Implementation (clients/wraith-transfer/frontend/)
**Build System:**
- Vite 7.2.7 with React plugin and HMR
- TypeScript 5.8 strict mode
- Tailwind CSS v4 with @tailwindcss/vite plugin
- ESLint 9 with TypeScript and React Hooks rules
**Type Definitions (src/types/index.ts):**
- NodeStatus: running, node_id, active_sessions, active_transfers
- TransferInfo: id, peer_id, file_name, bytes, progress, status, direction
- SessionInfo: peer_id, established_at, bytes_sent, bytes_received
- ConnectionHealth: peer_id, rtt_ms, loss_rate, last_activity, status
**Tauri IPC Bindings (src/lib/tauri.ts):**
- Type-safe wrappers for all 10 backend commands
- invoke<T> with proper TypeScript generics
- Async/await patterns for all operations
**State Management (src/stores/):**
- nodeStore.ts - Zustand store for node status, start/stop actions
- transferStore.ts - Transfer list, sendFile, cancelTransfer actions
- sessionStore.ts - Session list, closeSession actions
- All stores with loading/error state handling
**Styling (src/index.css):**
- Tailwind v4 CSS-first configuration with @import "tailwindcss"
- @theme directive for custom properties
- WRAITH brand colors: wraith-primary (#7c3aed), wraith-secondary (#4f46e5),
wraith-accent (#06b6d4), bg-primary (#0f172a), bg-secondary (#1e293b)
## Sprint 15.4: Transfer UI Components
### React Components (src/components/)
**Header.tsx:**
- Connection status indicator (green/red dot)
- Node ID display (truncated hex)
- Active sessions/transfers counters
- Start/Stop node button with loading state
- Responsive layout with flex
**TransferList.tsx:**
- TransferItem subcomponent with:
- Upload/download direction indicator
- File name and peer ID (truncated)
- Progress bar with color-coded status
- Bytes transferred / total with auto-formatting
- Cancel button for active transfers
- Empty state with helpful message
- Status colors: initializing (yellow), in_progress (blue),
completed (green), failed (red), cancelled (gray)
**SessionPanel.tsx:**
- Fixed-width sidebar (w-72)
- SessionItem with peer ID, bytes sent/received
- Disconnect button per session
- Empty state when no sessions
**NewTransferDialog.tsx:**
- Modal overlay with backdrop blur
- Peer ID input (64-char hex validation)
- File picker using @tauri-apps/plugin-dialog
- Error display with red styling
- Cancel/Send buttons with loading state
**StatusBar.tsx:**
- Error message display
- Ready/start node status hints
- "New Transfer" action button
- Disabled state when node not running
**App.tsx:**
- Full-height flexbox layout
- Header, main (TransferList + SessionPanel), StatusBar
- 1-second polling interval when node running
- Dialog state management for NewTransferDialog
- useEffect hooks for initial fetch and polling
## Quality Assurance
- Zero clippy warnings with -D warnings
- All 1,303 workspace tests passing
- Frontend TypeScript strict mode enabled
- Production builds verified (Rust + Vite)
- Code formatted with cargo fmt and prettier
## Files Changed Summary
- 66 files changed, 7,765 insertions
- New crate: wraith-ffi (10 files, ~1,683 lines Rust)
- New client: wraith-transfer (56 files)
- Tauri backend: 5 Rust files (~530 lines)
- React frontend: ~20 source files (~800 lines TypeScript/TSX)
- Assets: 17 icon files for cross-platform bundles
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>1 parent 01493c6 commit 8687234
File tree
66 files changed
+7765
-0
lines changed- clients
- wraith-transfer
- frontend
- public
- src
- assets
- components
- lib
- stores
- types
- src-tauri
- capabilities
- icons
- src
- crates/wraith-ffi
- src
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
66 files changed
+7765
-0
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
10 | 71 | | |
11 | 72 | | |
12 | 73 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
| 18 | + | |
17 | 19 | | |
18 | 20 | | |
19 | 21 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
0 commit comments