#![warn(missing_docs)]
use std::error::Error;
use std::time::Duration;
use std::io::{BufRead, BufReader, Read, Write};
use std::net::{TcpStream, Shutdown};
#[cfg(test)]
mod tests;
const TIMEOUT_SECS: u64 = 30;
fn wrap(input: String) -> String {
format!("{}\n{}", input.trim().len(), input)
}
pub struct Stream {
socket: TcpStream,
read_buffer: BufReader<TcpStream>,
}
impl Stream {
pub fn new(connection: TcpStream) -> Result<Stream, Box<dyn Error>> {
connection.set_read_timeout(Some(Duration::from_secs(TIMEOUT_SECS)))?;
Ok(Stream {
socket: connection.try_clone()?,
read_buffer: BufReader::new(connection),
})
}
pub fn write(&mut self, input: String) -> Result<(), Box<dyn Error>> {
let input = wrap(input.trim().to_string());
self.socket.write(input.as_ref())?;
Ok(())
}
pub fn read(&mut self) -> Result<String, Box<dyn Error>> {
loop {
let mut header_raw = String::new();
let header_len = self.read_buffer.read_line(&mut header_raw)?;
let header: usize = header_raw.trim().parse()?;
let mut contents = vec![0u8; header];
self.read_buffer.read_exact(&mut contents)?;
self.read_buffer.consume(header + header_len);
return Ok(String::from_utf8(contents)?);
}
}
pub fn close(self) -> Result<(), Box<dyn Error>>{
self.socket.shutdown(Shutdown::Both)?;
Ok(())
}
}