use crate::{records::SrvDomain, resolvables::*, Context, DnsClient, Target};
use async_trait::async_trait;
use rsip::{Domain, Host, Port, Transport};
use std::net::IpAddr;
#[derive(Debug, Clone)]
pub enum Lookup<C>
where
C: DnsClient,
{
IpAddr(ResolvableIpAddr),
DomainWithPort(ResolvableAddrRecord<C>),
DomainWithTransport(ResolvableVec<ResolvableEnum<C>, Target>),
JustDomain(ResolvableVec<ResolvableEnum<C>, Target>),
}
#[async_trait]
impl<C> ResolvableExt<Target> for Lookup<C>
where
C: DnsClient,
{
fn state(&self) -> ResolvableState {
match self {
Self::IpAddr(inner) => inner.state(),
Self::DomainWithPort(inner) => inner.state(),
Self::DomainWithTransport(inner) => inner.state(),
Self::JustDomain(inner) => inner.state(),
}
}
async fn resolve_next(&mut self) -> Option<Target> {
match self {
Self::IpAddr(inner) => inner.resolve_next().await,
Self::DomainWithPort(inner) => inner.resolve_next().await,
Self::DomainWithTransport(inner) => inner.resolve_next().await,
Self::JustDomain(inner) => inner.resolve_next().await,
}
}
}
impl<C> From<Context<C>> for Lookup<C>
where
C: DnsClient,
{
fn from(ctx: Context<C>) -> Self {
match ctx.host {
Host::IpAddr(ip_addr) => ip_addr_lookup(ip_addr, ctx),
Host::Domain(ref domain) => match (ctx.port, ctx.transport) {
(Some(port), _) => domain_with_port_lookup(domain.clone(), port, ctx),
(None, Some(transport)) => {
domain_with_transport_lookup(domain.clone(), transport, ctx)
}
(None, None) => just_domain_lookup(domain.clone(), ctx),
},
}
}
}
fn ip_addr_lookup<C: DnsClient>(ip_addr: IpAddr, ctx: Context<C>) -> Lookup<C> {
Lookup::IpAddr(ResolvableIpAddr::new(
ip_addr,
ctx.default_transport().default_port(),
ctx.default_transport(),
))
}
fn domain_with_port_lookup<C: DnsClient>(domain: Domain, port: Port, ctx: Context<C>) -> Lookup<C> {
Lookup::DomainWithPort(ResolvableAddrRecord::new(
ctx.dns_client.clone(),
domain,
port,
ctx.default_transport(),
))
}
fn domain_with_transport_lookup<C: DnsClient>(
domain: Domain,
transport: Transport,
ctx: Context<C>,
) -> Lookup<C> {
let mut lookups: Vec<ResolvableEnum<C>> = vec![];
let srv_domain = SrvDomain { secure: ctx.secure, protocol: transport.protocol(), domain };
lookups.push(ResolvableSrvRecord::new(ctx.dns_client.clone(), srv_domain.clone()).into());
lookups.push(
ResolvableAddrRecord::new(
ctx.dns_client,
srv_domain.domain.clone(),
srv_domain.transport().default_port(),
srv_domain.transport(),
)
.into(),
);
Lookup::DomainWithTransport(ResolvableVec::non_empty(lookups))
}
fn just_domain_lookup<C: DnsClient>(domain: Domain, ctx: Context<C>) -> Lookup<C> {
let mut lookups: Vec<ResolvableEnum<C>> = vec![ResolvableNaptrRecord::new(
ctx.dns_client.clone(),
domain.clone(),
ctx.available_transports(),
)
.into()];
ctx.available_protocols().into_iter().for_each(|transport| {
let srv_domain = SrvDomain {
secure: ctx.secure,
protocol: transport.protocol(),
domain: domain.clone(),
};
lookups.push(ResolvableSrvRecord::new(ctx.dns_client.clone(), srv_domain).into());
});
let default_transport = match ctx.secure {
true => Transport::default_secure_transport(),
false => Transport::default_insecure_transport(),
};
lookups.push(
ResolvableAddrRecord::new(
ctx.dns_client,
domain,
default_transport.default_port(),
default_transport,
)
.into(),
);
Lookup::JustDomain(ResolvableVec::non_empty(lookups))
}