use anyhow::Result; use tracing::info; use crate::Router; /// The OpenWrt package name for the TollGate reference implementation. const TOLLGATE_PACKAGE: &str = "tollgate-module-basic-go"; /// Direct-download fallback URLs by opkg architecture string. /// Used when the package is not in any configured feed. /// Source: https://github.com/OpenTollGate/tollgate-module-basic-go/releases/tag/v0.2.0 fn ipk_url(arch: &str) -> Option<&'static str> { match arch { "mips_24kc" => Some("https://github.com/OpenTollGate/tollgate-module-basic-go/releases/download/v0.2.0/mips_24kc.ipk"), "mipsel_24kc" => Some("https://github.com/OpenTollGate/tollgate-module-basic-go/releases/download/v0.2.0/mipsel_24kc.ipk"), "aarch64_cortex-a53" => Some("https://github.com/OpenTollGate/tollgate-module-basic-go/releases/download/v0.2.0/aarch64_cortex-a53.ipk"), "aarch64_cortex-a72" => Some("https://github.com/OpenTollGate/tollgate-module-basic-go/releases/download/v0.2.0/aarch64_cortex-a72.ipk"), "arm_cortex-a7" => Some("https://github.com/OpenTollGate/tollgate-module-basic-go/releases/download/v0.2.0/arm_cortex-a7.ipk"), _ => None, } } /// Install tollgate-module-basic-go. /// /// Tries opkg first (works if a custom feed is configured). Falls back to /// downloading the .ipk directly from GitHub releases if opkg can't find it. /// Caller is responsible for running `opkg_update` first. pub fn install_tollgate(router: &Router) -> Result<()> { info!("[{}] Installing {}", router.host, TOLLGATE_PACKAGE); // Fast path: standard opkg install (or already installed). if router.opkg_install(TOLLGATE_PACKAGE).is_ok() { return Ok(()); } // Package not in any feed — download the .ipk directly. let arch = router .run_ok("opkg print-architecture | grep -v 'all\\|noarch' | tail -1 | awk '{print $2}'")?; let arch = arch.trim(); let url = ipk_url(arch).ok_or_else(|| { anyhow::anyhow!( "No pre-built TollGate package for architecture '{}'. \ Add a custom opkg feed or build from source.", arch ) })?; info!("[{}] Downloading TollGate for {} from GitHub releases", router.host, arch); router.run_ok(&format!("wget -O /tmp/tollgate.ipk '{}'", url))?; // Capture stderr too — BusyBox opkg exits 0 even on "Cannot install" failures. let (out, _code) = router.run("opkg install --force-depends /tmp/tollgate.ipk 2>&1")?; router.run_ok("rm -f /tmp/tollgate.ipk")?; if out.contains("Cannot install") || out.contains("errors encountered") { if out.contains("Only have") && out.contains("available on filesystem") { // Extract the sizes from the error for a user-readable message. // Example: "Only have 8884kb available on filesystem /overlay, pkg tollgate-wrt needs 18750" anyhow::bail!( "No space left on router for TollGate ({}). \ This router has insufficient flash storage. \ Consider a router with ≥32 MB flash or add an extroot USB drive.", out.lines() .find(|l| l.contains("Only have")) .unwrap_or("check router disk space") .trim() ); } anyhow::bail!("TollGate installation failed: {}", out.trim()); } Ok(()) }