use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_repr::*; use std::convert::TryFrom; use std::num::ParseIntError; use std::str::FromStr; #[repr(u16)] #[derive(Serialize_repr, Deserialize_repr, Copy, Ord, PartialOrd, Eq, PartialEq, Debug, Clone)] pub enum GatewayOpcode { Dispatch = 0, Heartbeat = 1, Identify = 2, StatusUpdate = 3, VoiceStateUpdate = 4, Resume = 6, Reconnect = 7, RequestGuildMembers = 8, InvalidSession = 9, Hello = 10, HeartbeatAck = 11, UnknownError = 4000, UnknownOpcode = 4001, DecodeError = 4002, NotAuthenticated = 4003, AuthenticationFailed = 4004, InvalidSeq = 4007, RateLimited = 4008, SessionTimeout = 4009, InvalidShard = 4010, ShardingRequired = 4011, } impl GatewayOpcode { #[inline] fn is_err(&self) -> bool { return (*self as u16) >= 4000; } #[inline] fn is_ok(&self) -> bool { return (*self as u16) < 4000; } } #[derive(Debug, Clone, Deserialize, Serialize)] pub struct GatewayEvent { #[serde(rename = "op")] pub opcode: GatewayOpcode, #[serde(rename = "d")] pub data: Value, #[serde(rename = "s")] pub sequence_num: Option, #[serde(rename = "t")] pub event_name: Option, } #[derive(Debug, Clone, Deserialize, Serialize)] pub struct Identify { pub token: String, pub properties: IdentifyProperties, } #[derive(Debug, Clone, Deserialize, Serialize)] pub struct IdentifyProperties { #[serde(rename = "$os")] pub os: String, #[serde(rename = "$browser")] pub browser: String, #[serde(rename = "$device")] pub device: String, } #[derive(Debug, Clone, Deserialize, Serialize)] pub struct Ready { #[serde(rename = "v")] protocol_version: u32, user: (), private_channels: Vec<()>, guilds: Vec, session_id: String, shared: Option<(u32, u32)>, } #[derive(Debug, Clone, Copy, Deserialize, Serialize)] pub struct UnavailableGuild { id: Snowflake, available: bool, } #[derive(Debug, Clone, Deserialize, Serialize)] pub struct Resume { token: String, session_id: String, seq: u64, } #[derive(Debug, Clone, Deserialize, Serialize)] pub struct GatewayBot { pub url: String, shards: u32, session_start_limit: SessionStartLimit, } #[derive(Debug, Clone, Copy, Deserialize, Serialize)] pub struct SessionStartLimit { total: u64, remaining: u64, reset_after: u64, } #[derive(Debug, Clone, Deserialize, Serialize)] pub struct RateLimitNotice { pub global: bool, message: String, pub retry_after: u64, } #[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)] #[serde(try_from = "String", into = "String")] pub struct Snowflake(u64); impl Into for Snowflake { fn into(self) -> String { self.0.to_string() } } impl TryFrom for Snowflake { type Error = ParseIntError; fn try_from(from: String) -> Result { Ok(Snowflake(u64::from_str(&from)?)) } } #[cfg(test)] mod test { use crate::discord::dto::{GatewayOpcode, Snowflake}; #[test] fn snowflake() { assert_eq!( Ok(Snowflake(4)), serde_json::from_str("\"4\"").map_err(|_| ()) ); assert_eq!( Ok("\"4\"".to_string()), serde_json::to_string(&Snowflake(4)).map_err(|_| ()) ); } #[test] fn opcode() { assert!(GatewayOpcode::SessionTimeout.is_err()) } }