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)
}
}