v0.0.23: ETH display everywhere, local build, web UX fixes
Version: 0.0.22 → 0.0.23, SW cache wz-v3 → wz-v4 TUI: - Own messages show ETH address (0x...) instead of fingerprint - Received messages: async ETH cache lookup (resolve on first sight) - /info shows Identity + Fingerprint - Welcome message shows ETH address Web: - Header shows only ETH address (single element, click to copy) - Own messages show ETH format - Received messages resolve sender ETH via /v1/resolve/ - /peer 0x... resolves via /v1/resolve/ endpoint - Click messages area → focuses text input Client: - register_bundle sends eth_address to server - ETH↔fingerprint mapping stored on registration Build: - --local: build on current machine (auto-detect apt/dnf/pacman/brew) - --local-ship: build locally + deploy to all servers - --local-clean: build + clean cargo cache Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -43,6 +43,38 @@ fn send_receipt(
|
||||
});
|
||||
}
|
||||
|
||||
/// ETH address cache: fingerprint → ETH address (populated async, read sync).
|
||||
pub type EthCache = Arc<std::sync::Mutex<HashMap<String, String>>>;
|
||||
|
||||
/// Display a fingerprint as short ETH address if cached, otherwise truncated fingerprint.
|
||||
fn display_sender(fp: &str, eth_cache: &EthCache) -> String {
|
||||
let cache = eth_cache.lock().unwrap();
|
||||
if let Some(eth) = cache.get(fp) {
|
||||
format!("{}...", ð[..eth.len().min(12)])
|
||||
} else {
|
||||
fp[..fp.len().min(12)].to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Async: look up ETH address for a fingerprint and cache it.
|
||||
fn cache_eth_lookup(fp: &str, client: &ServerClient, eth_cache: &EthCache) {
|
||||
let fp = fp.to_string();
|
||||
let client = client.clone();
|
||||
let cache = eth_cache.clone();
|
||||
// Check if already cached
|
||||
if cache.lock().unwrap().contains_key(&fp) { return; }
|
||||
tokio::spawn(async move {
|
||||
let url = format!("{}/v1/resolve/{}", client.base_url, fp);
|
||||
if let Ok(resp) = client.client.get(&url).send().await {
|
||||
if let Ok(data) = resp.json::<serde_json::Value>().await {
|
||||
if let Some(eth) = data.get("eth_address").and_then(|v| v.as_str()) {
|
||||
cache.lock().unwrap().insert(fp, eth.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn store_received(db: &LocalDb, sender_fp: &str, text: &str) {
|
||||
let _ = db.touch_contact(sender_fp, None);
|
||||
let _ = db.store_message(sender_fp, sender_fp, text, false);
|
||||
@@ -58,10 +90,11 @@ pub fn process_incoming(
|
||||
pending_files: &Arc<Mutex<HashMap<String, PendingFileTransfer>>>,
|
||||
our_fp: &str,
|
||||
client: &ServerClient,
|
||||
eth_cache: &EthCache,
|
||||
last_dm_peer: &Arc<Mutex<Option<String>>>,
|
||||
) {
|
||||
match bincode::deserialize::<WireMessage>(raw) {
|
||||
Ok(wire) => process_wire_message(wire, identity, db, messages, receipts, pending_files, our_fp, client, last_dm_peer),
|
||||
Ok(wire) => process_wire_message(wire, identity, db, messages, receipts, pending_files, our_fp, client, last_dm_peer, eth_cache),
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
@@ -76,6 +109,7 @@ fn process_wire_message(
|
||||
our_fp: &str,
|
||||
client: &ServerClient,
|
||||
last_dm_peer: &Arc<Mutex<Option<String>>>,
|
||||
eth_cache: &EthCache,
|
||||
) {
|
||||
match wire {
|
||||
WireMessage::KeyExchange {
|
||||
@@ -117,7 +151,7 @@ fn process_wire_message(
|
||||
}
|
||||
store_received(db, &sender_fingerprint, &text);
|
||||
messages.lock().unwrap().push(ChatLine {
|
||||
sender: sender_fingerprint[..sender_fingerprint.len().min(12)].to_string(),
|
||||
sender: { cache_eth_lookup(&sender_fingerprint, client, eth_cache); display_sender(&sender_fingerprint, eth_cache) },
|
||||
text,
|
||||
is_system: false,
|
||||
is_self: false,
|
||||
@@ -166,7 +200,7 @@ fn process_wire_message(
|
||||
}
|
||||
store_received(db, &sender_fingerprint, &text);
|
||||
messages.lock().unwrap().push(ChatLine {
|
||||
sender: sender_fingerprint[..sender_fingerprint.len().min(12)].to_string(),
|
||||
sender: { cache_eth_lookup(&sender_fingerprint, client, eth_cache); display_sender(&sender_fingerprint, eth_cache) },
|
||||
text,
|
||||
is_system: false,
|
||||
is_self: false,
|
||||
@@ -464,7 +498,7 @@ fn process_wire_message(
|
||||
} => {
|
||||
let type_str = format!("{:?}", signal_type);
|
||||
messages.lock().unwrap().push(ChatLine {
|
||||
sender: sender_fingerprint[..sender_fingerprint.len().min(12)].to_string(),
|
||||
sender: { cache_eth_lookup(&sender_fingerprint, client, eth_cache); display_sender(&sender_fingerprint, eth_cache) },
|
||||
text: format!("\u{1f4de} Call signal: {}", type_str),
|
||||
is_system: false,
|
||||
is_self: false,
|
||||
@@ -487,6 +521,7 @@ pub async fn poll_loop(
|
||||
connected: Arc<AtomicBool>,
|
||||
) {
|
||||
let fp = normfp(&our_fp);
|
||||
let eth_cache: EthCache = Arc::new(std::sync::Mutex::new(HashMap::new()));
|
||||
|
||||
// Try WebSocket first
|
||||
let ws_url = client.base_url
|
||||
@@ -511,7 +546,7 @@ pub async fn poll_loop(
|
||||
|
||||
while let Some(Ok(msg)) = read.next().await {
|
||||
if let tokio_tungstenite::tungstenite::Message::Binary(data) = msg {
|
||||
process_incoming(&data, &identity, &db, &messages, &receipts, &pending_files, &our_fp, &client, &last_dm_peer);
|
||||
process_incoming(&data, &identity, &db, &messages, &receipts, &pending_files, &our_fp, &client, ð_cache, &last_dm_peer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,7 +569,7 @@ pub async fn poll_loop(
|
||||
Err(_) => continue,
|
||||
};
|
||||
for raw in &raw_msgs {
|
||||
process_incoming(raw, &identity, &db, &messages, &receipts, &pending_files, &our_fp, &client, &last_dm_peer);
|
||||
process_incoming(raw, &identity, &db, &messages, &receipts, &pending_files, &our_fp, &client, ð_cache, &last_dm_peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user