use std::convert::From;
use std::io;
use std::io::{ErrorKind, Read, Write};
use std::net::{Shutdown, TcpStream};
use std::ops::Drop;
use ::{TransportError, TransportErrorKind};
pub struct TTcpTransport {
stream: Option<TcpStream>,
}
impl TTcpTransport {
pub fn new() -> TTcpTransport {
TTcpTransport {
stream: None,
}
}
pub fn using_stream(stream: TcpStream) -> TTcpTransport {
TTcpTransport {
stream: Some(stream),
}
}
pub fn open(&mut self, remote_address: &str) -> ::Result<()> {
if let Some(_) = self.stream {
Err(
::Error::Transport(
TransportError::new(TransportErrorKind::AlreadyOpen, "transport previously opened")
)
)
} else {
match TcpStream::connect(&remote_address) {
Ok(s) => {
self.stream = Some(s);
Ok(())
}
Err(e) => Err(From::from(e))
}
}
}
pub fn close(&mut self) -> ::Result<()> {
self.if_set(|s| s.shutdown(Shutdown::Both)).map_err(From::from)
}
fn if_set<F, T>(&mut self, mut stream_operation: F) -> io::Result<T>
where F: FnMut(&mut TcpStream) -> io::Result<T> {
if let Some(ref mut s) = self.stream {
stream_operation(s)
} else {
Err(io::Error::new(ErrorKind::NotConnected, "tcp endpoint not connected"))
}
}
}
impl Read for TTcpTransport {
fn read(&mut self, b: &mut [u8]) -> io::Result<usize> {
self.if_set(|s| s.read(b))
}
}
impl Write for TTcpTransport {
fn write(&mut self, b: &[u8]) -> io::Result<usize> {
self.if_set(|s| s.write(b))
}
fn flush(&mut self) -> io::Result<()> {
self.if_set(|s| s.flush())
}
}
impl Drop for TTcpTransport {
fn drop(&mut self) {
if let Err(e) = self.close() {
warn!("error while closing socket transport: {:?}", e)
}
}
}