tw-econ 0.9.0

Simple Rust library to use Teeworlds external console
Documentation
use std::io::{Read, Write};
use std::net::{Shutdown, SocketAddr, TcpStream};
use std::time::Duration;

pub struct EconRaw {
    socket: TcpStream,
    buffer: Vec<u8>,
    lines: Vec<String>,
    unfinished_line: String,
    authed: bool,
    auth_message: String,
    timeout_secs: u64,
}

impl EconRaw {
    pub fn connect(
        address: impl Into<SocketAddr>,
        buffer_size: usize,
        timeout_secs: u64,
    ) -> std::io::Result<Self> {
        let buffer = vec![0u8; buffer_size];
        let address = address.into();

        let connection = TcpStream::connect_timeout(&address, Duration::from_secs(timeout_secs))?;

        Ok(Self {
            socket: connection,
            buffer,
            lines: Vec::new(),
            unfinished_line: String::new(),
            authed: false,
            auth_message: "Authentication successful".to_string(),
            timeout_secs,
        })
    }

    pub fn reconnect(&mut self) -> std::io::Result<()> {
        self.socket = TcpStream::connect_timeout(
            &self.socket.peer_addr().unwrap(),
            Duration::from_secs(self.timeout_secs),
        )?;

        Ok(())
    }

    pub fn disconnect(&mut self) -> std::io::Result<()> {
        self.socket.shutdown(Shutdown::Both)
    }

    pub fn set_auth_message(&mut self, auth_message: String) {
        self.auth_message = auth_message;
    }

    pub fn auth(&mut self, password: &str) -> std::io::Result<bool> {
        self.send(password)?;

        self.read()?;

        while let Some(line) = self.pop_line() {
            if line.starts_with(self.auth_message.as_str()) {
                self.authed = true;
            }
        }

        Ok(self.authed)
    }

    pub fn read(&mut self) -> std::io::Result<usize> {
        let mut lines_amount = 0;
        let written = self.socket.read(&mut self.buffer)?;

        if written != 0 {
            let mut lines: Vec<String> = String::from_utf8_lossy(&self.buffer[..written])
                .replace('\0', "")
                .split("\n")
                .map(String::from)
                .collect();

            if lines.last().unwrap() == "" {
                let _ = lines.pop();

                if !self.unfinished_line.is_empty() {
                    let take = self.unfinished_line.to_owned();
                    lines[0] = take + &lines[0];

                    self.unfinished_line.clear();
                }
            } else {
                self.unfinished_line = lines.pop().unwrap();
            }

            lines_amount = lines.len();

            self.lines.extend(lines);
        }

        Ok(lines_amount)
    }

    pub fn send(&mut self, line: &str) -> std::io::Result<()> {
        self.socket.write_all(line.as_bytes())?;
        self.socket.write_all("\n".as_bytes())?;

        self.socket.flush()?;

        Ok(())
    }

    pub fn pop_line(&mut self) -> Option<String> {
        self.lines.pop()
    }

    pub fn is_authed(&self) -> bool {
        self.authed
    }
}