qserve 1.2.0

Quickly serve your files on your network with speed and simplicity.
use {
    crate::{
        config::{get_short_path, Config},
        log::Logger,
        operations::html,
        response::Response,
    },
    std::{
        fs,
        fs::DirEntry,
        io::{Read, Write},
        net::TcpStream,
        path::Path,
    },
};

pub fn read_dir(path: &str) -> std::io::Result<Vec<DirEntry>> {
    let dir = fs::read_dir(path)?;
    let mut contents = Vec::new();
    for e in dir {
        contents.push(e.unwrap())
    }

    Ok(contents)
}

pub fn serve_file(mut stream: &TcpStream, path: String) {
    let file_contents = fs::read_to_string(path).unwrap();

    let _ = stream.write_all(Response::ok(&file_contents, "text/html").as_bytes());
}

pub fn stream(mut stream: &TcpStream, content_len: u64, path: String) {
    let config = Config::parse();
    match fs::File::open(&path) {
        Ok(mut file_buffer) => {
            let mut buffer = vec![0; config.chunks];
            let file_name = Path::new(&path).file_name().unwrap().to_str().unwrap();
            let _ = stream.write_all(Response::send_file(content_len, file_name).as_bytes());

            loop {
                match file_buffer.read(&mut buffer) {
                    Ok(bytes) => {
                        if bytes == 0 {
                            break;
                        }

                        let _ = stream.write_all(&buffer[..bytes]);
                    }
                    Err(e) => Logger::error(format!("file reading failed, {}", e)),
                }
            }
        }

        Err(e) => {
            let _ = stream.write_all(
                Response::bad_request("error: check terminal for logs", "text/plain").as_bytes(),
            );
            Logger::error(format!("{}", e))
        }
    }
}

pub fn serve_dir(mut stream: &TcpStream, request: String, path: String, back_btn: bool) {
    match read_dir(&path) {
        Ok(dir_contents) => {
            let mut contents = Vec::new();
            if back_btn {
                let parent_directory = Path::new(request.split_whitespace().nth(1).unwrap())
                    .parent()
                    .unwrap()
                    .display();
                contents.push(format!(
                    "<a class=\"back\" href=\"{}\"></a>",
                    parent_directory
                ));
            }

            for i in dir_contents {
                let mut file_type = String::from("file");
                match fs::metadata(i.path()) {
                    Ok(f_type) => {
                        if f_type.is_dir() {
                            file_type = "dir".to_string()
                        }
                    }
                    Err(_) => Logger::warn("unknown error"),
                }

                contents.push(format!(
                    "<a class=\"{0}\" href=\"{1}\">{2}</a>",
                    file_type,
                    get_short_path(i.path().display().to_string()),
                    i.file_name().to_str().unwrap()
                ));
            }

            let _ = stream.write_all(
                Response::ok(&html::generate(&contents.join("\n"), &path), "text/html").as_bytes(),
            );
        }
        Err(e) => {
            let _ = stream.write_all(
                Response::bad_request("error reading dir, check terminal for logs", "text/plain")
                    .as_bytes(),
            );
            Logger::error(format!("{}", e));
        }
    };
}