v0.0.8: Server-side message deduplication

Server:
- DedupTracker in AppState: bounded HashSet (10,000 IDs, FIFO eviction)
- send_message: extracts message ID from bincode, drops duplicates
- WS handler: dedup on both binary and JSON message frames
- extract_message_id() parses all WireMessage variants

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-03-27 11:00:58 +04:00
parent 708080f7be
commit 2599ce956a
5 changed files with 102 additions and 7 deletions

View File

@@ -17,9 +17,25 @@ use axum::{
Router,
};
use futures_util::{SinkExt, StreamExt};
use warzone_protocol::message::WireMessage;
use crate::state::AppState;
/// Try to extract the message ID from raw bincode-serialized WireMessage bytes.
fn extract_message_id(data: &[u8]) -> Option<String> {
if let Ok(wire) = bincode::deserialize::<WireMessage>(data) {
match wire {
WireMessage::KeyExchange { id, .. } => Some(id),
WireMessage::Message { id, .. } => Some(id),
WireMessage::FileHeader { id, .. } => Some(id),
WireMessage::FileChunk { id, .. } => Some(id),
WireMessage::Receipt { message_id, .. } => Some(message_id),
}
} else {
None
}
}
pub fn routes() -> Router<AppState> {
Router::new().route("/ws/:fingerprint", get(ws_handler))
}
@@ -90,6 +106,14 @@ async fn handle_socket(socket: WebSocket, state: AppState, fingerprint: String)
let to_fp = normalize_fp(&header);
let message = &data[64..];
// Dedup: skip if we already processed this message ID
if let Some(msg_id) = extract_message_id(message) {
if state_clone.dedup.check_and_insert(&msg_id) {
tracing::debug!("WS dedup: dropping duplicate binary message {}", msg_id);
continue;
}
}
// Try push to connected client first
if !state_clone.push_to_client(&to_fp, message).await {
// Queue in DB
@@ -110,6 +134,14 @@ async fn handle_socket(socket: WebSocket, state: AppState, fingerprint: String)
.filter_map(|v| v.as_u64().map(|n| n as u8))
.collect();
// Dedup: skip if we already processed this message ID
if let Some(msg_id) = extract_message_id(&message) {
if state_clone.dedup.check_and_insert(&msg_id) {
tracing::debug!("WS dedup: dropping duplicate JSON message {}", msg_id);
continue;
}
}
if !state_clone.push_to_client(&to_fp, &message).await {
let key = format!("queue:{}:{}", to_fp, uuid::Uuid::new_v4());
let _ = state_clone.db.messages.insert(key.as_bytes(), message);