btp 0.1.0

A rust library of, a lightweight protocol, Blog Transfer Protocol.
Documentation
use std::{fs::File, io::Read};

type Error = Box<dyn std::error::Error + Send + Sync>;

#[repr(u8)]
pub enum StatusCode {
    OkieDokie = 0,
    Message = 1,
    File = 2,
    Success = 3,
    Error = 4,
}

pub struct BtpMessage {
    pub header: BtpHeader,
    pub body: String,
}

pub struct BtpHeader {
    pub file_size: [u8; 4],
    pub file_name_size: [u8; 2],
    pub sc: [u8; 1],
    pub version: [u8; 3],
}

pub struct BtpFile {
    pub header: BtpHeader,
    pub file_content: String,
    pub file_name: String,
}

impl BtpHeader {
    pub fn from(
        file_size: [u8; 4],
        file_name_size: [u8; 2],
        sc: [u8; 1],
        version: [u8; 3],
    ) -> Self {
        BtpHeader {
            file_size,
            file_name_size,
            sc,
            version,
        }
    }

    pub fn from_raw(raw: [u8; 10]) -> Result<Self, Error> {
        let res = BtpHeader {
            file_size: raw[..4].try_into()?,
            sc: raw[4..5].try_into()?,
            version: raw[5..8].try_into()?,
            file_name_size: raw[8..].try_into()?,
        };
        Ok(res)
    }

    pub fn get_sc(&self) -> StatusCode {
        match self.sc {
            [0] => StatusCode::OkieDokie,
            [1] => StatusCode::Message,
            [2] => StatusCode::File,
            [3] => StatusCode::Success,
            [4] => StatusCode::Error,
            _ => StatusCode::Error,
        }
    }

    pub fn get_len(&self) -> usize {
        u32::from_be_bytes(self.file_size) as usize
    }

    pub fn get_file_name_len(&self) -> usize {
        u16::from_be_bytes(self.file_name_size) as usize
    }

    pub fn as_raw(self: Self) -> [u8; 10] {
        let mut header = [0u8; 10];
        header[..4].copy_from_slice(&self.file_size);
        header[4..5].copy_from_slice(&self.sc);
        header[5..8].copy_from_slice(&self.version);
        header[8..].copy_from_slice(&self.file_name_size);

        header
    }
}

impl BtpFile {
    pub fn from(
        sc: [u8; 1],
        version: [u8; 3],
        mut file: File,
        file_name: String,
    ) -> Result<BtpFile, Error> {
        let fn_len = file_name.len() as u16;
        let mut file_content = String::new();
        let f_len = file.read_to_string(&mut file_content)? as u32;

        let header = BtpHeader::from(f_len.to_be_bytes(), fn_len.to_be_bytes(), sc, version);

        Ok(BtpFile {
            header,
            file_content,
            file_name,
        })
    }
    pub fn as_vec(self: Self) -> Vec<u8> {
        let mut raw = Vec::new();
        raw.extend_from_slice(&self.header.as_raw());
        raw.extend_from_slice(&self.file_content.as_bytes());
        raw.extend_from_slice(&self.file_name.as_bytes());
        raw
    }

    pub fn from_header(header: BtpHeader, file_name: String, file_content: String) -> Self {
        BtpFile {
            header,
            file_content,
            file_name,
        }
    }
}

impl BtpMessage {
    pub fn from(len: [u8; 4], sc: [u8; 1], version: [u8; 3], msg: String) -> BtpMessage {
        let header = BtpHeader::from(len, [0, 0], sc, version);
        BtpMessage::from_header(header, msg)
    }

    pub fn from_header(header: BtpHeader, body: String) -> Self {
        BtpMessage { header, body }
    }

    pub fn as_vec(self: Self) -> Vec<u8> {
        let mut raw = Vec::new();
        raw.extend_from_slice(&self.header.as_raw());
        raw.extend_from_slice(self.body.as_bytes());
        raw
    }

    pub fn okie(ver: [u8; 3]) -> Self {
        let okie = String::from("okie");
        let len = (okie.len() as u32).to_be_bytes();
        let header = BtpHeader::from(len, [0, 0], [1], ver);
        BtpMessage::from_header(header, okie)
    }

    pub fn dokie(ver: [u8; 3]) -> Self {
        let dokie = String::from("dokie");
        let len = (dokie.len() as u32).to_be_bytes();
        let header = BtpHeader::from(len, [0, 0], [1], ver);
        BtpMessage::from_header(header, dokie)
    }
}