ts3/
lib.rs

1//! # TS3
2//! A fully asynchronous library to interact with the TeamSpeak 3 Server query interface.
3//! The commands are avaliable after connecting to a TS3 Server using a [`Client`]. Commands
4//! can either be sent using the associated command or using [`Client.sent`] to send raw messages.
5//!
6//! # Examples
7//!
8//! Connect to a TS3 query interface and select a server
9//! ```no_run
10//! use ts3::Client;
11//!
12//! #[tokio::main]
13//! async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
14//!     // Create a new client and connect to the server query interface
15//!     let client = Client::connect("localhost:10011").await?;
16//!
17//!     // switch to virtual server with id 1
18//!     client.use_sid(1).await?;
19//!
20//!     Ok(())
21//! }
22//! ```
23//!
24//! ```no_run
25//! use ts3::{Client, async_trait};
26//! use ts3::request::{TextMessageTarget};
27//! use ts3::event::{EventHandler, ClientEnterView};
28//!
29//! #[tokio::main]
30//! async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
31//!     let client = Client::connect("localhost:10011").await?;
32//!
33//!     client.use_sid(1).await?;
34//!
35//!     // Assign a new event handler.
36//!     client.set_event_handler(Handler);
37//!
38//!     tokio::signal::ctrl_c().await?;
39//!     Ok(())
40//! }
41//!
42//! pub struct Handler;
43//!
44//! #[async_trait]
45//! impl EventHandler for Handler {
46//!     async fn cliententerview(&self, client: Client, event: ClientEnterView) {
47//!         println!("Client {} joined!", event.client_nickname);
48//!
49//!         // Send a private message to the client using "sendtextmessage".
50//!         client.sendtextmessage(TextMessageTarget::Client(event.clid), "Hello World!")
51//!             .await.unwrap();
52//!     }
53//! }
54//!
55//! ```
56
57extern crate self as ts3;
58
59mod client;
60pub mod event;
61pub mod request;
62pub mod response;
63pub mod shared;
64mod types;
65
66pub use async_trait::async_trait;
67pub use client::Client;
68pub use ts3_derive::Decode;
69
70use std::{
71    convert::{Infallible, TryFrom},
72    fmt::{Debug, Write},
73    io,
74    num::ParseIntError,
75    str::{from_utf8, Utf8Error},
76};
77
78use thiserror::Error;
79
80/// An error that can occur when interacting with the TS3 query API.
81#[derive(Debug, Error)]
82#[error(transparent)]
83pub struct Error(ErrorKind);
84
85impl From<Infallible> for Error {
86    fn from(value: Infallible) -> Self {
87        match value {}
88    }
89}
90
91#[derive(Debug, Error)]
92enum ErrorKind {
93    /// Error returned from the ts3 interface. id of 0 indicates no error.
94    #[error("TS3 error {id}: {msg}")]
95    TS3 { id: u16, msg: String },
96    /// Io error from the underlying tcp stream.
97    #[error("io: {0}")]
98    Io(#[from] io::Error),
99    /// Error occured while decoding the server response.
100    #[error("failed to decode stream: {0}")]
101    Decode(#[from] DecodeError),
102    #[error("failed to parse integer: {0}")]
103    ParseInt(#[from] ParseIntError),
104    #[error("recevied invalid utf8: {0}")]
105    Utf8(#[from] Utf8Error),
106    #[error("send error")]
107    SendError,
108    #[error("no field")]
109    NoField,
110}
111
112#[derive(Debug, Error)]
113enum DecodeError {
114    #[error("unexpected eof")]
115    UnexpectedEof,
116    #[error("unexpected byte: {0}")]
117    UnexpectedByte(u8),
118    #[error("invalid reasonid: {0}")]
119    InvalidReasonId(u8),
120    #[error("invalid apikey scope: {0}")]
121    InvalidApiKeyScope(String),
122}
123
124/// Any type implementing `Decode` can be directly decoded from the TS3 stream.
125/// It provides the complete buffer of the response from the stream.
126pub trait Decode: Sized {
127    type Error: std::error::Error;
128
129    fn decode(buf: &[u8]) -> Result<Self, Self::Error>;
130}
131
132pub trait Encode {
133    fn encode(&self, buf: &mut String);
134}
135
136/// Implements `Serialize` for types that can be directly written as they are formatted.
137macro_rules! impl_serialize {
138    ($t:ty) => {
139        impl crate::Encode for $t {
140            fn encode(&self, writer: &mut ::std::string::String) {
141                write!(writer, "{}", self).unwrap();
142            }
143        }
144    };
145}
146
147/// The `impl_decode` macro implements `Decode` for any type that implements `FromStr`.
148macro_rules! impl_decode {
149    ($t:ty) => {
150        impl Decode for $t {
151            type Error = Error;
152
153            fn decode(buf: &[u8]) -> std::result::Result<$t, Self::Error> {
154                Ok(from_utf8(buf)
155                    .map_err(|e| Error(ErrorKind::Utf8(e)))?
156                    .parse()
157                    .map_err(|e| Error(ErrorKind::ParseInt(e)))?)
158            }
159        }
160    };
161}
162
163/// Implement `Decode` for `()`. Calling `()::decode(&[u8])` will never fail
164/// and can always be unwrapped safely.
165impl Decode for () {
166    type Error = Infallible;
167
168    fn decode(_: &[u8]) -> Result<(), Self::Error> {
169        Ok(())
170    }
171}
172
173// Implement `Decode` for `String`
174impl Decode for String {
175    type Error = Error;
176
177    fn decode(buf: &[u8]) -> Result<String, Self::Error> {
178        // Create a new string, allocating the same length as the buffer. Most
179        // chars are one-byte only.
180        let mut string = String::with_capacity(buf.len());
181
182        // Create a peekable iterator to iterate over all bytes, appending all bytes
183        // and replacing escaped chars.
184        let mut iter = buf.into_iter().peekable();
185        while let Some(b) = iter.next() {
186            match b {
187                // Match any escapes, starting with a '\' followed by another char.
188                b'\\' => {
189                    match iter.peek() {
190                        Some(c) => match c {
191                            b'\\' => string.push('\\'),
192                            b'/' => string.push('/'),
193                            b's' => string.push(' '),
194                            b'p' => string.push('|'),
195                            b'a' => string.push(7u8 as char),
196                            b'b' => string.push(8u8 as char),
197                            b'f' => string.push(12u8 as char),
198                            b'n' => string.push(10u8 as char),
199                            b'r' => string.push(13u8 as char),
200                            b't' => string.push(9u8 as char),
201                            b'v' => string.push(11u8 as char),
202                            _ => {
203                                return Err(Error(ErrorKind::Decode(DecodeError::UnexpectedByte(
204                                    **c,
205                                ))))
206                            }
207                        },
208                        None => {
209                            return Err(Error(ErrorKind::Decode(DecodeError::UnexpectedEof.into())))
210                        }
211                    }
212                    iter.next();
213                }
214                _ => string.push(char::try_from(*b).unwrap()),
215            }
216        }
217
218        // Shrink the string to its fitting size before returning it.
219        string.shrink_to_fit();
220        Ok(string)
221    }
222}
223
224impl Encode for &str {
225    fn encode(&self, writer: &mut String) {
226        for c in self.chars() {
227            match c {
228                '\\' => writer.write_str("\\\\").unwrap(),
229                '/' => writer.write_str("\\/").unwrap(),
230                ' ' => writer.write_str("\\s").unwrap(),
231                '|' => writer.write_str("\\p").unwrap(),
232                c if c == 7u8 as char => writer.write_str("\\a").unwrap(),
233                c if c == 8u8 as char => writer.write_str("\\b").unwrap(),
234                c if c == 12u8 as char => writer.write_str("\\f").unwrap(),
235                c if c == 10u8 as char => writer.write_str("\\n").unwrap(),
236                c if c == 13u8 as char => writer.write_str("\\r").unwrap(),
237                c if c == 9u8 as char => writer.write_str("\\t").unwrap(),
238                c if c == 11u8 as char => writer.write_str("\\v").unwrap(),
239                _ => writer.write_char(c).unwrap(),
240            }
241        }
242    }
243}
244
245impl Encode for bool {
246    fn encode(&self, writer: &mut String) {
247        write!(
248            writer,
249            "{}",
250            match self {
251                false => b'0',
252                true => b'1',
253            }
254        )
255        .unwrap();
256    }
257}
258
259impl Decode for bool {
260    type Error = Error;
261
262    fn decode(buf: &[u8]) -> Result<bool, Self::Error> {
263        match buf.get(0) {
264            Some(b) => match b {
265                b'0' => Ok(true),
266                b'1' => Ok(false),
267                _ => Err(Error(ErrorKind::Decode(
268                    DecodeError::UnexpectedByte(*b).into(),
269                ))),
270            },
271            None => Err(Error(ErrorKind::Decode(DecodeError::UnexpectedEof.into()))),
272        }
273    }
274}
275
276// Implement `Decode` for all int types.
277impl_decode!(isize);
278impl_decode!(i8);
279impl_decode!(i16);
280impl_decode!(i32);
281impl_decode!(i64);
282impl_decode!(i128);
283
284impl_decode!(usize);
285impl_decode!(u8);
286impl_decode!(u16);
287impl_decode!(u32);
288impl_decode!(u64);
289impl_decode!(u128);
290
291impl_serialize!(isize);
292impl_serialize!(i8);
293impl_serialize!(i16);
294impl_serialize!(i32);
295impl_serialize!(i64);
296impl_serialize!(i128);
297
298impl_serialize!(usize);
299impl_serialize!(u8);
300impl_serialize!(u16);
301impl_serialize!(u32);
302impl_serialize!(u64);
303impl_serialize!(u128);
304
305impl Error {
306    fn decode(buf: &[u8]) -> Result<Error, Error> {
307        let (mut id, mut msg) = (0, String::new());
308
309        // Error is a key-value map separated by ' ' with only the id and msg key.
310        for s in buf.split(|c| *c == b' ') {
311            // Error starts with "error" as the first key.
312            if s == b"error" {
313                continue;
314            }
315
316            // Get both key and value from the buffer, separated by a '='.
317            let parts: Vec<&[u8]> = s.splitn(2, |c| *c == b'=').collect();
318
319            match parts.get(0) {
320                Some(key) => {
321                    // Extract the value.
322                    let val = match parts.get(1) {
323                        Some(val) => val,
324                        None => return Err(Error(ErrorKind::Decode(DecodeError::UnexpectedEof))),
325                    };
326
327                    // Match the key of the pair and assign the corresponding value.
328                    match *key {
329                        b"id" => {
330                            id = u16::decode(val)?;
331                        }
332                        b"msg" => {
333                            msg = String::decode(val)?;
334                        }
335                        _ => (),
336                    }
337                }
338                None => return Err(Error(ErrorKind::Decode(DecodeError::UnexpectedEof))),
339            }
340        }
341
342        Ok(Error(ErrorKind::TS3 { id, msg }))
343    }
344}
345
346#[cfg(test)]
347mod tests {
348    use super::{Decode, Error, ErrorKind};
349
350    #[test]
351    fn test_string_decode() {
352        let buf = b"Hello\\sWorld!";
353        assert_eq!(String::decode(buf).unwrap(), "Hello World!".to_owned());
354    }
355
356    #[test]
357    fn test_error_decode() {
358        let buf = b"error id=0 msg=ok";
359        let (id, msg) = match Error::decode(buf).unwrap().0 {
360            ErrorKind::TS3 { id, msg } => (id, msg),
361            _ => unreachable!(),
362        };
363        assert!(id == 0 && msg == "ok".to_owned());
364    }
365}