discord_rpc_client/models/
message.rs1use std::{io::{Write, Read}, mem::size_of};
2use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian};
3use num_derive::FromPrimitive;
4use num_traits::FromPrimitive;
5use serde::Serialize;
6use crate::{Error, Result};
7
8#[repr(u32)]
9#[derive(Debug, Copy, Clone, PartialEq, FromPrimitive)]
10pub enum OpCode {
11 Handshake,
12 Frame,
13 Close,
14 Ping,
15 Pong,
16}
17
18#[derive(Debug, PartialEq, Clone)]
19pub struct Message {
20 pub opcode: OpCode,
21 pub payload: String,
22}
23
24impl Message {
25 pub fn new<T>(opcode: OpCode, payload: T) -> Self
26 where T: Serialize
27 {
28 Self { opcode, payload: serde_json::to_string(&payload).unwrap() }
29 }
30
31 pub fn encode(&self) -> Result<Vec<u8>> {
32 let payload_len = self.payload.len();
33 let mut bytes: Vec<u8> = Vec::with_capacity(2 * size_of::<u32>() + payload_len);
34
35 bytes.write_u32::<LittleEndian>(self.opcode as u32)?;
36 bytes.write_u32::<LittleEndian>(payload_len as u32)?;
37 bytes.write_all(self.payload.as_bytes())?;
38
39 Ok(bytes)
40 }
41
42 pub fn decode(mut bytes: &[u8]) -> Result<Self> {
43 let opcode = OpCode::from_u32(bytes.read_u32::<LittleEndian>()?).ok_or(Error::Conversion)?;
44 let len = bytes.read_u32::<LittleEndian>()? as usize;
45 let mut payload = String::with_capacity(len);
46 bytes.read_to_string(&mut payload)?;
47
48 Ok(Self { opcode, payload })
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[derive(Debug, PartialEq, Serialize, Deserialize)]
57 struct Something {
58 empty: bool
59 }
60
61 #[test]
62 fn test_encoder() {
63 let msg = Message::new(OpCode::Frame, Something { empty: true });
64 let encoded = msg.encode().unwrap();
65 let decoded = Message::decode(&encoded).unwrap();
66 assert_eq!(msg, decoded);
67 }
68
69 #[test]
70 fn test_opcode() {
71 assert_eq!(OpCode::from_u32(0), Some(OpCode::Handshake));
72 assert_eq!(OpCode::from_u32(4), Some(OpCode::Pong));
73 assert_eq!(OpCode::from_u32(5), None);
74 }
75}