use std::{
collections::HashMap,
net::{IpAddr, SocketAddr},
};
use crate::conversion_utils::{hashmap_to_txt, ip_addr_to_resource_record, port_to_srv_record};
use simple_dns::{Name, ResourceRecord};
#[derive(Debug)]
pub struct InstanceInformation {
pub ip_addresses: Vec<IpAddr>,
pub ports: Vec<u16>,
pub attributes: HashMap<String, Option<String>>,
}
impl Default for InstanceInformation {
fn default() -> Self {
Self::new()
}
}
impl InstanceInformation {
pub fn new() -> Self {
Self {
ip_addresses: Vec::new(),
ports: Vec::new(),
attributes: HashMap::new(),
}
}
pub(crate) fn from_records<'a>(records: impl Iterator<Item = &'a ResourceRecord<'a>>) -> Self {
let mut ip_addresses: Vec<IpAddr> = Vec::new();
let mut ports = Vec::new();
let mut attributes = HashMap::new();
for resource in records {
match &resource.rdata {
simple_dns::rdata::RData::A(a) => {
ip_addresses.push(std::net::Ipv4Addr::from(a.address).into())
}
simple_dns::rdata::RData::AAAA(aaaa) => {
ip_addresses.push(std::net::Ipv6Addr::from(aaaa.address).into())
}
simple_dns::rdata::RData::TXT(txt) => attributes.extend(txt.attributes()),
simple_dns::rdata::RData::SRV(srv) => ports.push(srv.port),
_ => {}
}
}
InstanceInformation {
ip_addresses,
ports,
attributes,
}
}
pub fn into_records<'a>(
self,
service_name: &Name<'a>,
ttl: u32,
) -> Result<Vec<ResourceRecord<'a>>, crate::SimpleMdnsError> {
let mut records = Vec::new();
for ip_address in self.ip_addresses {
records.push(ip_addr_to_resource_record(service_name, ip_address, ttl));
}
for port in self.ports {
records.push(port_to_srv_record(service_name, port, ttl));
}
records.push(hashmap_to_txt(service_name, self.attributes, ttl)?);
Ok(records)
}
pub fn get_socket_addresses(&'_ self) -> impl Iterator<Item = SocketAddr> + '_ {
self.ip_addresses.iter().copied().flat_map(move |addr| {
self.ports
.iter()
.copied()
.map(move |port| SocketAddr::new(addr, port))
})
}
}
impl std::hash::Hash for InstanceInformation {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.ip_addresses.hash(state);
self.ports.hash(state);
}
}
impl From<SocketAddr> for InstanceInformation {
fn from(addr: SocketAddr) -> Self {
let ip_address = addr.ip();
let port = addr.port();
Self {
ip_addresses: vec![ip_address],
ports: vec![port],
attributes: HashMap::new(),
}
}
}