fix(mesh): message federation contacts without a radio (fixes 'Missing contact_id')
Messaging a federation-only peer (e.g. 'Arch Dev') failed with 'Missing contact_id'. The UI gave federation-only rows a *negative* placeholder contact_id derived from a DID hash, but the backend parses contact_id as u64, so a negative value deserialized to None. The negative id also never matched the positive federation-synthetic id that federation-routed messages are stored under, so those threads looked empty. - Frontend: derive the SAME positive federation-synthetic id the backend uses (federationContactId mirrors federation_peer_contact_id) so mesh.send accepts it and messages thread correctly. - Backend: send_typed_wire now resolves a federation-synthetic contact_id from nodes.json when it isn't in the live mesh peer table (radio-less node), instead of bailing 'Unknown federation peer'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e456c9701b
commit
1ea3f8d65c
@@ -825,15 +825,33 @@ impl MeshService {
|
||||
let is_federation_synthetic = contact_id & 0x8000_0000 != 0;
|
||||
let exceeds_lora = wire.len() > protocol::MAX_MESSAGE_LEN;
|
||||
if is_federation_synthetic || exceeds_lora {
|
||||
let (peer_pubkey, peer_did) = {
|
||||
// Resolve the peer's pubkey/did. Prefer the live mesh peer table,
|
||||
// but fall back to federation storage for federation-synthetic ids
|
||||
// that were never seeded into `state.peers` — e.g. a radio-less
|
||||
// node where the mesh device table is empty. Without this fallback
|
||||
// chatting a federation contact bails "Unknown federation peer"
|
||||
// even though we know its onion from nodes.json.
|
||||
let from_table = {
|
||||
let peers = self.state.peers.read().await;
|
||||
match peers.get(&contact_id) {
|
||||
Some(p) => (p.pubkey_hex.clone(), p.did.clone()),
|
||||
None if is_federation_synthetic => {
|
||||
anyhow::bail!("Unknown federation peer {}", contact_id);
|
||||
peers
|
||||
.get(&contact_id)
|
||||
.map(|p| (p.pubkey_hex.clone(), p.did.clone()))
|
||||
};
|
||||
let (peer_pubkey, peer_did) = match from_table {
|
||||
Some(v) => v,
|
||||
None if is_federation_synthetic => {
|
||||
let nodes = crate::federation::load_nodes(&self.data_dir)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
match nodes
|
||||
.iter()
|
||||
.find(|n| federation_peer_contact_id(&n.pubkey) == contact_id)
|
||||
{
|
||||
Some(n) => (Some(n.pubkey.clone()), Some(n.did.clone())),
|
||||
None => anyhow::bail!("Unknown federation peer {}", contact_id),
|
||||
}
|
||||
None => (None, None),
|
||||
}
|
||||
None => (None, None),
|
||||
};
|
||||
let nodes = crate::federation::load_nodes(&self.data_dir)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user