style: cargo fmt the workspace (release-gate cargo-fmt was red)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
412251ac9a
commit
db4de0ac96
@@ -162,7 +162,10 @@ async fn status_line() -> String {
|
||||
} else {
|
||||
format!("electrum {:.0}%", e.progress_pct)
|
||||
};
|
||||
format!("Archipelago OS v{}: {btc}, {elec}.", env!("CARGO_PKG_VERSION"))
|
||||
format!(
|
||||
"Archipelago OS v{}: {btc}, {elec}.",
|
||||
env!("CARGO_PKG_VERSION")
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -141,7 +141,9 @@ impl MeshRadioDevice {
|
||||
anyhow::bail!("Native image send is Reticulum-only")
|
||||
}
|
||||
Self::Reticulum(device) => {
|
||||
device.send_native_image(dest_pubkey_prefix, mime, bytes, caption).await
|
||||
device
|
||||
.send_native_image(dest_pubkey_prefix, mime, bytes, caption)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -297,7 +299,9 @@ async fn auto_detect_and_open(
|
||||
info!(path = %path, "Found Reticulum (RNode) device via auto-detect");
|
||||
return Ok((path.clone(), MeshRadioDevice::Reticulum(dev), info));
|
||||
}
|
||||
Err(e) => debug!(path = %path, error = %e, "Reticulum daemon failed to initialize"),
|
||||
Err(e) => {
|
||||
debug!(path = %path, error = %e, "Reticulum daemon failed to initialize")
|
||||
}
|
||||
},
|
||||
Err(e) => debug!(path = %path, error = %e, "Not a Reticulum RNode"),
|
||||
}
|
||||
@@ -323,7 +327,9 @@ async fn auto_detect_and_open(
|
||||
}
|
||||
Err(e) => debug!(path = %path, error = %e, "Not a Meshtastic device"),
|
||||
},
|
||||
Err(e) => debug!(path = %path, error = %e, "Could not open serial port for Meshtastic"),
|
||||
Err(e) => {
|
||||
debug!(path = %path, error = %e, "Could not open serial port for Meshtastic")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -399,7 +405,9 @@ async fn open_preferred_path(
|
||||
{
|
||||
Ok(mut dev) => match dev.initialize().await {
|
||||
Ok(info) => return Ok((MeshRadioDevice::Reticulum(dev), info)),
|
||||
Err(e) => debug!(path = %path, error = %e, "Preferred path is not a working Reticulum RNode"),
|
||||
Err(e) => {
|
||||
debug!(path = %path, error = %e, "Preferred path is not a working Reticulum RNode")
|
||||
}
|
||||
},
|
||||
Err(e) => debug!(path = %path, error = %e, "Could not open preferred path as Reticulum"),
|
||||
}
|
||||
@@ -431,26 +439,22 @@ async fn open_reticulum_tcp(
|
||||
our_x25519_pubkey_hex: &str,
|
||||
) -> Result<(String, MeshRadioDevice, DeviceInfo)> {
|
||||
let mut dev = match cfg {
|
||||
ReticulumTcpConfig::Server { bind } => {
|
||||
ReticulumLink::open_tcp_server(
|
||||
bind,
|
||||
data_dir,
|
||||
Some(our_ed_pubkey_hex),
|
||||
Some(our_x25519_pubkey_hex),
|
||||
)
|
||||
.await
|
||||
.context("Could not open Reticulum TCP server interface")?
|
||||
}
|
||||
ReticulumTcpConfig::Client { connect } => {
|
||||
ReticulumLink::open_tcp_client(
|
||||
connect,
|
||||
data_dir,
|
||||
Some(our_ed_pubkey_hex),
|
||||
Some(our_x25519_pubkey_hex),
|
||||
)
|
||||
.await
|
||||
.context("Could not open Reticulum TCP client interface")?
|
||||
}
|
||||
ReticulumTcpConfig::Server { bind } => ReticulumLink::open_tcp_server(
|
||||
bind,
|
||||
data_dir,
|
||||
Some(our_ed_pubkey_hex),
|
||||
Some(our_x25519_pubkey_hex),
|
||||
)
|
||||
.await
|
||||
.context("Could not open Reticulum TCP server interface")?,
|
||||
ReticulumTcpConfig::Client { connect } => ReticulumLink::open_tcp_client(
|
||||
connect,
|
||||
data_dir,
|
||||
Some(our_ed_pubkey_hex),
|
||||
Some(our_x25519_pubkey_hex),
|
||||
)
|
||||
.await
|
||||
.context("Could not open Reticulum TCP client interface")?,
|
||||
};
|
||||
let info = dev
|
||||
.initialize()
|
||||
@@ -790,7 +794,9 @@ fn meshtastic_contact_id(public_key_hex: &str) -> Option<u32> {
|
||||
fn reticulum_contact_id(public_key_hex: &str) -> Option<u32> {
|
||||
let bytes = hex::decode(public_key_hex).ok()?;
|
||||
let hash: [u8; 16] = bytes.try_into().ok()?;
|
||||
Some(super::super::reticulum::reticulum_contact_id_from_hash(&hash))
|
||||
Some(super::super::reticulum::reticulum_contact_id_from_hash(
|
||||
&hash,
|
||||
))
|
||||
}
|
||||
|
||||
/// Drain any queued messages from the device.
|
||||
@@ -873,12 +879,23 @@ pub(super) async fn run_mesh_session(
|
||||
"Preferred path {} probe failed: {} — trying auto-detect",
|
||||
path, e
|
||||
);
|
||||
auto_detect_and_open(data_dir, our_ed_pubkey_hex, our_x25519_pubkey_hex, device_kind)
|
||||
.await?
|
||||
auto_detect_and_open(
|
||||
data_dir,
|
||||
our_ed_pubkey_hex,
|
||||
our_x25519_pubkey_hex,
|
||||
device_kind,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto_detect_and_open(data_dir, our_ed_pubkey_hex, our_x25519_pubkey_hex, device_kind).await?
|
||||
auto_detect_and_open(
|
||||
data_dir,
|
||||
our_ed_pubkey_hex,
|
||||
our_x25519_pubkey_hex,
|
||||
device_kind,
|
||||
)
|
||||
.await?
|
||||
};
|
||||
|
||||
// Update status
|
||||
|
||||
@@ -414,7 +414,11 @@ impl MeshtasticDevice {
|
||||
// tx_power defaults to max, which is what we want for a stock mesh.
|
||||
let mut lora = Vec::new();
|
||||
encode_varint_field_into(LORA_USE_PRESET_FIELD, 1, &mut lora);
|
||||
encode_varint_field_into(LORA_MODEM_PRESET_FIELD, LORA_MODEM_PRESET_LONG_FAST, &mut lora);
|
||||
encode_varint_field_into(
|
||||
LORA_MODEM_PRESET_FIELD,
|
||||
LORA_MODEM_PRESET_LONG_FAST,
|
||||
&mut lora,
|
||||
);
|
||||
encode_varint_field_into(LORA_REGION_FIELD, region_code as u64, &mut lora);
|
||||
encode_varint_field_into(LORA_HOP_LIMIT_FIELD, 3, &mut lora);
|
||||
encode_varint_field_into(LORA_TX_ENABLED_FIELD, 1, &mut lora);
|
||||
@@ -772,7 +776,9 @@ impl MeshtasticDevice {
|
||||
if let Err(e) = self.send_to_radio(&encode_want_config()).await {
|
||||
warn!("Failed to re-request config after radio reboot: {}", e);
|
||||
} else {
|
||||
info!("Re-requested Meshtastic config after reboot — packet stream resubscribed");
|
||||
info!(
|
||||
"Re-requested Meshtastic config after reboot — packet stream resubscribed"
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some(inbound) = inbound {
|
||||
@@ -890,7 +896,10 @@ impl MeshtasticDevice {
|
||||
if let Some((region, modem_preset)) = parse_config_lora_region(value) {
|
||||
self.current_region = Some(region);
|
||||
self.current_modem_preset = Some(modem_preset);
|
||||
debug!(region, modem_preset, "Meshtastic LoRa region/preset from device config");
|
||||
debug!(
|
||||
region,
|
||||
modem_preset, "Meshtastic LoRa region/preset from device config"
|
||||
);
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -1066,7 +1075,10 @@ fn packet_to_inbound_frame(
|
||||
|
||||
if packet.portnum == POSITION_APP {
|
||||
if let Some((lat, lon)) = parse_position_lat_lon(&packet.payload) {
|
||||
debug!(from = format!("!{:08x}", from), lat, lon, "Meshtastic position update");
|
||||
debug!(
|
||||
from = format!("!{:08x}", from),
|
||||
lat, lon, "Meshtastic position update"
|
||||
);
|
||||
contact.lat = Some(lat);
|
||||
contact.lon = Some(lon);
|
||||
}
|
||||
@@ -1811,10 +1823,10 @@ mod tests {
|
||||
encode_fixed32_field(1, 0x1111_2222, &mut packet); // from
|
||||
encode_len_field(4, &decoded, &mut packet); // decoded
|
||||
encode_fixed32_field(8, (-7.5f32).to_bits(), &mut packet); // rx_snr
|
||||
// int32 rx_rssi=-92 dBm, protobuf varint-encodes a negative int32 as
|
||||
// the 10-byte two's-complement-extended varint; truncating back to
|
||||
// i32 after decode recovers the original value (see parse_mesh_packet's
|
||||
// `v as i32` cast — confirmed by this roundtrip, not just asserted).
|
||||
// int32 rx_rssi=-92 dBm, protobuf varint-encodes a negative int32 as
|
||||
// the 10-byte two's-complement-extended varint; truncating back to
|
||||
// i32 after decode recovers the original value (see parse_mesh_packet's
|
||||
// `v as i32` cast — confirmed by this roundtrip, not just asserted).
|
||||
encode_varint_field_into(12, (-92i32) as u32 as u64, &mut packet);
|
||||
|
||||
let parsed = parse_mesh_packet(&packet).expect("packet should parse");
|
||||
@@ -1901,7 +1913,10 @@ mod tests {
|
||||
// must still update the contact's signal/position bookkeeping.
|
||||
let frame =
|
||||
packet_to_inbound_frame(&packet, Some(0x1111_1111), &mut contacts, &mut peer_pubkeys);
|
||||
assert!(frame.is_none(), "POSITION_APP must not surface as a chat frame");
|
||||
assert!(
|
||||
frame.is_none(),
|
||||
"POSITION_APP must not surface as a chat frame"
|
||||
);
|
||||
let contact = contacts.get(&from).expect("contact should be tracked");
|
||||
assert_eq!(contact.snr, Some(-6.0));
|
||||
assert_eq!(contact.rssi, Some(-80));
|
||||
@@ -1930,7 +1945,10 @@ mod tests {
|
||||
// A `to == BROADCAST_NUM` text is a channel broadcast (3ccc on public
|
||||
// LongFast), so it routes to the channel thread, carrying its sender.
|
||||
assert_eq!(frame.code, protocol::RESP_MESHTASTIC_CHANNEL_TEXT);
|
||||
assert_eq!(frame.data[0], 0, "no channel field set => primary/public (0)");
|
||||
assert_eq!(
|
||||
frame.data[0], 0,
|
||||
"no channel field set => primary/public (0)"
|
||||
);
|
||||
assert_eq!(&frame.data[1..7], &[0xcc, 0x3c, 0x00, 0x00, 0x6d, 0x65]);
|
||||
assert_eq!(&frame.data[7..], b"hello from 3ccc");
|
||||
assert!(contacts.contains_key(&from));
|
||||
@@ -1954,9 +1972,8 @@ mod tests {
|
||||
encode_len_field(4, &decoded, &mut packet);
|
||||
encode_fixed32_field(7, 12_345, &mut packet);
|
||||
|
||||
let frame =
|
||||
packet_to_inbound_frame(&packet, Some(me), &mut contacts, &mut peer_pubkeys)
|
||||
.expect("directed DM must surface");
|
||||
let frame = packet_to_inbound_frame(&packet, Some(me), &mut contacts, &mut peer_pubkeys)
|
||||
.expect("directed DM must surface");
|
||||
assert_eq!(frame.code, protocol::RESP_CONTACT_MSG_V3);
|
||||
let (sender_prefix, payload, _snr) =
|
||||
protocol::parse_contact_msg_v3_raw(&frame.data).unwrap();
|
||||
|
||||
@@ -213,7 +213,11 @@ pub struct TypedEnvelope {
|
||||
/// Unix timestamp (seconds since epoch).
|
||||
pub ts: u32,
|
||||
/// Optional Ed25519 signature of (t || v || ts_bytes) — for signed messages.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none", with = "compact_bytes_opt")]
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
with = "compact_bytes_opt"
|
||||
)]
|
||||
pub sig: Option<Vec<u8>>,
|
||||
/// Message sequence number (per-sender, monotonically increasing).
|
||||
#[serde(default)]
|
||||
@@ -564,7 +568,11 @@ pub struct ContentRefPayload {
|
||||
pub mime: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub filename: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none", with = "base64_opt_bytes")]
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
with = "base64_opt_bytes"
|
||||
)]
|
||||
pub thumb_bytes: Option<Vec<u8>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub caption: Option<String>,
|
||||
@@ -860,8 +868,8 @@ mod tests {
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
let key = SigningKey::generate(&mut OsRng);
|
||||
let envelope = TypedEnvelope::new(MeshMessageType::Alert, b"test".to_vec())
|
||||
.signed_with_seq(42, &key);
|
||||
let envelope =
|
||||
TypedEnvelope::new(MeshMessageType::Alert, b"test".to_vec()).signed_with_seq(42, &key);
|
||||
assert!(envelope.verify_signature(&key.verifying_key()).unwrap());
|
||||
|
||||
// v2 binds seq: replaying the signed envelope under a different
|
||||
@@ -880,8 +888,8 @@ mod tests {
|
||||
// preimage, no seq) and allocate seq afterwards; verify must still
|
||||
// accept that.
|
||||
let key = SigningKey::generate(&mut OsRng);
|
||||
let envelope = TypedEnvelope::new_signed(MeshMessageType::Alert, b"test".to_vec(), &key)
|
||||
.with_seq(7);
|
||||
let envelope =
|
||||
TypedEnvelope::new_signed(MeshMessageType::Alert, b"test".to_vec(), &key).with_seq(7);
|
||||
assert!(envelope.verify_signature(&key.verifying_key()).unwrap());
|
||||
}
|
||||
|
||||
|
||||
@@ -2327,7 +2327,10 @@ mod tests {
|
||||
// Force the dev fallback even if a packaged binary happens to exist
|
||||
// on this machine's PATH convention — this test wants exactly the
|
||||
// freshly-built venv daemon under test.
|
||||
std::env::set_var("ARCHY_RETICULUM_DAEMON_BIN", "/nonexistent-force-dev-fallback");
|
||||
std::env::set_var(
|
||||
"ARCHY_RETICULUM_DAEMON_BIN",
|
||||
"/nonexistent-force-dev-fallback",
|
||||
);
|
||||
|
||||
let data_dir = root.path().join("node");
|
||||
std::fs::create_dir_all(data_dir.join("identity")).unwrap();
|
||||
|
||||
@@ -270,7 +270,9 @@ impl ReticulumLink {
|
||||
our_ed_pubkey_hex: Option<&str>,
|
||||
our_x25519_pubkey_hex: Option<&str>,
|
||||
) -> Result<Self> {
|
||||
probe_rnode(path).await.context("RNode KISS detect failed")?;
|
||||
probe_rnode(path)
|
||||
.await
|
||||
.context("RNode KISS detect failed")?;
|
||||
Self::spawn(
|
||||
ReticulumInterface::Serial(path),
|
||||
data_dir,
|
||||
@@ -342,8 +344,9 @@ impl ReticulumLink {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let _ = tokio::fs::set_permissions(&runtime_dir, std::fs::Permissions::from_mode(0o700))
|
||||
.await;
|
||||
let _ =
|
||||
tokio::fs::set_permissions(&runtime_dir, std::fs::Permissions::from_mode(0o700))
|
||||
.await;
|
||||
}
|
||||
let label = iface.label();
|
||||
let iface_key = label.replace(['/', ' ', ':', ','], "_");
|
||||
@@ -553,7 +556,11 @@ impl ReticulumLink {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_text_msg(&mut self, dest_pubkey_prefix: &[u8; 6], payload: &[u8]) -> Result<()> {
|
||||
pub async fn send_text_msg(
|
||||
&mut self,
|
||||
dest_pubkey_prefix: &[u8; 6],
|
||||
payload: &[u8],
|
||||
) -> Result<()> {
|
||||
let dest_hash = self
|
||||
.prefix_to_hash
|
||||
.get(dest_pubkey_prefix)
|
||||
@@ -738,11 +745,9 @@ impl ReticulumLink {
|
||||
async fn drain_events(&mut self) {
|
||||
loop {
|
||||
let mut line = String::new();
|
||||
let read = tokio::time::timeout(
|
||||
Duration::from_millis(20),
|
||||
self.reader.read_line(&mut line),
|
||||
)
|
||||
.await;
|
||||
let read =
|
||||
tokio::time::timeout(Duration::from_millis(20), self.reader.read_line(&mut line))
|
||||
.await;
|
||||
let n = match read {
|
||||
Ok(Ok(n)) => n,
|
||||
_ => break, // timeout (no data) or read error — stop draining
|
||||
@@ -840,7 +845,8 @@ impl ReticulumLink {
|
||||
// to survive a restart — give it a placeholder name (the real
|
||||
// one, if any, arrives via a later "announce" and overwrites
|
||||
// this) so its routing entry alone doesn't get lost.
|
||||
if let std::collections::hash_map::Entry::Vacant(e) = self.peers.entry(source_hash) {
|
||||
if let std::collections::hash_map::Entry::Vacant(e) = self.peers.entry(source_hash)
|
||||
{
|
||||
e.insert(ReticulumPeer {
|
||||
dest_hash: source_hash,
|
||||
display_name: format!("Reticulum {}", hex::encode(&source_hash[..4])),
|
||||
@@ -858,13 +864,22 @@ impl ReticulumLink {
|
||||
// UI (dispatch.rs's existing ContentInline handling, zero new
|
||||
// frontend code) instead of the plain text bytes below.
|
||||
use base64::{engine::general_purpose::STANDARD as B64, Engine as _};
|
||||
let caption = ev.get("content").and_then(Value::as_str).filter(|s| !s.trim().is_empty());
|
||||
let caption = ev
|
||||
.get("content")
|
||||
.and_then(Value::as_str)
|
||||
.filter(|s| !s.trim().is_empty());
|
||||
if let (Some(fmt), Some(b64)) = (
|
||||
ev.get("image_format").and_then(Value::as_str),
|
||||
ev.get("image_b64").and_then(Value::as_str),
|
||||
) {
|
||||
if let Ok(bytes) = B64.decode(b64) {
|
||||
match build_content_inline_frame(&prefix, image_format_to_mime(fmt), None, caption, bytes) {
|
||||
match build_content_inline_frame(
|
||||
&prefix,
|
||||
image_format_to_mime(fmt),
|
||||
None,
|
||||
caption,
|
||||
bytes,
|
||||
) {
|
||||
Ok(frame) => {
|
||||
self.inbound.push_back(frame);
|
||||
return;
|
||||
@@ -905,7 +920,8 @@ impl ReticulumLink {
|
||||
},
|
||||
None => content_str.as_bytes().to_vec(),
|
||||
};
|
||||
self.inbound.push_back(build_synthetic_frame(&prefix, &content));
|
||||
self.inbound
|
||||
.push_back(build_synthetic_frame(&prefix, &content));
|
||||
}
|
||||
Some("resource_recv") => {
|
||||
let Some(source_hex) = ev.get("source_hash").and_then(Value::as_str) else {
|
||||
@@ -916,7 +932,8 @@ impl ReticulumLink {
|
||||
};
|
||||
let prefix: [u8; 6] = source_hash[..6].try_into().unwrap();
|
||||
self.prefix_to_hash.insert(prefix, source_hash);
|
||||
if let std::collections::hash_map::Entry::Vacant(e) = self.peers.entry(source_hash) {
|
||||
if let std::collections::hash_map::Entry::Vacant(e) = self.peers.entry(source_hash)
|
||||
{
|
||||
e.insert(ReticulumPeer {
|
||||
dest_hash: source_hash,
|
||||
display_name: format!("Reticulum {}", hex::encode(&source_hash[..4])),
|
||||
@@ -939,7 +956,8 @@ impl ReticulumLink {
|
||||
// Resources are already a binary-safe whole-blob transfer),
|
||||
// so this is the same payload shape `decode.rs` already
|
||||
// accepts for a single-frame (non-chunked) typed envelope.
|
||||
self.inbound.push_back(build_synthetic_frame(&prefix, &data));
|
||||
self.inbound
|
||||
.push_back(build_synthetic_frame(&prefix, &data));
|
||||
}
|
||||
Some("resource_progress") => {
|
||||
debug!(
|
||||
@@ -1138,7 +1156,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn detect_resp_found_in_kiss_stream() {
|
||||
let stream = [0x10, 0x20, KISS_FEND, KISS_CMD_DETECT, KISS_DETECT_RESP, 0x99];
|
||||
let stream = [
|
||||
0x10,
|
||||
0x20,
|
||||
KISS_FEND,
|
||||
KISS_CMD_DETECT,
|
||||
KISS_DETECT_RESP,
|
||||
0x99,
|
||||
];
|
||||
assert!(contains_detect_resp(&stream));
|
||||
}
|
||||
|
||||
@@ -1154,7 +1179,9 @@ mod tests {
|
||||
async fn probe_rnode_detects_real_hardware() {
|
||||
let port = std::env::var("ARCHY_RNODE_TEST_PORT")
|
||||
.expect("set ARCHY_RNODE_TEST_PORT to the RNode's serial path");
|
||||
probe_rnode(&port).await.expect("KISS detect probe failed against real hardware");
|
||||
probe_rnode(&port)
|
||||
.await
|
||||
.expect("KISS detect probe failed against real hardware");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1181,7 +1208,8 @@ mod tests {
|
||||
arch_pubkey_hex: Some("abcdef".to_string()),
|
||||
}];
|
||||
|
||||
let dir = std::env::temp_dir().join(format!("archy-reticulum-peers-test-{}", std::process::id()));
|
||||
let dir =
|
||||
std::env::temp_dir().join(format!("archy-reticulum-peers-test-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let path = dir.join("peers.json");
|
||||
std::fs::write(&path, serde_json::to_vec(&persisted).unwrap()).unwrap();
|
||||
@@ -1207,7 +1235,10 @@ mod tests {
|
||||
h
|
||||
};
|
||||
let id = reticulum_contact_id_from_hash(&hash_high_bit);
|
||||
assert!(id < 0x8000_0000, "must not collide with federation-synthetic space");
|
||||
assert!(
|
||||
id < 0x8000_0000,
|
||||
"must not collide with federation-synthetic space"
|
||||
);
|
||||
assert_ne!(id, 0);
|
||||
|
||||
let zero_hash = [0u8; 16];
|
||||
|
||||
Reference in New Issue
Block a user