fix(mesh): Meshtastic 3ccc pkc_capable pill + Sideband image interop + critical CBOR wire-bloat fix
Merges in the meshtastic agent's now-finished work alongside this session's
continuation: stock-peer (3ccc) PKI-capability is now stamped through
get_contacts -> refresh_contacts -> MeshPeer.pkc_capable, so a directed DM to/from
a PKC-capable stock Meshtastic peer correctly shows the E2E pill on the Sent row,
not just received messages. Confirmed live: .198 sees "Meshtastic 3ccc" with
pkc_capable=true.
Also fixes two real interop/correctness bugs found while live-testing the
Reticulum <-> Sideband link:
- Receive: the daemon only ever read LXMF's plain-text content, silently
dropping native FIELD_IMAGE/FIELD_FILE_ATTACHMENTS fields — a stock
Sideband/NomadNet photo vanished into a blank-space message. Now decoded
into the same ContentInline typed envelope our own attachments use.
- Send: images to a non-archy (stock) peer now use native LXMF FIELD_IMAGE
instead of our own opaque CBOR wire format, which Sideband can't decode.
- Root cause of a garbled MC-chunk-fragment bug: TypedEnvelope.v/.sig (the
OUTER wrapper every message type uses) serialized raw bytes as a CBOR
array-of-integers instead of a native byte string, bloating every
message on the wire ~2-3.5x — enough to push even a tiny ReadReceipt
over the 140-byte single-frame chunking threshold. Root-caused by
reading ciborium's deserializer source directly (deserialize_bytes only
works within its internal scratch buffer; deserialize_byte_buf streams
unbounded).
Frontend: consolidated the attach/record buttons into a single animated "+"
menu (was overflowing the compose row).
857/857 tests pass. Verified live across all 5 deploy-roster nodes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
f54c853128
commit
0eb5c258f5
@@ -1241,6 +1241,39 @@ impl MeshService {
|
||||
.await)
|
||||
}
|
||||
|
||||
/// Send an image via native LXMF `FIELD_IMAGE` instead of our own typed
|
||||
/// envelope — for a stock (non-archy) peer that can't decode our CBOR
|
||||
/// wire format. Caller (the RPC layer) gates this on
|
||||
/// `!is_archy_peer(contact_id)`; low-level "just send the bytes" shape
|
||||
/// mirroring `send_raw_payload` — does NOT record a Sent MeshMessage
|
||||
/// itself, callers use `record_sent_typed` same as the typed-envelope
|
||||
/// paths so the Sent card renders identically regardless of which wire
|
||||
/// format actually went out.
|
||||
pub async fn send_native_image(
|
||||
&self,
|
||||
contact_id: u32,
|
||||
mime: &str,
|
||||
bytes: Vec<u8>,
|
||||
caption: Option<String>,
|
||||
) -> Result<()> {
|
||||
let status = self.state.status.read().await;
|
||||
if !status.device_connected {
|
||||
anyhow::bail!("No mesh device connected");
|
||||
}
|
||||
drop(status);
|
||||
let dest_prefix = self.peer_dest_prefix(contact_id).await?;
|
||||
self.state
|
||||
.send_cmd(listener::MeshCommand::SendNativeImage {
|
||||
dest_pubkey_prefix: dest_prefix,
|
||||
mime: mime.to_string(),
|
||||
bytes,
|
||||
caption,
|
||||
})
|
||||
.await
|
||||
.map_err(|_| anyhow::anyhow!("Mesh listener not running"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Send a typed envelope over a dedicated Reticulum RNS Resource transfer
|
||||
/// (`MeshCommand::SendResource`) instead of the small inline-chunk path
|
||||
/// `send_typed_wire`/`send_raw_payload` uses. Callers (the `mesh.send-content-inline`
|
||||
@@ -1696,7 +1729,7 @@ impl MeshService {
|
||||
/// only once we've learned their archipelago identity (DID or x25519 key,
|
||||
/// from federation seeding or an identity exchange). Stock clients have
|
||||
/// neither, so we send them plain text rather than typed envelopes.
|
||||
async fn is_archy_peer(&self, contact_id: u32) -> bool {
|
||||
pub(crate) async fn is_archy_peer(&self, contact_id: u32) -> bool {
|
||||
if contact_id & 0x8000_0000 != 0 {
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user