Abstract out NetworkStream
This introduces a new Trait, NetworkStream, which abstracts over the functionality provided by TcpStream so that it can be easily mocked and extended in testing and hyper can be used for other connection sources.
This commit is contained in:
		
				
					committed by
					
						 Jonathan Reem
						Jonathan Reem
					
				
			
			
				
	
			
			
			
						parent
						
							a8d7b681da
						
					
				
				
					commit
					0285fc2acc
				
			| @@ -1,11 +1,13 @@ | ||||
| //! HTTP Server | ||||
| use std::io::net::tcp::{TcpListener, TcpAcceptor}; | ||||
| use std::io::{Acceptor, Listener, IoResult, EndOfFile, IncomingConnections}; | ||||
| use std::io::net::ip::{IpAddr, Port, SocketAddr}; | ||||
|  | ||||
| pub use self::request::Request; | ||||
| pub use self::response::{Response, Fresh, Streaming}; | ||||
|  | ||||
| use net::{NetworkListener, NetworkAcceptor, NetworkStream}; | ||||
| use net::{HttpListener, HttpAcceptor}; | ||||
|  | ||||
| pub mod request; | ||||
| pub mod response; | ||||
|  | ||||
| @@ -13,32 +15,41 @@ pub mod response; | ||||
| /// | ||||
| /// Once listening, it will create a `Request`/`Response` pair for each | ||||
| /// incoming connection, and hand them to the provided handler. | ||||
| pub struct Server { | ||||
| pub struct Server<L = HttpListener> { | ||||
|     ip: IpAddr, | ||||
|     port: Port | ||||
| } | ||||
|  | ||||
|  | ||||
| impl Server { | ||||
|  | ||||
|     /// Creates a server to be used for `http` conenctions. | ||||
| impl Server<HttpListener> { | ||||
|     /// Creates a new server that will handle `HttpStream`s. | ||||
|     pub fn http(ip: IpAddr, port: Port) -> Server { | ||||
|         Server { | ||||
|             ip: ip, | ||||
|             port: port | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<L: NetworkListener<S, A>, S: NetworkStream, A: NetworkAcceptor<S>> Server<L> { | ||||
|  | ||||
|     /// Creates a server that can listen for and handle `NetworkStreams`. | ||||
|     pub fn new(ip: IpAddr, port: Port) -> Server<L> { | ||||
|         Server { | ||||
|             ip: ip, | ||||
|             port: port | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// Binds to a socket, and starts handling connections. | ||||
|     pub fn listen<H: Handler + 'static>(self, handler: H) -> IoResult<Listening> { | ||||
|         let mut listener = try!(TcpListener::bind(self.ip.to_string().as_slice(), self.port)); | ||||
|     pub fn listen<H: Handler<A, S> + 'static>(self, handler: H) -> IoResult<Listening<A>> { | ||||
|         let mut listener: L = try!(NetworkListener::bind(self.ip.to_string().as_slice(), self.port)); | ||||
|         let socket = try!(listener.socket_name()); | ||||
|         let acceptor = try!(listener.listen()); | ||||
|         let worker = acceptor.clone(); | ||||
|         let mut worker = acceptor.clone(); | ||||
|  | ||||
|         spawn(proc() { | ||||
|             let mut acceptor = worker; | ||||
|             handler.handle(Incoming { from: acceptor.incoming() }); | ||||
|             handler.handle(Incoming { from: worker.incoming() }); | ||||
|         }); | ||||
|  | ||||
|         Ok(Listening { | ||||
| @@ -51,12 +62,12 @@ impl Server { | ||||
|  | ||||
| /// An iterator over incoming connections, represented as pairs of | ||||
| /// hyper Requests and Responses. | ||||
| pub struct Incoming<'a> { | ||||
|     from: IncomingConnections<'a, TcpAcceptor> | ||||
| pub struct Incoming<'a, A: 'a = HttpAcceptor> { | ||||
|     from: IncomingConnections<'a, A> | ||||
| } | ||||
|  | ||||
| impl<'a> Iterator<(Request, Response<Fresh>)> for Incoming<'a> { | ||||
|     fn next(&mut self) -> Option<(Request, Response<Fresh>)> { | ||||
| impl<'a, A: NetworkAcceptor<S>, S: NetworkStream> Iterator<(Request<S>, Response<Fresh, S>)> for Incoming<'a, A> { | ||||
|     fn next(&mut self) -> Option<(Request<S>, Response<Fresh, S>)> { | ||||
|         for conn in self.from { | ||||
|             match conn { | ||||
|                 Ok(stream) => { | ||||
| @@ -85,30 +96,30 @@ impl<'a> Iterator<(Request, Response<Fresh>)> for Incoming<'a> { | ||||
| } | ||||
|  | ||||
| /// A listening server, which can later be closed. | ||||
| pub struct Listening { | ||||
|     acceptor: TcpAcceptor, | ||||
| pub struct Listening<A = HttpAcceptor> { | ||||
|     acceptor: A, | ||||
|     /// The socket address that the server is bound to. | ||||
|     pub socket_addr: SocketAddr, | ||||
| } | ||||
|  | ||||
| impl Listening { | ||||
|     /// Stop the server from listening to its socket address. | ||||
| impl<A: NetworkAcceptor<S>, S: NetworkStream> Listening<A> { | ||||
|     /// Stop the server from listening to it's socket address. | ||||
|     pub fn close(mut self) -> IoResult<()> { | ||||
|         debug!("closing server"); | ||||
|         self.acceptor.close_accept() | ||||
|         self.acceptor.close() | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// A handler that can handle incoming requests for a server. | ||||
| pub trait Handler: Send { | ||||
| pub trait Handler<A: NetworkAcceptor<S>, S: NetworkStream>: Send { | ||||
|     /// Receives a `Request`/`Response` pair, and should perform some action on them. | ||||
|     /// | ||||
|     /// This could reading from the request, and writing to the response. | ||||
|     fn handle(self, Incoming); | ||||
|     fn handle(self, Incoming<A>); | ||||
| } | ||||
|  | ||||
| impl Handler for fn(Incoming) { | ||||
|     fn handle(self, incoming: Incoming) { | ||||
| impl<A: NetworkAcceptor<S>, S: NetworkStream> Handler<A, S> for fn(Incoming<A>) { | ||||
|     fn handle(self, incoming: Incoming<A>) { | ||||
|         (self)(incoming) | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user