feat(mesh): MessageKey foundation and debug-dump RPC

Adds sender_pubkey + sender_seq fields to MeshMessage so received
messages carry a stable cross-transport identity: (sender_pubkey,
sender_seq) pair. This is the foundation for the upcoming reply,
reaction, edit, and read-receipt variants — they need to target a
message by an ID that is meaningful on every node, not just locally.

Receive-side population lives in dispatch.rs::store_typed_message,
which now looks up the peer's pubkey_hex and copies envelope.seq from
the decoded TypedEnvelope. Sent-side population will land when we
plumb a per-node monotonic seq counter through the RPC layer.

Also adds mesh.debug-dump: a full in-memory state snapshot returning
peers, messages, status, shared-secret peer ids, encrypt_relay flag,
and stego mode — intended for smoke tests and bug investigation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-04-13 08:18:01 -04:00
co-authored by Claude Opus 4.6
parent ca7119df8c
commit 390ceaa75d
6 changed files with 79 additions and 5 deletions
+30
View File
@@ -432,6 +432,28 @@ impl MeshService {
messages.iter().skip(skip).cloned().collect()
}
/// Full in-memory state dump for debugging. Returns peers, all messages,
/// status, shared-secret peer ids (not the secrets), encrypt_relay flag,
/// and stego mode. Intended for development/smoke-test use only — don't
/// call this on a hot path.
pub async fn debug_dump(&self) -> serde_json::Value {
let status = self.state.status.read().await.clone();
let peers: Vec<_> = self.state.peers.read().await.values().cloned().collect();
let messages: Vec<_> = self.state.messages.read().await.iter().cloned().collect();
let secret_peer_ids: Vec<u32> =
self.state.shared_secrets.read().await.keys().copied().collect();
serde_json::json!({
"status": status,
"peers": peers,
"peer_count": peers.len(),
"messages": messages,
"message_count": messages.len(),
"secret_peer_ids": secret_peer_ids,
"encrypt_relay": self.state.encrypt_relay,
"stego_mode": format!("{:?}", self.state.stego_mode),
})
}
/// Resolve a peer's 6-byte public-key prefix for mesh addressing.
async fn peer_dest_prefix(&self, contact_id: u32) -> Result<[u8; 6]> {
let peers = self.state.peers.read().await;
@@ -547,6 +569,8 @@ impl MeshService {
encrypted: false,
message_type: type_label.to_string(),
typed_payload,
sender_pubkey: None,
sender_seq: None,
};
self.state.store_message(msg.clone()).await;
{
@@ -584,6 +608,8 @@ impl MeshService {
encrypted,
message_type: "text".to_string(),
typed_payload: None,
sender_pubkey: None,
sender_seq: None,
};
self.state.store_message(msg.clone()).await;
@@ -625,6 +651,8 @@ impl MeshService {
encrypted: false,
message_type: type_label.to_string(),
typed_payload,
sender_pubkey: None,
sender_seq: None,
};
self.state.store_message(msg.clone()).await;
{
@@ -678,6 +706,8 @@ impl MeshService {
encrypted: false,
message_type: "text".to_string(),
typed_payload: None,
sender_pubkey: None,
sender_seq: None,
};
self.state.store_message(msg.clone()).await;