From 1851728a099c1d74a997e61ca8675822edd500f3 Mon Sep 17 00:00:00 2001 From: Siavash Sameni Date: Sun, 29 Mar 2026 09:04:37 +0400 Subject: [PATCH] v0.0.24: ETH display in TUI header/messages, web peer resolve, click-focus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TUI: - Header shows peer ETH address (resolved on /peer set) - Own messages show ETH format - Resolve display shows full formatted fingerprint (xxxx:xxxx:...) - peer_eth field stored on App for header display Web: - Pasting 0x address in peer input box now resolves via /v1/resolve/ - Send path resolves 0x/@ before encrypting - Click messages area → focuses text input - Own messages show ETH format Version: 0.0.23 → 0.0.24, SW cache wz-v4 → wz-v5 Build script: --local, --local-ship, --local-clean commands Co-Authored-By: Claude Opus 4.6 (1M context) --- warzone/Cargo.lock | 10 ++++---- warzone/Cargo.toml | 2 +- .../crates/warzone-client/src/tui/commands.rs | 23 +++++++++++++++++-- warzone/crates/warzone-client/src/tui/draw.rs | 10 ++++---- .../crates/warzone-client/src/tui/types.rs | 3 +++ warzone/crates/warzone-protocol/Cargo.toml | 2 +- .../crates/warzone-server/src/routes/web.rs | 13 +++++------ 7 files changed, 43 insertions(+), 20 deletions(-) diff --git a/warzone/Cargo.lock b/warzone/Cargo.lock index 27cffb7..d1fb3e9 100644 --- a/warzone/Cargo.lock +++ b/warzone/Cargo.lock @@ -2956,7 +2956,7 @@ dependencies = [ [[package]] name = "warzone-client" -version = "0.0.22" +version = "0.0.24" dependencies = [ "anyhow", "argon2", @@ -2989,7 +2989,7 @@ dependencies = [ [[package]] name = "warzone-mule" -version = "0.0.22" +version = "0.0.24" dependencies = [ "anyhow", "clap", @@ -2998,7 +2998,7 @@ dependencies = [ [[package]] name = "warzone-protocol" -version = "0.0.22" +version = "0.0.24" dependencies = [ "base64", "bincode", @@ -3023,7 +3023,7 @@ dependencies = [ [[package]] name = "warzone-server" -version = "0.0.22" +version = "0.0.24" dependencies = [ "anyhow", "axum", @@ -3053,7 +3053,7 @@ dependencies = [ [[package]] name = "warzone-wasm" -version = "0.0.22" +version = "0.0.24" dependencies = [ "base64", "bincode", diff --git a/warzone/Cargo.toml b/warzone/Cargo.toml index 6ae20ae..1167562 100644 --- a/warzone/Cargo.toml +++ b/warzone/Cargo.toml @@ -9,7 +9,7 @@ members = [ ] [workspace.package] -version = "0.0.23" +version = "0.0.24" edition = "2021" license = "MIT" rust-version = "1.75" diff --git a/warzone/crates/warzone-client/src/tui/commands.rs b/warzone/crates/warzone-client/src/tui/commands.rs index 50fa676..fe7c4be 100644 --- a/warzone/crates/warzone-client/src/tui/commands.rs +++ b/warzone/crates/warzone-client/src/tui/commands.rs @@ -371,6 +371,8 @@ impl App { if text.starts_with("/peer ") || text.starts_with("/p ") { let text = if text.starts_with("/p ") { format!("/peer {}", &text[3..]) } else { text.clone() }; let raw = text[6..].trim().to_string(); + let is_eth_input = raw.starts_with("0x") || raw.starts_with("0X"); + let eth_input = if is_eth_input { Some(raw.clone()) } else { None }; let fp = if raw.starts_with('@') { match self.resolve_alias(&raw[1..], client).await { Some(resolved) => resolved, @@ -389,9 +391,22 @@ impl App { self.add_message(ChatLine { sender: "system".into(), text: "Cannot set yourself as peer".into(), is_system: true, is_self: false, message_id: None, timestamp: Local::now() }); return; } + // Resolve peer ETH for display + if is_eth_input { + self.peer_eth = eth_input; + } else { + // Try to look up ETH for this fingerprint + let resolve_url = format!("{}/v1/resolve/{}", client.base_url, normfp(&fp)); + if let Ok(resp) = client.client.get(&resolve_url).send().await { + if let Ok(data) = resp.json::().await { + self.peer_eth = data.get("eth_address").and_then(|v| v.as_str()).map(String::from); + } + } + } + let display = self.peer_eth.as_deref().unwrap_or(&fp); self.add_message(ChatLine { sender: "system".into(), - text: format!("Peer set to {}", fp), + text: format!("Peer set to {}", display), is_system: true, is_self: false, message_id: None, timestamp: Local::now(), @@ -938,7 +953,11 @@ impl App { Ok(resp) => { if let Ok(data) = resp.json::().await { if let Some(fp) = data.get("fingerprint").and_then(|v| v.as_str()) { - self.add_message(ChatLine { sender: "system".into(), text: format!("{} → {}", addr, &fp[..fp.len().min(16)]), is_system: true, is_self: false, message_id: None, timestamp: Local::now() }); + // Format fingerprint with colons: xxxx:xxxx:xxxx:... + let formatted: String = fp.chars().enumerate() + .flat_map(|(i, c)| if i > 0 && i % 4 == 0 { vec![':', c] } else { vec![c] }) + .collect(); + self.add_message(ChatLine { sender: "system".into(), text: format!("{} → {}", addr, formatted), is_system: true, is_self: false, message_id: None, timestamp: Local::now() }); return Some(fp.to_string()); } if let Some(err) = data.get("error") { diff --git a/warzone/crates/warzone-client/src/tui/draw.rs b/warzone/crates/warzone-client/src/tui/draw.rs index fb75fe3..94a8309 100644 --- a/warzone/crates/warzone-client/src/tui/draw.rs +++ b/warzone/crates/warzone-client/src/tui/draw.rs @@ -48,10 +48,12 @@ impl App { .split(frame.area()); // Header - let peer_str = self - .peer_fp - .as_deref() - .unwrap_or("no peer"); + let peer_str = match (&self.peer_eth, &self.peer_fp) { + (Some(eth), _) => format!("{}...", ð[..eth.len().min(12)]), + (None, Some(fp)) => fp.clone(), + (None, None) => "no peer".to_string(), + }; + let peer_str = peer_str.as_str(); let is_connected = self.connected.load(Ordering::Relaxed); let (conn_indicator, conn_color) = if is_connected { (" \u{25CF}", Color::Green) // ● diff --git a/warzone/crates/warzone-client/src/tui/types.rs b/warzone/crates/warzone-client/src/tui/types.rs index ec2de23..5782eab 100644 --- a/warzone/crates/warzone-client/src/tui/types.rs +++ b/warzone/crates/warzone-client/src/tui/types.rs @@ -43,6 +43,8 @@ pub struct App { pub pending_files: Arc>>, /// Our ETH address (derived from seed). pub our_eth: String, + /// Current peer's ETH address (resolved on /peer set). + pub peer_eth: Option, /// Scroll offset from bottom (0 = pinned to newest). pub scroll_offset: usize, /// Whether the WebSocket connection is active. @@ -123,6 +125,7 @@ impl App { receipts: Arc::new(Mutex::new(HashMap::new())), pending_files: Arc::new(Mutex::new(HashMap::new())), our_eth, + peer_eth: None, scroll_offset: 0, connected: Arc::new(AtomicBool::new(false)), } diff --git a/warzone/crates/warzone-protocol/Cargo.toml b/warzone/crates/warzone-protocol/Cargo.toml index 5b08ee6..56cd3cf 100644 --- a/warzone/crates/warzone-protocol/Cargo.toml +++ b/warzone/crates/warzone-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "warzone-protocol" -version = "0.0.23" +version = "0.0.24" edition = "2021" license = "MIT" description = "Core crypto & wire protocol for featherChat (Warzone messenger)" diff --git a/warzone/crates/warzone-server/src/routes/web.rs b/warzone/crates/warzone-server/src/routes/web.rs index dbabbe2..a98ac67 100644 --- a/warzone/crates/warzone-server/src/routes/web.rs +++ b/warzone/crates/warzone-server/src/routes/web.rs @@ -50,7 +50,7 @@ async fn pwa_manifest() -> impl IntoResponse { async fn service_worker() -> impl IntoResponse { ([(header::CONTENT_TYPE, "application/javascript")], r##" -const CACHE = 'wz-v4'; +const CACHE = 'wz-v5'; const SHELL = ['/', '/wasm/warzone_wasm.js', '/wasm/warzone_wasm_bg.wasm', '/icon.svg', '/manifest.json']; self.addEventListener('install', e => { @@ -242,7 +242,7 @@ let pollTimer = null; let ws = null; // WebSocket connection let wasmReady = false; -const VERSION = '0.0.23'; +const VERSION = '0.0.24'; let DEBUG = true; // toggle with /debug command // ── Receipt tracking ── @@ -1193,13 +1193,12 @@ async function doSend() { let peer = $peerInput.value.trim(); if (!peer || peer.startsWith('#')) { addSys('Set a peer fingerprint/@alias or use /g '); return; } - if (peer.startsWith('@')) { - const aliasName = peer.slice(1); - const resp = await fetch(SERVER + '/v1/alias/resolve/' + aliasName); + if (peer.startsWith('@') || peer.startsWith('0x') || peer.startsWith('0X')) { + const endpoint = peer.startsWith('@') ? '/v1/alias/resolve/' + peer.slice(1) : '/v1/resolve/' + peer; + const resp = await fetch(SERVER + endpoint); const data = await resp.json(); - if (data.error) { addSys('Unknown alias @' + aliasName); return; } + if (data.error) { addSys('Cannot resolve ' + peer + ': ' + data.error); return; } peer = data.fingerprint; - addSys('Resolved @' + aliasName + ' → ' + peer.slice(0,16) + '...'); } localStorage.setItem('wz-peer', $peerInput.value.trim());