// src/mqtt/config.rs #![allow(dead_code)] use embassy_net::{IpAddress, Ipv4Address, Ipv6Address}; // Compile-time values injected by build.rs const BROKER_IP: &str = env!("BROKER_IP"); const BROKER_PORT: &str = env!("BROKER_PORT"); pub fn mqtt_broker_endpoint() -> (IpAddress, u16) { (parse_ip(BROKER_IP), parse_port(BROKER_PORT)) } fn parse_port(s: &str) -> u16 { let p: u16 = s .parse() .unwrap_or_else(|_| panic!("BROKER_PORT must be a valid u16 (1..=65535)")); assert!(p != 0, "BROKER_PORT cannot be 0"); p } fn parse_ip(s: &str) -> IpAddress { if s.contains(':') { IpAddress::Ipv6(parse_ipv6(s)) } else { IpAddress::Ipv4(parse_ipv4(s)) } } fn parse_ipv4(s: &str) -> Ipv4Address { let mut it = s.split('.'); let a = parse_octet(it.next(), 1); let b = parse_octet(it.next(), 2); let c = parse_octet(it.next(), 3); let d = parse_octet(it.next(), 4); assert!(it.next().is_none(), "Too many IPv4 octets"); Ipv4Address::new(a, b, c, d) } fn parse_octet(part: Option<&str>, idx: usize) -> u8 { let p = part.unwrap_or_else(|| panic!("IPv4 missing octet {}", idx)); let v: u16 = p .parse() .unwrap_or_else(|_| panic!("Invalid IPv4 octet {}: {}", idx, p)); assert!(v <= 255, "IPv4 octet {} out of range: {}", idx, v); v as u8 } // Minimal IPv6 parser with '::' compression. Does not handle IPv4-embedded IPv6. fn parse_ipv6(s: &str) -> Ipv6Address { assert!( !s.contains('.'), "IPv4-embedded IPv6 like ::ffff:192.0.2.1 not supported; \ use pure hex IPv6" ); let has_double = s.contains("::"); let (left_s, right_s) = if has_double { let mut sp = s.splitn(2, "::"); (sp.next().unwrap_or(""), sp.next().unwrap_or("")) } else { (s, "") }; let mut left = [0u16; 8]; let mut right = [0u16; 8]; let mut ll = 0usize; let mut rl = 0usize; if !left_s.is_empty() { for part in left_s.split(':') { left[ll] = parse_group(part); ll += 1; assert!(ll <= 8, "Too many IPv6 groups on the left"); } } if !right_s.is_empty() { for part in right_s.split(':') { right[rl] = parse_group(part); rl += 1; assert!(rl <= 8, "Too many IPv6 groups on the right"); } } let zeros = if has_double { assert!(ll + rl < 8, "Invalid IPv6 '::' usage"); 8 - (ll + rl) } else { assert!(ll == 8, "IPv6 must have 8 groups without '::'"); 0 }; let mut g = [0u16; 8]; let mut idx = 0usize; for i in 0..ll { g[idx] = left[i]; idx += 1; } for _ in 0..zeros { g[idx] = 0; idx += 1; } for i in 0..rl { g[idx] = right[i]; idx += 1; } assert!(idx == 8, "IPv6 did not resolve to 8 groups"); Ipv6Address::new(g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7]) } fn parse_group(part: &str) -> u16 { assert!( !part.is_empty(), "Empty IPv6 group (use '::' instead for compression)" ); assert!(part.len() <= 4, "IPv6 group too long: {}", part); u16::from_str_radix(part, 16) .unwrap_or_else(|_| panic!("Invalid IPv6 hex group: {}", part)) }