1 use std::{fmt, io};
2 use std::sync::Arc;
3 use std::net::SocketAddr;
4 use std::marker::PhantomData;
5 
6 use BindClient;
7 use tokio_core::reactor::Handle;
8 use tokio_core::net::{TcpStream, TcpStreamNew};
9 use futures::{Future, Poll, Async};
10 
11 // TODO: add configuration, e.g.:
12 // - connection timeout
13 // - multiple addresses
14 // - request timeout
15 
16 // TODO: consider global event loop handle, so that providing one in the builder
17 // is optional
18 
19 /// Builds client connections to external services.
20 ///
21 /// To connect to a service, you need a *client protocol* implementation; see
22 /// the crate documentation for guidance.
23 ///
24 /// At the moment, this builder offers minimal configuration, but more will be
25 /// added over time.
26 #[derive(Debug)]
27 pub struct TcpClient<Kind, P> {
28     _kind: PhantomData<Kind>,
29     proto: Arc<P>,
30 }
31 
32 /// A future for establishing a client connection.
33 ///
34 /// Yields a service for interacting with the server.
35 pub struct Connect<Kind, P> {
36     _kind: PhantomData<Kind>,
37     proto: Arc<P>,
38     socket: TcpStreamNew,
39     handle: Handle,
40 }
41 
42 impl<Kind, P> Future for Connect<Kind, P> where P: BindClient<Kind, TcpStream> {
43     type Item = P::BindClient;
44     type Error = io::Error;
45 
poll(&mut self) -> Poll<P::BindClient, io::Error>46     fn poll(&mut self) -> Poll<P::BindClient, io::Error> {
47         let socket = try_ready!(self.socket.poll());
48         Ok(Async::Ready(self.proto.bind_client(&self.handle, socket)))
49     }
50 }
51 
52 impl<Kind, P> TcpClient<Kind, P> where P: BindClient<Kind, TcpStream> {
53     /// Create a builder for the given client protocol.
54     ///
55     /// To connect to a service, you need a *client protocol* implementation;
56     /// see the crate documentation for guidance.
new(protocol: P) -> TcpClient<Kind, P>57     pub fn new(protocol: P) -> TcpClient<Kind, P> {
58         TcpClient {
59             _kind: PhantomData,
60             proto: Arc::new(protocol)
61         }
62     }
63 
64     /// Establish a connection to the given address.
65     ///
66     /// # Return value
67     ///
68     /// Returns a future for the establishment of the connection. When the
69     /// future completes, it yields an instance of `Service` for interacting
70     /// with the server.
connect(&self, addr: &SocketAddr, handle: &Handle) -> Connect<Kind, P>71     pub fn connect(&self, addr: &SocketAddr, handle: &Handle) -> Connect<Kind, P> {
72         Connect {
73             _kind: PhantomData,
74             proto: self.proto.clone(),
75             socket: TcpStream::connect(addr, handle),
76             handle: handle.clone(),
77         }
78     }
79 }
80 
81 impl<Kind, P> fmt::Debug for Connect<Kind, P> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result82     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83         write!(f, "Connect {{ ... }}")
84     }
85 }
86