From 7a89ee272fa932394d83bd4cebafce076bb8aed0 Mon Sep 17 00:00:00 2001 From: LowderPlay Date: Sat, 29 Aug 2026 04:23:19 +0500 Subject: [PATCH] feat: track bundle (#90) * feat: track bundle * fix: remove apk arch --- Cargo.lock | 4 +-- probe/Cargo.toml | 2 +- probe/install.sh | 7 ++++- probe/src/main.rs | 6 ++++ probe/src/update.rs | 55 +++++++++++++++++++++++++++++++---- reports/src/probe.rs | 2 ++ website/Cargo.toml | 2 +- website/src/api/node_stats.rs | 5 ++++ website/src/mqtt.rs | 6 +++- 9 files changed, 77 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9923cf5..8848036 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2577,7 +2577,7 @@ dependencies = [ [[package]] name = "probe" -version = "0.6.0" +version = "0.6.1" dependencies = [ "anyhow", "clap", @@ -4652,7 +4652,7 @@ dependencies = [ [[package]] name = "website" -version = "1.3.0" +version = "1.3.1" dependencies = [ "dotenvy", "env_logger", diff --git a/probe/Cargo.toml b/probe/Cargo.toml index 99402c6..210baab 100644 --- a/probe/Cargo.toml +++ b/probe/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "probe" -version = "0.6.0" +version = "0.6.1" edition = "2024" license-file = "../LICENSE" description = "Dynamic network probe daemon for Cheburcheck" diff --git a/probe/install.sh b/probe/install.sh index 3da9473..5a35dff 100644 --- a/probe/install.sh +++ b/probe/install.sh @@ -76,7 +76,12 @@ detect_platform() { if command_exists apk; then PLATFORM=openwrt-apk PLATFORM_NAME='OpenWrt (apk)' - ARCH=$(apk --print-arch) + if [ -s /etc/apk/arch ]; then + ARCH=$(head -n 1 /etc/apk/arch) + else + ARCH=$(sed -n 's/^DISTRIB_ARCH=//p' /etc/openwrt_release | tr -d "'\"" | head -n 1) + fi + [ -n "$ARCH" ] || fail "OpenWrt did not report its package architecture" validate_openwrt_arch "$ARCH" elif command_exists opkg; then PLATFORM=openwrt-opkg diff --git a/probe/src/main.rs b/probe/src/main.rs index 2e85266..930b0e3 100644 --- a/probe/src/main.rs +++ b/probe/src/main.rs @@ -78,6 +78,7 @@ struct Args { probe_token: String, max_concurrent_tasks: usize, traceroute_retries: u8, + bundle_type: &'static str, } impl Cli { @@ -94,6 +95,7 @@ impl Cli { .context("--probe-token or PROBE_TOKEN is required when running the probe")?, max_concurrent_tasks: self.max_concurrent_tasks, traceroute_retries: self.traceroute_retries, + bundle_type: update::bundle_type().context("failed to detect probe bundle type")?, }) } } @@ -127,6 +129,7 @@ async fn main() -> Result<()> { online: false, probe_id: &args.probe_id, version: env!("CARGO_PKG_VERSION"), + bundle_type: Some(args.bundle_type), dpi_hop_v4: None, dpi_hop_v6: None, })?; @@ -456,6 +459,7 @@ async fn publish_status( online, probe_id: &args.probe_id, version: env!("CARGO_PKG_VERSION"), + bundle_type: Some(args.bundle_type), dpi_hop_v4: dpi_hops.v4, dpi_hop_v6: dpi_hops.v6, })?; @@ -625,6 +629,7 @@ mod tests { online: true, probe_id: "probe-1", version: "1.0.0", + bundle_type: Some("debian"), dpi_hop_v4: Some(4), dpi_hop_v6: Some(6), }; @@ -632,6 +637,7 @@ mod tests { assert_eq!(value["dpi_hop_v4"], 4); assert_eq!(value["dpi_hop_v6"], 6); + assert_eq!(value["bundle_type"], "debian"); } #[test] diff --git a/probe/src/update.rs b/probe/src/update.rs index cb640fd..c598971 100644 --- a/probe/src/update.rs +++ b/probe/src/update.rs @@ -33,6 +33,22 @@ enum PackageKind { Windows, } +impl PackageKind { + const fn bundle_type(self) -> &'static str { + match self { + Self::Debian => "debian", + Self::Apk => "openwrt-apk", + Self::Opkg => "openwrt-opkg", + Self::Linux => "linux", + Self::Windows => "windows", + } + } +} + +pub fn bundle_type() -> Result<&'static str> { + detect_platform().map(|(kind, _, _)| kind.bundle_type()) +} + #[cfg(unix)] struct UpdateLock { _file: File, @@ -191,14 +207,10 @@ fn detect_platform() -> Result<(PackageKind, String, bool)> { } else if command_exists("apk") && command_succeeds("apk", &["info", "--exists", "cheburprobe"])? { - let architecture = output_text("apk", &["--print-arch"])?; + let architecture = openwrt_apk_arch()?; let luci_installed = command_succeeds("apk", &["info", "--exists", "luci-app-cheburprobe"])?; - Ok(( - PackageKind::Apk, - architecture.trim().to_owned(), - luci_installed, - )) + Ok((PackageKind::Apk, architecture, luci_installed)) } else if command_exists("opkg") && output_text("opkg", &["list-installed", "cheburprobe"])? .lines() @@ -227,6 +239,28 @@ fn detect_platform() -> Result<(PackageKind, String, bool)> { bail!("updates are not supported on this operating system") } +#[cfg(target_os = "linux")] +fn openwrt_apk_arch() -> Result { + if let Ok(architecture) = std::fs::read_to_string("/etc/apk/arch") { + let architecture = architecture.trim(); + if !architecture.is_empty() { + return Ok(architecture.to_owned()); + } + } + let release = std::fs::read_to_string("/etc/openwrt_release") + .context("failed to read /etc/openwrt_release")?; + parse_openwrt_release_arch(&release).context("OpenWrt did not report DISTRIB_ARCH") +} + +#[cfg(target_os = "linux")] +fn parse_openwrt_release_arch(release: &str) -> Option { + release.lines().find_map(|line| { + line.strip_prefix("DISTRIB_ARCH=") + .map(|value| value.trim_matches(['\'', '"']).to_owned()) + .filter(|value| !value.is_empty()) + }) +} + fn select_luci_asset<'a>( assets: &'a [Asset], kind: PackageKind, @@ -463,6 +497,15 @@ mod tests { ); } + #[cfg(target_os = "linux")] + #[test] + fn parses_full_openwrt_architecture() { + assert_eq!( + parse_openwrt_release_arch("DISTRIB_ID='OpenWrt'\nDISTRIB_ARCH='aarch64_cortex-a53'\n"), + Some("aarch64_cortex-a53".to_owned()) + ); + } + #[test] fn selects_each_package_format() { let assets = vec![ diff --git a/reports/src/probe.rs b/reports/src/probe.rs index 103cd18..982801a 100644 --- a/reports/src/probe.rs +++ b/reports/src/probe.rs @@ -7,6 +7,8 @@ pub struct ProbeStatus<'a> { pub probe_id: &'a str, pub version: &'a str, #[serde(default)] + pub bundle_type: Option<&'a str>, + #[serde(default)] pub dpi_hop_v4: Option, #[serde(default)] pub dpi_hop_v6: Option, diff --git a/website/Cargo.toml b/website/Cargo.toml index be13542..e2eec82 100644 --- a/website/Cargo.toml +++ b/website/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "website" -version = "1.3.0" +version = "1.3.1" edition = "2024" [dependencies] diff --git a/website/src/api/node_stats.rs b/website/src/api/node_stats.rs index a538370..4b65780 100644 --- a/website/src/api/node_stats.rs +++ b/website/src/api/node_stats.rs @@ -56,6 +56,7 @@ struct NodeStatus { connected_at: Option>, online: bool, version: Option, + bundle_type: Option, dpi_hop_v4: Option, dpi_hop_v6: Option, } @@ -107,6 +108,7 @@ fn build_node_statuses( connected_at: probe.last_connected_at, online: status.is_some_and(|status| status.online), version: status.map(|status| status.version.clone()), + bundle_type: status.and_then(|status| status.bundle_type.clone()), dpi_hop_v4: status.and_then(|status| status.dpi_hop_v4), dpi_hop_v6: status.and_then(|status| status.dpi_hop_v6), } @@ -152,6 +154,7 @@ mod tests { ProbeStatusSnapshot { online: true, version: "1.2.3".to_string(), + bundle_type: Some("debian".to_string()), dpi_hop_v4: Some(5), dpi_hop_v6: None, }, @@ -171,6 +174,7 @@ mod tests { connected_at: Some("2026-08-24T12:34:56Z".parse().unwrap()), online: true, version: Some("1.2.3".to_string()), + bundle_type: Some("debian".to_string()), dpi_hop_v4: Some(5), dpi_hop_v6: None, }, @@ -183,6 +187,7 @@ mod tests { connected_at: Some("2026-08-23T12:34:56Z".parse().unwrap()), online: false, version: None, + bundle_type: None, dpi_hop_v4: None, dpi_hop_v6: None, }, diff --git a/website/src/mqtt.rs b/website/src/mqtt.rs index e381166..b18e130 100644 --- a/website/src/mqtt.rs +++ b/website/src/mqtt.rs @@ -66,6 +66,7 @@ type ProbeStatuses = Arc, pub dpi_hop_v4: Option, pub dpi_hop_v6: Option, } @@ -377,6 +378,7 @@ async fn dispatch_probe_status(probe_statuses: &ProbeStatuses, topic: &str, payl ProbeStatusSnapshot { online: status.online, version: status.version.to_string(), + bundle_type: status.bundle_type.map(str::to_string), dpi_hop_v4: status.dpi_hop_v4, dpi_hop_v6: status.dpi_hop_v6, }, @@ -462,7 +464,7 @@ mod tests { dispatch_probe_status( &statuses, "probe/status/v1/42", - br#"{"online":false,"probe_id":"42","version":"1.2.3","dpi_hop_v4":4,"dpi_hop_v6":6}"#, + br#"{"online":false,"probe_id":"42","version":"1.2.3","bundle_type":"openwrt","dpi_hop_v4":4,"dpi_hop_v6":6}"#, ) .await; @@ -471,6 +473,7 @@ mod tests { Some(&ProbeStatusSnapshot { online: false, version: "1.2.3".to_string(), + bundle_type: Some("openwrt".to_string()), dpi_hop_v4: Some(4), dpi_hop_v6: Some(6), }) @@ -484,6 +487,7 @@ mod tests { ProbeStatusSnapshot { online: true, version: "1.2.3".to_string(), + bundle_type: None, dpi_hop_v4: None, dpi_hop_v6: None, },