Skip to content

Instantly share code, notes, and snippets.

@MCausc78
Last active May 29, 2024 20:23
Show Gist options
  • Save MCausc78/4fb04386eeece8e5102ecb356bef8621 to your computer and use it in GitHub Desktop.
Save MCausc78/4fb04386eeece8e5102ecb356bef8621 to your computer and use it in GitHub Desktop.
Basic Discord typings

A basic Discord typings module for Rust

mod typing {
use num_derive::ToPrimitive;
use num_traits::ToPrimitive;
use serde::{Serialize, Serializer};
#[derive(Debug, Default, Serialize)]
pub struct AvatarDecorationData {
asset: String,
#[serde(skip_serializing_if = "Option::is_none")]
sku_id: Option<String>,
}
#[derive(Debug, Default)]
pub struct UserClan {
pub identity_guild_id: String,
pub identity_enabled: bool,
pub tag: String,
pub badge: String,
}
impl Serialize for UserClan {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
#[derive(Debug, Serialize)]
struct TemporaryUserClan<'a> {
identity_guild_id: Option<&'a String>,
identity_enabled: bool,
tag: Option<&'a String>,
badge: Option<&'a String>,
}
if self.identity_enabled {
TemporaryUserClan {
identity_guild_id: Some(&self.identity_guild_id),
identity_enabled: self.identity_enabled,
tag: Some(&self.tag),
badge: Some(&self.badge),
}
} else {
TemporaryUserClan {
identity_guild_id: None,
identity_enabled: self.identity_enabled,
tag: None,
badge: None,
}
}
.serialize(serializer)
}
}
#[derive(Debug, Default, Serialize)]
pub struct PartialUser {
pub id: String,
pub username: String,
pub discriminator: String,
pub global_name: Option<String>,
pub avatar: Option<String>,
pub avatar_decoration_data: Option<AvatarDecorationData>,
pub clan: Option<UserClan>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bot: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub system: Option<bool>,
pub banner: Option<String>,
pub accent_color: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub public_flags: Option<i32>,
}
#[derive(ToPrimitive, PartialEq, Debug)]
pub enum RelationshipKind {
Friend = 1,
Blocked = 2,
IncomingRequest = 3,
OutgoingRequest = 4,
Implicit = 5,
}
impl Serialize for RelationshipKind {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u8(self.to_u8().unwrap())
}
}
#[derive(Debug, Serialize)]
pub struct Relationship {
pub id: String,
#[serde(rename = "type")]
pub kind: RelationshipKind,
pub user: PartialUser,
pub nickname: Option<String>,
}
}
mod gateway {
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug, Serialize)]
#[serde(content = "d", tag = "t", rename_all = "SCREAMING_SNAKE_CASE")]
pub enum DispatchEvent {
Ready {
relationships: Vec<crate::typing::Relationship>,
session_id: String,
},
}
#[derive(Debug, Default, Serialize)]
pub struct Hello {
pub heartbeat_interval: i32,
}
#[derive(Debug)]
pub enum ServerEvent {
Dispatch { data: DispatchEvent, sequence: i32 },
Heartbeat,
HeartbeatAck,
Reconnect,
Hello(Hello),
}
#[derive(Debug, Serialize)]
struct SimpleServerPacket<D> {
op: i32,
d: D,
s: (),
t: (),
}
impl Serialize for ServerEvent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
ServerEvent::Dispatch { data, sequence } => {
#[derive(Debug, Serialize)]
struct DispatchPacket<'a> {
#[serde(flatten)]
inner: &'a DispatchEvent,
op: i32,
s: i32,
}
DispatchPacket {
inner: data,
op: 0,
s: *sequence,
}
.serialize(serializer)
}
ServerEvent::Heartbeat => SimpleServerPacket {
op: 1,
d: (),
s: (),
t: (),
}
.serialize(serializer),
ServerEvent::HeartbeatAck => SimpleServerPacket {
op: 11,
d: (),
s: (),
t: (),
}
.serialize(serializer),
ServerEvent::Reconnect => SimpleServerPacket {
op: 7,
d: (),
s: (),
t: (),
}
.serialize(serializer),
ServerEvent::Hello(d) => SimpleServerPacket {
op: 10,
d,
s: (),
t: (),
}
.serialize(serializer),
}
}
}
#[derive(Debug, Deserialize)]
pub struct Identify {
pub token: String,
pub intents: i32,
}
#[derive(Debug, Deserialize)]
pub struct Resume {
pub token: String,
pub session_id: String,
pub seq: i32,
}
#[derive(Debug, Deserialize)]
pub struct UpdateVoiceState {
pub guild_id: String,
pub channel_id: Option<String>,
pub self_mute: bool,
pub self_deaf: bool,
}
#[derive(Debug)]
pub enum ClientEvent {
Identify(Identify),
Resume(Resume),
Heartbeat(Option<i64>),
UpdateVoiceState(UpdateVoiceState),
}
impl<'de: 'a, 'a> Deserialize<'de> for ClientEvent {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Debug, Deserialize)]
pub struct InternalClientPacket {
op: i32,
d: serde_json::Value,
}
match InternalClientPacket::deserialize(deserializer) {
Ok(packet) => match packet.op {
1 => Ok(ClientEvent::Heartbeat(
Option::<i64>::deserialize(packet.d).unwrap(),
)),
2 => Ok(ClientEvent::Identify(
Identify::deserialize(packet.d).unwrap(),
)),
4 => Ok(ClientEvent::UpdateVoiceState(
UpdateVoiceState::deserialize(packet.d).unwrap(),
)),
6 => Ok(ClientEvent::Resume(Resume::deserialize(packet.d).unwrap())),
_ => panic!("Client opcode sucks {}", packet.op),
},
Err(e) => Err(e),
}
}
}
}
fn main() {
let events = vec![
gateway::ServerEvent::Hello(gateway::Hello {
heartbeat_interval: 41250,
}),
gateway::ServerEvent::Dispatch {
data: gateway::DispatchEvent::Ready {
relationships: vec![typing::Relationship {
id: "1".to_string(),
kind: typing::RelationshipKind::Friend,
user: typing::PartialUser {
id: "1".to_string(),
username: "testuser1".to_string(),
discriminator: "0".to_string(),
clan: Some(typing::UserClan {
identity_guild_id: "3".to_string(),
identity_enabled: true,
badge: "CCCC".to_string(),
tag: "Rust".to_string(),
}),
..Default::default()
},
nickname: None,
}],
session_id: "deeznuts".to_string(),
},
sequence: 1,
},
gateway::ServerEvent::Heartbeat,
gateway::ServerEvent::HeartbeatAck,
gateway::ServerEvent::Reconnect,
];
for event in events {
println!("Server {}", serde_json::to_string(&event).unwrap());
}
let cps = vec![
r##" {"op": 1, "d": null} "##,
r##" {"op": 1, "d": 1} "##,
r##" {"op": 2, "d": {"token": "Test", "intents": 65535} } "##,
r##" {"op": 4, "d": {"guild_id": "3", "channel_id": "4", "self_mute": true, "self_deaf": true}} "##,
r##" {"op": 4, "d": {"guild_id": "3", "channel_id": null, "self_mute": true, "self_deaf": true}} "##,
r##" {"op": 4, "d": {"guild_id": "3", "channel_id": "4", "self_mute": false, "self_deaf": false}} "##,
r##" {"op": 6, "d": {"token": "Test", "session_id": "Test", "seq": 1 }} "##,
];
for cp in cps {
println!(
"Client {:?}",
serde_json::from_str::<gateway::ClientEvent>(cp).unwrap()
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment