use crate::{warn, MQTT_INSECURE_DEFAULT_PORT};
use core::convert::TryFrom;
use embedded_nal::{nb, AddrType, Dns, IpAddr, Ipv4Addr, SocketAddr};
pub trait Broker {
fn get_address(&mut self) -> Option<SocketAddr>;
fn set_port(&mut self, port: u16);
}
#[derive(Debug)]
pub struct NamedBroker<R: Dns, const T: usize = 253> {
raw: heapless::String<T>,
resolver: R,
addr: SocketAddr,
}
impl<R: Dns, const T: usize> NamedBroker<R, T> {
pub fn new(broker: &str, resolver: R) -> Result<Self, &str> {
let addr: Ipv4Addr = broker.parse().unwrap_or(Ipv4Addr::UNSPECIFIED);
Ok(Self {
raw: heapless::String::try_from(broker).map_err(|_| "Broker domain name too long")?,
resolver,
addr: SocketAddr::new(IpAddr::V4(addr), MQTT_INSECURE_DEFAULT_PORT),
})
}
}
impl<R: Dns, const T: usize> Broker for NamedBroker<R, T> {
fn get_address(&mut self) -> Option<SocketAddr> {
if self.addr.ip().is_unspecified() {
match self.resolver.get_host_by_name(&self.raw, AddrType::IPv4) {
Ok(ip) => self.addr.set_ip(ip),
Err(nb::Error::WouldBlock) => {}
Err(_other) => {
warn!("DNS lookup failed: {_other:?}")
}
}
}
if !self.addr.ip().is_unspecified() {
Some(self.addr)
} else {
None
}
}
fn set_port(&mut self, port: u16) {
self.addr.set_port(port)
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct IpBroker {
addr: SocketAddr,
}
impl IpBroker {
pub fn new(broker: IpAddr) -> Self {
Self {
addr: SocketAddr::new(broker, MQTT_INSECURE_DEFAULT_PORT),
}
}
}
impl Broker for IpBroker {
fn get_address(&mut self) -> Option<SocketAddr> {
Some(self.addr)
}
fn set_port(&mut self, port: u16) {
self.addr.set_port(port)
}
}
impl From<IpAddr> for IpBroker {
fn from(addr: IpAddr) -> Self {
IpBroker::new(addr)
}
}