use byteorder::{ByteOrder, BigEndian};
use protocol::{Request, Response};
use retry::retry;
use bincode;
use errors::*;
use std::io::{
self,
BufReader,
BufWriter,
Read,
Write,
};
use std::net::TcpStream;
pub struct ServerConnection {
reader : BufReader<TcpStream>,
writer : BufWriter<TcpStream>,
}
impl ServerConnection {
pub fn new(stream : TcpStream) -> io::Result<ServerConnection> {
let writer = try!(stream.try_clone());
Ok(ServerConnection {
reader : BufReader::new(stream),
writer : BufWriter::new(writer),
})
}
pub fn request(&mut self, request: Request) -> Result<Response> {
trace!("ServerConnection::request");
let bytes = bincode::serialize(&request, bincode::Infinite)?;
let mut len = [0; 4];
BigEndian::write_u32(&mut len, bytes.len() as u32);
self.writer.write_all(&len)?;
self.writer.write_all(&bytes)?;
self.writer.flush()?;
trace!("ServerConnection::request: sent request");
self.read_one_response()
}
pub fn read_one_response(&mut self) -> Result<Response> {
trace!("ServerConnection::read_one_response");
let mut bytes = [0; 4];
self.reader.read_exact(&mut bytes).chain_err(|| "Failed to read response header")?;
let len = BigEndian::read_u32(&bytes);
trace!("Should read {} more bytes", len);
let mut data = vec![0; len as usize];
self.reader.read_exact(&mut data)?;
trace!("Done reading");
Ok(bincode::deserialize(&data)?)
}
}
pub fn connect_to_server(port: u16) -> io::Result<ServerConnection> {
trace!("connect_to_server({})", port);
let stream = try!(TcpStream::connect(("127.0.0.1", port)));
ServerConnection::new(stream)
}
pub fn connect_with_retry(port: u16) -> io::Result<ServerConnection> {
trace!("connect_with_retry({})", port);
match retry(10, 500, || connect_to_server(port), |res| res.is_ok()) {
Ok(Ok(conn)) => Ok(conn),
_ => Err(io::Error::new(io::ErrorKind::TimedOut,
"Connection to server timed out")),
}
}