use super::RpcHandler; use anyhow::Result; use archipelago_openwrt::{ detect, router::Router, tollgate::{self, TollGateConfig}, }; /// Default port for the local Cashu mint (nutshell / cashu-mint app). const LOCAL_MINT_PORT: u16 = 3338; impl RpcHandler { /// Scan the local subnet for OpenWrt routers. /// /// Params: `{ "subnet": "192.168.1.0", "prefix": 24, /// "ssh_user": "root", "ssh_password": "" }` pub(super) async fn handle_openwrt_scan( &self, params: Option, ) -> Result { let p = params.unwrap_or_default(); let subnet: [u8; 4] = parse_ipv4( p.get("subnet").and_then(|v| v.as_str()).unwrap_or("192.168.1.0"), )?; let prefix = p.get("prefix").and_then(|v| v.as_u64()).unwrap_or(24) as u8; let ssh_user = p .get("ssh_user") .and_then(|v| v.as_str()) .unwrap_or("root") .to_string(); let ssh_password = p .get("ssh_password") .and_then(|v| v.as_str()) .unwrap_or("") .to_string(); let routers = detect::scan_subnet(subnet, prefix, &ssh_user, &ssh_password).await; let ips: Vec = routers.iter().map(|ip| ip.to_string()).collect(); Ok(serde_json::json!({ "routers": ips })) } /// Provision TollGate on an OpenWrt router and create the "archipelago" SSID. /// /// Params: `{ "host": "192.168.1.1", "ssh_user": "root", "ssh_password": "", /// "price_sats": 10, "step_size_ms": 60000, "min_steps": 1, /// "mint_url": "" }` /// /// `mint_url` defaults to `http://:3338` — the local Cashu /// mint that must be running as an Archy app before calling this endpoint. pub(super) async fn handle_openwrt_provision_tollgate( &self, params: Option, ) -> Result { let p = params.ok_or_else(|| anyhow::anyhow!("Missing params"))?; let host = p .get("host") .and_then(|v| v.as_str()) .ok_or_else(|| anyhow::anyhow!("Missing host"))? .to_string(); let ssh_user = p .get("ssh_user") .and_then(|v| v.as_str()) .unwrap_or("root") .to_string(); let ssh_password = p .get("ssh_password") .and_then(|v| v.as_str()) .unwrap_or("") .to_string(); let default_mint_url = format!("http://{}:{}", self.config.host_ip, LOCAL_MINT_PORT); let mint_url = p .get("mint_url") .and_then(|v| v.as_str()) .unwrap_or(&default_mint_url) .to_string(); let config = TollGateConfig { ssid: "archipelago".to_string(), mint_url, price_sats: p.get("price_sats").and_then(|v| v.as_u64()).unwrap_or(10), step_size_ms: p .get("step_size_ms") .and_then(|v| v.as_u64()) .unwrap_or(60_000), min_steps: p .get("min_steps") .and_then(|v| v.as_u64()) .unwrap_or(1) as u32, }; let router = Router::connect_password(&host, 22, &ssh_user, &ssh_password)?; router.verify_openwrt()?; tollgate::provision(&router, &config).await?; Ok(serde_json::json!({ "ok": true, "host": host, "ssid": config.ssid, "mint_url": config.mint_url, })) } } fn parse_ipv4(s: &str) -> Result<[u8; 4]> { let parts: Vec<&str> = s.split('.').collect(); if parts.len() != 4 { anyhow::bail!("Invalid IPv4: {}", s); } Ok([ parts[0].parse()?, parts[1].parse()?, parts[2].parse()?, parts[3].parse()?, ]) }