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