1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
use std::convert::TryInto;
use std::i16;
use std::io::Error;
use std::io::{Read, Write};
use std::str;

pub struct Response {
    code: u8,
    data: Vec<u8>,
}

impl Response {
    pub fn new(code: u8, data: Vec<u8>) -> Self {
        Response { code, data }
    }

    pub fn print(&self) {
        if self.code == 0x7f {
            let msg = str::from_utf8(&self.data).unwrap();
            println!("[debug] {:?}", msg);
            return;
        }
        if self.code == 0x7e {
            let msg = str::from_utf8(&self.data).unwrap();
            println!("[error] {:?}", msg);
            return;
        }
        if self.code == 0x02 {
            let msg = str::from_utf8(&self.data).unwrap();
            println!("[room] {:?}", msg);
            return;
        }
        if self.code == 0x03 {
            let msg = str::from_utf8(&self.data).unwrap();
            println!("[msg] {:?}", msg);
            return;
        }
        println!("Unhandle code: {:?}", self.code);
    }

    pub fn as_string(&self) -> String {
        String::from_utf8(self.data.clone()).unwrap()
    }
}

fn common(stream: &mut impl Write, code: &[u8], payload: &[u8]) -> Result<usize, Error> {
    let size = payload.len();
    let size: [u8; 8] = size.to_le_bytes();

    let mut written: usize = 0;

    written += stream.write(&code)?;
    written += stream.write(&size[0..2])?;
    written += stream.write(&payload)?;

    Ok(written)
}

pub fn read(stream: &mut impl Read) -> Result<Response, Error> {
    let mut code: [u8; 1] = [0x00];
    let mut size: [u8; 2] = [0x00, 0x00];

    stream.read(&mut code)?;
    stream.read(&mut size)?;

    let size = i16::from_le_bytes(size);
    let size: usize = size.try_into().unwrap();

    let mut buf = Vec::with_capacity(size);
    stream
        .take(size.try_into().unwrap())
        .read_to_end(&mut buf)?;

    Ok(Response::new(code[0], buf))
}

pub fn authenticate(stream: &mut impl Write, token: &str) -> Result<usize, Error> {
    common(stream, &[0x01], token.as_bytes())
}

pub fn enter(stream: &mut impl Write, room: &str) -> Result<usize, Error> {
    common(stream, &[0x02], room.as_bytes())
}

pub fn publish(stream: &mut impl Write, data: &[u8]) -> Result<usize, Error> {
    common(stream, &[0x03], data)
}

pub fn subscribe(stream: &mut impl Write, tag: &str) -> Result<usize, Error> {
    common(stream, &[0x04], tag.as_bytes())
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::env;
    use std::fs::File;
    use std::io::BufWriter;

    #[test]
    fn test_to_authenticate() {
        let mut dir = env::temp_dir();
        dir.push("test_to_authenticate.bin");
        let file = File::create(dir).unwrap();
        let mut file = BufWriter::new(&file);
        let written = authenticate(&mut file, "token").unwrap();
        assert_eq!(written, 1 + 2 + 5);
    }
}