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