v0.0.40: reliability — call reload, ETH cache prefill, 10 server tests

Call state reload on restart:
- Loads Ringing/Active calls from sled into active_calls on startup
- Expires calls older than 24h automatically

TUI sender ETH cache prefill:
- prefill_eth_cache() resolves all known contacts on poll_loop start
- First message from known contacts now shows ETH address immediately

Server integration tests (10 new):
- push_to_client offline/online
- register_ws + connection cap (5 max)
- is_online + device_count
- kick_device + revoke_all_except
- deliver_or_queue offline/online
- call state lifecycle
- list_devices

155 tests passing (was 135)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-03-29 17:39:47 +04:00
parent c37bd7934c
commit 1295f1c937
8 changed files with 207 additions and 4 deletions

View File

@@ -75,6 +75,30 @@ fn cache_eth_lookup(fp: &str, client: &ServerClient, eth_cache: &EthCache) {
});
}
/// Pre-populate the ETH cache for all known contacts.
pub async fn prefill_eth_cache(
db: &crate::storage::LocalDb,
client: &ServerClient,
eth_cache: &EthCache,
) {
if let Ok(contacts) = db.list_contacts() {
for c in &contacts {
if let Some(fp) = c.get("fingerprint").and_then(|v| v.as_str()) {
let fp = fp.to_string();
if eth_cache.lock().unwrap().contains_key(&fp) { continue; }
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()) {
eth_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);
@@ -584,6 +608,9 @@ pub async fn poll_loop(
let fp = normfp(&our_fp);
let eth_cache: EthCache = Arc::new(std::sync::Mutex::new(HashMap::new()));
// Pre-populate ETH cache for known contacts
prefill_eth_cache(&db, &client, &eth_cache).await;
// Try WebSocket first
let ws_url = client.base_url
.replace("http://", "ws://")