1use crate::{records::SrvDomain, resolvables::*, Context, DnsClient, Target};
2use async_trait::async_trait;
3use rsip::{Domain, Host, Port, Transport};
4use std::net::IpAddr;
5
6#[derive(Debug, Clone)]
7pub enum Lookup<C>
8where
9 C: DnsClient,
10{
11 IpAddr(ResolvableIpAddr),
12 DomainWithPort(ResolvableAddrRecord<C>),
13 DomainWithTransport(ResolvableVec<ResolvableEnum<C>, Target>),
17 JustDomain(ResolvableVec<ResolvableEnum<C>, Target>),
18}
19
20#[async_trait]
21impl<C> ResolvableExt<Target> for Lookup<C>
22where
23 C: DnsClient,
24{
25 fn state(&self) -> ResolvableState {
26 match self {
27 Self::IpAddr(inner) => inner.state(),
28 Self::DomainWithPort(inner) => inner.state(),
29 Self::DomainWithTransport(inner) => inner.state(),
30 Self::JustDomain(inner) => inner.state(),
31 }
32 }
33
34 async fn resolve_next(&mut self) -> Option<Target> {
35 match self {
36 Self::IpAddr(inner) => inner.resolve_next().await,
37 Self::DomainWithPort(inner) => inner.resolve_next().await,
38 Self::DomainWithTransport(inner) => inner.resolve_next().await,
39 Self::JustDomain(inner) => inner.resolve_next().await,
40 }
41 }
42}
43
44impl<C> From<Context<C>> for Lookup<C>
45where
46 C: DnsClient,
47{
48 fn from(ctx: Context<C>) -> Self {
49 match ctx.host {
50 Host::IpAddr(ip_addr) => ip_addr_lookup(ip_addr, ctx),
51 Host::Domain(ref domain) => match (ctx.port, ctx.transport) {
52 (Some(port), _) => domain_with_port_lookup(domain.clone(), port, ctx),
53 (None, Some(transport)) => {
54 domain_with_transport_lookup(domain.clone(), transport, ctx)
55 }
56 (None, None) => just_domain_lookup(domain.clone(), ctx),
57 },
58 }
59 }
60}
61
62fn ip_addr_lookup<C: DnsClient>(ip_addr: IpAddr, ctx: Context<C>) -> Lookup<C> {
63 Lookup::IpAddr(ResolvableIpAddr::new(
64 ip_addr,
65 ctx.default_transport().default_port(),
66 ctx.default_transport(),
67 ))
68}
69
70fn domain_with_port_lookup<C: DnsClient>(domain: Domain, port: Port, ctx: Context<C>) -> Lookup<C> {
71 Lookup::DomainWithPort(ResolvableAddrRecord::new(
72 ctx.dns_client.clone(),
73 domain,
74 port,
75 ctx.default_transport(),
76 ))
77}
78
79fn domain_with_transport_lookup<C: DnsClient>(
80 domain: Domain,
81 transport: Transport,
82 ctx: Context<C>,
83) -> Lookup<C> {
84 let mut lookups: Vec<ResolvableEnum<C>> = vec![];
85
86 let srv_domain = SrvDomain { secure: ctx.secure, protocol: transport.protocol(), domain };
87 lookups.push(ResolvableSrvRecord::new(ctx.dns_client.clone(), srv_domain.clone()).into());
88 lookups.push(
89 ResolvableAddrRecord::new(
90 ctx.dns_client,
91 srv_domain.domain.clone(),
92 srv_domain.transport().default_port(),
93 srv_domain.transport(),
94 )
95 .into(),
96 );
97
98 Lookup::DomainWithTransport(ResolvableVec::non_empty(lookups))
99}
100
101fn just_domain_lookup<C: DnsClient>(domain: Domain, ctx: Context<C>) -> Lookup<C> {
102 let mut lookups: Vec<ResolvableEnum<C>> = vec![ResolvableNaptrRecord::new(
103 ctx.dns_client.clone(),
104 domain.clone(),
105 ctx.available_transports(),
106 )
107 .into()];
108
109 ctx.available_protocols().into_iter().for_each(|transport| {
110 let srv_domain = SrvDomain {
111 secure: ctx.secure,
112 protocol: transport.protocol(),
113 domain: domain.clone(),
114 };
115
116 lookups.push(ResolvableSrvRecord::new(ctx.dns_client.clone(), srv_domain).into());
117 });
118
119 let default_transport = match ctx.secure {
120 true => Transport::default_secure_transport(),
121 false => Transport::default_insecure_transport(),
122 };
123 lookups.push(
124 ResolvableAddrRecord::new(
125 ctx.dns_client,
126 domain,
127 default_transport.default_port(),
128 default_transport,
129 )
130 .into(),
131 );
132
133 Lookup::JustDomain(ResolvableVec::non_empty(lookups))
134}
135
136