initial commit
commit
ee1f66651a
@ -0,0 +1,2 @@
|
||||
/target
|
||||
**/*.rs.bk
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "unredeemed"
|
||||
version = "0.1.0"
|
||||
authors = ["eater <=@eater.me>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
[dependencies]
|
||||
tungstenite = "0.9.2"
|
||||
reqwest = "0.10.1"
|
||||
async-std = { version = "1.4.0", features = ["attributes", "unstable"] }
|
||||
crossbeam-channel = "0.4.0"
|
||||
bytes = "0.5.3"
|
||||
serde_json = "1.0.44"
|
||||
serde_repr = "0.1.5"
|
||||
serde = { version ="1.0.104", features = ["derive"] }
|
@ -0,0 +1,3 @@
|
||||
# Unredeemed
|
||||
|
||||
> Discord bot, but make it cursed
|
@ -0,0 +1,126 @@
|
||||
use bytes::Bytes;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde_repr::*;
|
||||
use std::convert::{TryFrom, Infallible};
|
||||
use std::num::ParseIntError;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Serialize_repr, Deserialize_repr, Copy, Ord, PartialOrd, Eq, PartialEq, Debug, Clone)]
|
||||
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)]
|
||||
struct GatewayEvent {
|
||||
#[serde(rename = "op")]
|
||||
opcode: GatewayOpcode,
|
||||
#[serde(rename = "d")]
|
||||
data: String,
|
||||
#[serde(rename = "s")]
|
||||
sequence_num: Option<u64>,
|
||||
#[serde(rename = "t")]
|
||||
event_name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
struct Identify {
|
||||
token: String,
|
||||
properties: IdentifyProperties,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
struct IdentifyProperties {
|
||||
#[serde(rename = "$os")]
|
||||
os: String,
|
||||
#[serde(rename = "$browser")]
|
||||
browser: String,
|
||||
#[serde(rename = "$device")]
|
||||
device: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
struct Ready {
|
||||
#[serde(rename = "v")]
|
||||
protocol_version: u32,
|
||||
user: (),
|
||||
private_channels: Vec<()>,
|
||||
guilds: Vec<UnavailableGuild>,
|
||||
session_id: String,
|
||||
shared: Option<(u32, u32)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
struct UnavailableGuild {
|
||||
id: Snowflake,
|
||||
available: bool,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(try_from = "String", into = "String")]
|
||||
struct Snowflake(u64);
|
||||
|
||||
impl Into<String> for Snowflake {
|
||||
fn into(self) -> String {
|
||||
self.0.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl TryFrom<String> for Snowflake {
|
||||
type Error = ParseIntError;
|
||||
|
||||
fn try_from(from: String) -> Result<Snowflake, ParseIntError> {
|
||||
Ok(Snowflake(u64::from_str(&from)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::discord::dto::{Snowflake, GatewayOpcode};
|
||||
|
||||
#[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())
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
mod ws;
|
||||
mod dto;
|
@ -0,0 +1,20 @@
|
||||
use async_std::sync::{Sender, Receiver, channel};
|
||||
use async_std::task;
|
||||
use tungstenite::WebSocket;
|
||||
|
||||
enum DiscordEvent {
|
||||
|
||||
}
|
||||
|
||||
struct DiscordReceiver(Receiver<DiscordEvent>);
|
||||
|
||||
struct DiscordSocket(Sender<DiscordEvent>);
|
||||
|
||||
|
||||
fn connect_discord_ws() -> (DiscordSocket, DiscordReceiver) {
|
||||
let (s,r) = channel(10);
|
||||
let receiver = DiscordReceiver(r);
|
||||
let socket = DiscordSocket(s);
|
||||
|
||||
(socket, receiver)
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
const DISCORD_TOKEN: &str = "[CENSORED]";
|
||||
|
||||
mod discord;
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
|
||||
}
|
Loading…
Reference in New Issue