http2byond/
lib.rs

1#![crate_name = "http2byond"]
2
3use std::io::prelude::*;
4use std::net::{SocketAddr,TcpStream};
5use bytes::{Bytes, BytesMut, Buf, BufMut};
6use std::time::Duration;
7
8/// This enum represents the possible return types of send_byond
9/// It can be nothing, a String (containing String), or a Number (containing f32)
10pub enum ByondTopicValue {
11    None,
12    String(String),
13    Number(f32),
14}
15
16/// Main (and only) function of this library.
17/// 
18/// # Arguments
19/// 
20/// * `target` - A TCP SocketAddr of a Dream Daemon instance.
21/// * `topic` - The string you want sent to Dream Daemon. Make sure to always start this with the character `?`.ByondTopicValue
22/// 
23/// # Examples
24/// 
25/// ```
26/// use http2byond::{send_byond, ByondTopicValue};
27/// match send_byond(&SocketAddr::from(([127, 0, 0, 1], 1337)), "?status") {
28///     Err(_) => {}
29///     Ok(btv_result) => {
30///         match btv_result {
31///             ByondTopicValue::None => println!("Byond returned nothing"),
32///             ByondTopicValue::String(str) => println!("Byond returned string {}", str),
33///             ByondTopicValue::Number(num) => println!("Byond returned number {}", num),
34///         }
35///     }
36/// }
37/// ```
38pub fn send_byond(target: &SocketAddr, topic: &str) -> std::io::Result<ByondTopicValue> {
39    let mut stream = TcpStream::connect(target)?;
40    stream.set_read_timeout(Some(Duration::new(5, 0)))?;
41
42    let topic_bytes = topic.as_bytes();
43
44    let mut buf = BytesMut::with_capacity(1024);
45    // Header of 00 83
46    buf.put_u16(0x0083);
47
48    // Unsigned short of data length
49    buf.put_u16(topic_bytes.len() as u16 + 6);
50
51    // 40 bytes of padding
52    buf.put_u32(0x0);
53    buf.put_u8(0x0);
54
55    // Append our topic
56    buf.put(topic_bytes);
57
58    // End with a 00
59    buf.put_u8(0x0);
60
61    println!("{:02X?}", &buf[..]);
62
63    stream.write(&buf)?;
64
65    let mut recv_buf = [0; 1024];
66
67    let bytes_read = stream.read(&mut recv_buf)?;
68
69    if bytes_read == 0 {
70        return Ok(ByondTopicValue::None);
71    }
72
73    let mut recv_buf = Bytes::from(Vec::from(recv_buf));
74
75    if recv_buf.get_u16() == 0x0083 {
76        let mut size = recv_buf.get_u16() - 1;
77        let data_type = recv_buf.get_u8();
78
79        let ret = match data_type {
80            0x2a => ByondTopicValue::Number(recv_buf.get_f32_le()),
81            0x06 => {
82                let mut str = String::new();
83                while size > 0 {
84                    str.push(recv_buf.get_u8() as char);
85                    size -= 1;
86                }
87                ByondTopicValue::String(str)
88            },
89            _ => ByondTopicValue::None,
90        };
91
92        return Ok(ret)
93    }
94
95    Ok(ByondTopicValue::None)
96}
97
98#[test]
99fn it_works() {
100    let res = send_byond(&SocketAddr::from(([127, 0, 0, 1], 1337)), "?status");
101    match res {
102        Err(x) => panic!("Error from send_byond {}", x),
103        Ok(wrapper) => {
104            match wrapper {
105                ByondTopicValue::None => println!("Returned NONE"),
106                ByondTopicValue::String(str) => println!("Returned string {}", str),
107                ByondTopicValue::Number(num) => println!("Returned f32 {}", num)
108            }
109        }
110    }
111}