summaryrefslogtreecommitdiffstats
path: root/src/protocol.rs
blob: 54a343c54cb085f011a59cf32bcdb45eb137bafb (plain)
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
use std::io::{Read, Write};

use crate::Error;

pub const INFO_MSG: &[u8; 29] = br#"{"system":{"get_sysinfo":{}}}"#;

pub trait SHomeProtocol {
    fn recv(&mut self) -> Result<String, Error>;
    fn send(&mut self, msg: &str) -> Result<(), Error>;

    fn encrypt(msg: &str) -> Vec<u8> {
        msg.as_bytes()
            .iter()
            .scan(0xAB, |key, b| {
                *key ^= *b;
                Some(*key)
            })
            .collect()
    }

    fn decrypt(bytes: &[u8]) -> Result<String, Error> {
        let buf: Vec<u8> = bytes
            .iter()
            .scan(0xAB, |key, b| {
                let xor = *b ^ *key;
                *key = *b;
                Some(xor)
            })
            .collect();

        Ok(std::str::from_utf8(&buf)?.to_owned())
    }
}

//impl SHomeProtocol for UdpSocket {
//    fn recv(&mut self) -> Result<String, Error> {
//        todo!()
//    }
//
//    fn send(&mut self, msg: &str) -> Result<(), Error> {
//        todo!()
//    }
//}

impl<T: Read + Write> SHomeProtocol for T {
    fn recv(&mut self) -> Result<String, Error> {
        let mut buf = [0; 4];
        self.read_exact(&mut buf)?;

        let mut buf = vec![0; u32::from_be_bytes(buf) as usize];
        self.read_exact(&mut buf)?;

        Self::decrypt(&buf)
    }

    fn send(&mut self, msg: &str) -> Result<(), Error> {
        let buf = Self::encrypt(msg);

        self.write_all(&(buf.len() as u32).to_be_bytes())?;
        self.write_all(&buf)?;
        Ok(())
    }
}

#[cfg(test)]
pub(crate) mod tests {
    use crate::Device;

    use super::*;

    #[test]
    fn test_get_sysinfo() -> Result<(), Error> {
        let mut device = Device::connect("10.42.0.119:9999")?;
        let msg = device.send(r#"{"system":{"get_sysinfo":{}}}"#)?;

        assert!(!msg.is_empty());

        println!("{msg}");

        Ok(())
    }
}