feat(history): dedupe by call_id + explicit Incoming/Outgoing/Missed labels
User reported that outgoing direct calls from macOS show up in the history list as "missed" even when the call completes successfully. Adds two changes to fix / diagnose: 1. history::log now dedupes by call_id. If an entry for this call_id already exists in the store, it updates the existing row's direction + timestamp in place instead of appending a duplicate. Protects against double-emit (caller side adding Missed on top of Placed, or any future signal loop that fires twice). One row per call_id, which matches what the user intuitively expects. 2. history::log now logs every write with tracing::info — call_id, peer_fp, direction, alias. Plus an extra line when we replace an existing entry: "history::log replacing existing entry from=Placed to=Missed" etc. Makes it easy to see in the desktop stderr which side is writing what, so we can find the outgoing => missed regression immediately if it recurs. 3. main.ts now renders an explicit text label next to the direction arrow: "Outgoing", "Incoming", or "Missed" instead of just the ↗ ↙ ✗ icons. Removes any ambiguity about what the icon means so future users can't misread a Placed entry as Missed based on icon shape alone. Side fix for scripts/build-windows-cloud.sh: - die() and the do_full ERR trap now respect WZP_KEEP_VM=1 so a failed build doesn't auto-destroy the debug VM (previously the trap fired before the KEEP_VM check and tore down the VM on any error). - Bump default server type cx23 → cx33. 4GB RAM is not enough for a cold tauri + rustls + quinn + wzp-client cross-compile — the cx23 run got "Read from remote host ... Connection reset by peer" partway through rustc, which is the classic signature of an OOM kill on the SSH session. cx33 has 8GB RAM and 8 vCPU which should comfortably fit the build.
This commit is contained in:
@@ -100,14 +100,33 @@ pub fn log(
|
||||
peer_alias: Option<String>,
|
||||
direction: CallDirection,
|
||||
) {
|
||||
tracing::info!(
|
||||
%call_id, %peer_fp, ?direction,
|
||||
alias = ?peer_alias,
|
||||
"history::log"
|
||||
);
|
||||
let entry = CallHistoryEntry {
|
||||
call_id,
|
||||
call_id: call_id.clone(),
|
||||
peer_fp,
|
||||
peer_alias,
|
||||
direction,
|
||||
timestamp_unix: now_unix(),
|
||||
};
|
||||
let mut guard = store().write().unwrap();
|
||||
// If an entry for this call_id already exists, update it in-place
|
||||
// rather than appending a duplicate. Protects against the caller
|
||||
// side adding a second Missed row when the callee's DirectCallOffer
|
||||
// bounces back through federation / loopback, or when some future
|
||||
// relay routing edge case double-emits a signal. The dedup keeps
|
||||
// history tidy and matches what the user intuitively expects (one
|
||||
// history row per call, not one per signal event).
|
||||
if let Some(existing) = guard.iter_mut().rev().find(|e| e.call_id == call_id) {
|
||||
tracing::info!(%call_id, from = ?existing.direction, to = ?direction, "history::log replacing existing entry");
|
||||
existing.direction = direction;
|
||||
existing.timestamp_unix = entry.timestamp_unix;
|
||||
save_to_disk(&guard);
|
||||
return;
|
||||
}
|
||||
guard.push(entry);
|
||||
if guard.len() > MAX_ENTRIES {
|
||||
let drop_n = guard.len() - MAX_ENTRIES;
|
||||
|
||||
@@ -819,6 +819,15 @@ function directionIcon(dir: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
function directionLabel(dir: string): string {
|
||||
switch (dir) {
|
||||
case "placed": return "Outgoing";
|
||||
case "received": return "Incoming";
|
||||
case "missed": return "Missed";
|
||||
default: return dir;
|
||||
}
|
||||
}
|
||||
|
||||
function directionClass(dir: string): string {
|
||||
return `dir-${dir}`;
|
||||
}
|
||||
@@ -866,7 +875,7 @@ async function refreshHistory() {
|
||||
<span class="history-dir">${directionIcon(e.direction)}</span>
|
||||
<div class="history-meta">
|
||||
<span class="history-peer">${label}</span>
|
||||
<span class="history-time">${fmtTimestamp(e.timestamp_unix)}</span>
|
||||
<span class="history-time">${directionLabel(e.direction)} · ${fmtTimestamp(e.timestamp_unix)}</span>
|
||||
</div>
|
||||
<button class="history-call-btn" title="Call back">Call</button>
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user