tplink_shome_protocol/
lib.rs

1//! Simple library to easily communicate with a tp link smart device.
2//! # Usage
3//! ```rust
4//! use std::io;
5//! use std::net::TcpStream;
6//!
7//! use tplink_shome_protocol::{receive_message, send_message};
8//!
9//! fn main() -> io::Result<()> {
10//!     let stream = TcpStream::connect("192.168.1.1:9999")?;
11//!     let raw = r#"{"system":{"get_sysinfo":{}}}"#;
12//!     send_message(&stream, raw)?;
13//!     let message = receive_message(&stream)?;
14//!     ...
15//! }
16//! ```
17use std::{
18    io::{self, Read, Write},
19    net::TcpStream,
20};
21
22pub fn encrypt(data: &[u8]) -> Vec<u8> {
23    let mut encryption_key = 0xAB;
24    data.iter()
25        .map(|e| {
26            let res = e ^ encryption_key;
27            encryption_key = res;
28            res
29        })
30        .collect()
31}
32
33pub fn decrypt(encrypted: &[u8]) -> Vec<u8> {
34    let mut encryption_key = 0xAB;
35    encrypted
36        .iter()
37        .map(|e| {
38            let res = e ^ encryption_key;
39            encryption_key = *e;
40            res
41        })
42        .collect()
43}
44
45///
46/// Blocks until it receives a message from the [TcpStream]
47///
48/// Example
49/// ```
50///use std::io;
51///use std::net::TcpStream;
52///
53///use tplink_shome_protocol::receive_message;
54///
55///fn main() -> io::Result<()> {
56///    let stream = TcpStream::connect("192.168.1.1:9999")?;
57///    let response = receive_message(&stream)?;
58///    ...
59///}
60/// ```
61///
62pub fn receive_message(mut stream: &TcpStream) -> io::Result<String> {
63    let mut lenbuff = [0; 4];
64    stream.read_exact(&mut lenbuff)?;
65    let num = u32::from_be_bytes(lenbuff);
66    let mut buffer: Vec<u8> = vec![0; num as usize];
67    stream.read_exact(&mut buffer)?;
68    let decrypted = decrypt(&buffer);
69    match std::str::from_utf8(&decrypted) {
70        Ok(v) => Ok(v.to_string()),
71        Err(e) => Err(io::Error::new(
72            io::ErrorKind::InvalidData,
73            format!("received message is invalid {e}"),
74        )),
75    }
76}
77
78///
79/// Sends a message to the smart device connected via the [TcpStream]
80///
81/// Example
82/// ```
83///use std::io;
84///use std::net::TcpStream;
85///
86/// use tplink_shome_protocol::send_message;
87///
88///fn main() -> io::Result<()> {
89///    let stream = TcpStream::connect("192.168.1.1:9999")?;
90///    let raw = r#"{"system":{"get_sysinfo":{}}}"#;
91///    let response = receive_message(&stream)?;
92///    ...
93///}
94/// ```
95///
96pub fn send_message(mut stream: &TcpStream, message: &str) -> io::Result<()> {
97    let encrypted = encrypt(message.as_bytes());
98    let b32len: u32 = encrypted.len() as u32;
99    let lenbytes = b32len.to_be_bytes();
100
101    // send first length of data
102    stream.write_all(&lenbytes)?;
103
104    stream.write_all(&encrypted)?;
105    Ok(())
106}