use core::str::FromStr;
use embedded_hal::blocking::rng;
use embedded_nal::{AddrType, Dns, IpAddr, SocketAddr, UdpClientStack};
use embedded_timers::clock::Clock;
use super::{error::Error, CoapEndpoint, ConnectionLink, Uri};
impl<
'a,
UDP,
RNG,
CLOCK,
const MAX_OPTION_COUNT: usize,
const MAX_OPTION_SIZE: usize,
const INCOMING_BUFFER_SIZE: usize,
const OUTGOING_BUFFER_SIZE: usize,
const RECEIVE_BUFFER_SIZE: usize,
>
CoapEndpoint<
'a,
UDP,
RNG,
CLOCK,
MAX_OPTION_COUNT,
MAX_OPTION_SIZE,
INCOMING_BUFFER_SIZE,
OUTGOING_BUFFER_SIZE,
RECEIVE_BUFFER_SIZE,
>
where
UDP: UdpClientStack,
RNG: rng::Read,
CLOCK: Clock,
{
pub fn connect_with_socket(
&mut self,
socket: UDP::UdpSocket,
addr: SocketAddr,
) -> Result<(), Error<<UDP as UdpClientStack>::Error>> {
if self.connection_link.is_none() {
self.connection_link = Some(ConnectionLink { socket, addr });
Ok(())
} else {
Err(Error::AlreadyConnected)
}
}
pub fn connect_to_addr<'client>(
&mut self,
client: &'client mut UDP,
addr: SocketAddr,
) -> Result<&'client mut UDP, Error<<UDP as UdpClientStack>::Error>> {
if self.connection_link.is_some() {
Err(Error::AlreadyConnected)
} else {
let mut socket = client.socket().map_err(Error::Network)?;
client.connect(&mut socket, addr).map_err(Error::Network)?;
self.connection_link = Some(ConnectionLink { socket, addr });
Ok(client)
}
}
pub fn close<'client>(
&mut self,
client: &'client mut UDP,
) -> Result<&'client mut UDP, Error<<UDP as UdpClientStack>::Error>> {
if self.connection_link.is_none() {
Err(Error::NotConnected)
} else {
client
.close(self.connection_link.take().unwrap().socket)
.map_err(Error::Network)?;
self.connection_link = None;
Ok(client)
}
}
}
impl<
'a,
UDP,
RNG,
CLOCK,
const MAX_OPTION_COUNT: usize,
const MAX_OPTION_SIZE: usize,
const INCOMING_BUFFER_SIZE: usize,
const OUTGOING_BUFFER_SIZE: usize,
const RECEIVE_BUFFER_SIZE: usize,
>
CoapEndpoint<
'a,
UDP,
RNG,
CLOCK,
MAX_OPTION_COUNT,
MAX_OPTION_SIZE,
INCOMING_BUFFER_SIZE,
OUTGOING_BUFFER_SIZE,
RECEIVE_BUFFER_SIZE,
>
where
UDP: UdpClientStack + Dns,
RNG: rng::Read,
CLOCK: Clock,
{
pub fn connect_to_url(
&mut self,
client: &mut UDP,
url: &str,
) -> Result<(), Error<<UDP as UdpClientStack>::Error>> {
if self.connection_link.is_some() {
return Err(Error::AlreadyConnected);
}
let uri = Uri::new(url).map_err(|_| Error::Uri)?;
let components = uri.authority_components().ok_or(Error::Uri)?;
let host = components.host();
let port = if let Some(port_str) = components.port() {
port_str.parse::<u16>().map_err(|_| Error::Uri)?
} else {
super::DEFAULT_COAP_PORT
};
let ip = if let Ok(ip) = IpAddr::from_str(host) {
ip
} else {
nb::block!(client.get_host_by_name(host, AddrType::Either)).unwrap()
};
let socket_addr = SocketAddr::new(ip, port);
self.connect_to_addr(client, socket_addr)?;
Ok(())
}
}