buss_protocol/
lib.rs

1pub mod actions;
2pub mod settings;
3pub mod types;
4
5pub use actions::BussAction;
6pub use settings::BussSettings;
7pub use types::buss_flags;
8
9/// Version of bussin binary protocol
10mod version {
11    pub const MAJOR: u8 = 1;
12    pub const MINOR: u8 = 0;
13}
14
15/// The protocol header
16pub struct BussHeader {
17    /// Set to 0x00042069. The server/client should check if the first 4 bytes matches these sequence. Otherwise should cancel the request and respond with an error.
18    /// If you see this, we are bussin.
19    pub magic_number: u32,
20    /// Bussin protocol version number. e.g. if currently at version 69.1 it will be the 69 part
21    pub version_major: u8,
22    /// Bussing protocol version number minor. e.g. if currently at version 69.1 it will be the 1 part
23    pub version_minor: u8,
24    /// Action the client wants executed or what response code the server replied with.
25    pub action: BussAction,
26    /// Flags that describe the binary content of the protocol
27    pub flags: u8,
28}
29
30/// Trait to facilitate conversion of various bussin types to raw bytes
31pub trait ToBytes {
32    /// Convert to bytes
33    fn to_bytes(self) -> Vec<u8>;
34}
35
36/// Trait to do the conversion of raw bytes to the given type
37pub trait FromBytes<T: Sized> {
38    /// get a type from the sized byte array
39    fn from_bytes(bytes: T) -> Self;
40}
41
42impl BussHeader {
43    /// Create new head
44    pub fn new() -> Self {
45        BussHeader {
46            magic_number: 0x00042069,
47            version_major: version::MAJOR,
48            version_minor: version::MINOR,
49            action: BussAction::Noop,
50            flags: 0,
51        }
52    }
53    /// Sets the action to be performed
54    pub fn set_action(&mut self, action: BussAction) {
55        self.action = action;
56    }
57}
58
59impl Default for BussHeader {
60    fn default() -> Self {
61        Self::new()
62    }
63}
64
65impl ToBytes for BussHeader {
66    fn to_bytes(self) -> Vec<u8> {
67        let mut bytes = Vec::new();
68        bytes.extend(self.magic_number.to_be_bytes());
69        bytes.push(self.version_major);
70        bytes.push(self.version_minor);
71        bytes.push(self.action as u8);
72        bytes.push(self.flags);
73        bytes
74    }
75}
76impl FromBytes<&[u8; 8]> for BussHeader {
77    fn from_bytes(bytes: &[u8; 8]) -> Self {
78        let magic_bytes = &bytes[0..4];
79        let magic_number = u32::from_be_bytes(magic_bytes.try_into().unwrap());
80        let version_major = bytes[4];
81        let version_minor = bytes[5];
82        let action_number = bytes[6];
83        let action: BussAction = action_number.try_into().unwrap();
84        let flags = bytes[7];
85
86        BussHeader {
87            magic_number,
88            version_major,
89            version_minor,
90            action,
91            flags,
92        }
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use std::{
99        fs::File,
100        io::{self, Write},
101    };
102
103    use crate::{
104        settings::{BodyLength, Host, Settings},
105        types::BussPath,
106        BussAction, BussHeader, ToBytes,
107    };
108
109    #[test]
110    fn skeleton() -> io::Result<()> {
111        let mut header = BussHeader::new();
112        header.set_action(BussAction::Read);
113        let content = "Hello from the rizzler!";
114
115        let mut settings = Settings::new();
116        settings.add(Box::new(BodyLength::new(content.len())));
117        settings.add(Box::new(Host::new("buss.rizz")));
118
119        let path = BussPath::new("/");
120
121        let mut file: File = File::create("test.bbp")?;
122        let _ = file.write(&header.to_bytes())?;
123        let _ = file.write(&path.to_bytes())?;
124        let _ = file.write(&settings.to_bytes())?;
125
126        let _ = file.write(content.as_bytes())?;
127
128        Ok(())
129    }
130}