ntex_net/connect/
service.rs1use std::{collections::VecDeque, io, marker, net::SocketAddr};
2
3use ntex_error::Error;
4use ntex_io::{Io, IoConfig, types};
5use ntex_service::{Ctx, Service, cfg::SharedCfg};
6use ntex_util::{future::Either, time::timeout_checked};
7
8use super::{Address, Connect, ConnectError, resolve};
9
10#[derive(Debug)]
11pub struct Connector<A> {
13 _t: marker::PhantomData<A>,
14}
15
16impl<A> Connector<A> {
17 #[inline]
18 pub fn new() -> Self {
20 Connector {
21 _t: marker::PhantomData,
22 }
23 }
24}
25
26impl<A> Default for Connector<A> {
27 fn default() -> Self {
28 Connector::new()
29 }
30}
31
32impl<A> Clone for Connector<A> {
33 fn clone(&self) -> Self {
34 Connector {
35 _t: marker::PhantomData,
36 }
37 }
38}
39
40impl<A: Address> Connector<A> {
41 pub async fn connect<U>(&self, message: U, cfg: &SharedCfg) -> Result<Io, Error<ConnectError>>
43 where
44 Connect<A>: From<U>,
45 {
46 let timeout = cfg.get::<IoConfig>().connect_timeout();
47 timeout_checked(timeout, async {
48 let msg = resolve::lookup(message.into(), cfg.tag()).await?;
50
51 let port = msg.port();
52 let Connect { req, addr, .. } = msg;
53
54 if let Some(addr) = addr {
55 connect(req, port, addr, cfg).await
56 } else if let Some(addr) = req.addr() {
57 connect(req, addr.port(), Either::Left(addr), cfg).await
58 } else {
59 Err(Error::from(ConnectError::Unresolved))
60 }
61 })
62 .await
63 .map_err(|()| {
64 Error::from(ConnectError::Io(io::Error::new(
65 io::ErrorKind::TimedOut,
66 "Connect timeout",
67 )))
68 })
69 .and_then(|item| item)
70 .map_err(|e| e.with_service(cfg.service()))
71 }
72}
73
74impl<A: Address> Service<SharedCfg, Connect<A>> for Connector<A> {
75 type Res = Io;
76 type Error = Error<ConnectError>;
77
78 async fn call(
79 &self,
80 req: Connect<A>,
81 ctx: Ctx<'_, Self, SharedCfg>,
82 ) -> Result<Io, Self::Error> {
83 self.connect(req, ctx.st()).await
84 }
85}
86
87async fn connect<A: Address>(
89 req: A,
90 port: u16,
91 addr: Either<SocketAddr, VecDeque<SocketAddr>>,
92 cfg: &SharedCfg,
93) -> Result<Io, Error<ConnectError>> {
94 log::trace!(
95 "{}: TCP connector - connecting to {:?} addr:{addr:?} port:{port}",
96 cfg.tag(),
97 req.host(),
98 );
99
100 let io = match addr {
101 Either::Left(addr) => crate::tcp_connect(addr, cfg.clone())
102 .await
103 .map_err(ConnectError::from)?,
104 Either::Right(mut addrs) => loop {
105 let addr = addrs.pop_front().unwrap();
106
107 match crate::tcp_connect(addr, cfg.clone()).await {
108 Ok(io) => break io,
109 Err(err) => {
110 log::trace!(
111 "{}: TCP connector - failed to connect to {:?} port: {port} err: {err:?}",
112 cfg.tag(),
113 req.host(),
114 );
115 if addrs.is_empty() {
116 return Err(ConnectError::from(err).into());
117 }
118 }
119 }
120 },
121 };
122
123 log::trace!(
124 "{}: TCP connector - successfully connected to {:?} - {:?}",
125 cfg.tag(),
126 req.host(),
127 io.query::<types::PeerAddr>().get()
128 );
129 Ok(io)
130}