This commit is contained in:
kozabrada123 2023-10-14 08:19:35 +02:00
commit 3fc0a7dd37
53 changed files with 583 additions and 244 deletions

View File

@ -2,7 +2,7 @@ name: Build and Test
on: on:
push: push:
branches: [ "main" ] branches: [ "main", "dev" ]
pull_request: pull_request:
branches: [ "main" ] branches: [ "main" ]

View File

@ -11,7 +11,7 @@ name: rust-clippy analyze
on: on:
push: push:
branches: [ "main", "preserve/*" ] branches: [ "main", "preserve/*", "dev" ]
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [ "main" ] branches: [ "main" ]

129
Cargo.lock generated
View File

@ -31,9 +31,9 @@ dependencies = [
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "1.0.4" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -67,7 +67,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
] ]
[[package]] [[package]]
@ -177,7 +177,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "chorus" name = "chorus"
version = "0.4.0" version = "0.9.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"base64 0.21.3", "base64 0.21.3",
@ -211,18 +211,20 @@ dependencies = [
[[package]] [[package]]
name = "chorus-macros" name = "chorus-macros"
version = "0.1.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a81545a60b926f815517dadbbd40cd502294ae2baea25fa8194d854d607512b0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
] ]
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.26" version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f"
dependencies = [ dependencies = [
"android-tzdata", "android-tzdata",
"iana-time-zone", "iana-time-zone",
@ -231,7 +233,7 @@ dependencies = [
"serde", "serde",
"time 0.1.45", "time 0.1.45",
"wasm-bindgen", "wasm-bindgen",
"winapi", "windows-targets",
] ]
[[package]] [[package]]
@ -345,7 +347,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim", "strsim",
"syn 2.0.29", "syn 2.0.31",
] ]
[[package]] [[package]]
@ -356,7 +358,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
] ]
[[package]] [[package]]
@ -439,9 +441,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.2" version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
dependencies = [ dependencies = [
"errno-dragonfly", "errno-dragonfly",
"libc", "libc",
@ -581,7 +583,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
] ]
[[package]] [[package]]
@ -686,21 +688,20 @@ dependencies = [
[[package]] [[package]]
name = "hashlink" name = "hashlink"
version = "0.8.3" version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "312f66718a2d7789ffef4f4b7b213138ed9f1eb3aa1d0d82fc99f88fb3ffd26f" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7"
dependencies = [ dependencies = [
"hashbrown 0.14.0", "hashbrown 0.14.0",
] ]
[[package]] [[package]]
name = "headers" name = "headers"
version = "0.3.8" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270"
dependencies = [ dependencies = [
"base64 0.13.1", "base64 0.21.3",
"bitflags 1.3.2",
"bytes", "bytes",
"headers-core", "headers-core",
"http", "http",
@ -1033,9 +1034,9 @@ dependencies = [
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.5.0" version = "2.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
[[package]] [[package]]
name = "mime" name = "mime"
@ -1184,9 +1185,9 @@ dependencies = [
[[package]] [[package]]
name = "object" name = "object"
version = "0.32.0" version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -1199,11 +1200,11 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.56" version = "0.10.57"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "729b745ad4a5575dd06a3e1af1414bd330ee561c01b3899eb584baeaa8def17e" checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.0",
"cfg-if", "cfg-if",
"foreign-types", "foreign-types",
"libc", "libc",
@ -1220,7 +1221,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
] ]
[[package]] [[package]]
@ -1231,9 +1232,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.91" version = "0.9.92"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac" checksum = "db7e971c2c2bba161b2d2fdf37080177eff520b3bc044787c7f1f5f9e78d869b"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -1311,7 +1312,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
] ]
[[package]] [[package]]
@ -1355,9 +1356,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]] [[package]]
name = "poem" name = "poem"
version = "1.3.57" version = "1.3.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0d92c532a37a9e98c0e9a0411e6852b8acccf9ec07d5e6e450b01cbf947d90b" checksum = "ebc7ae19f3e791ae8108b08801abb3708d64d3a16490c720e0b81040cae87b5d"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"bytes", "bytes",
@ -1384,14 +1385,14 @@ dependencies = [
[[package]] [[package]]
name = "poem-derive" name = "poem-derive"
version = "1.3.57" version = "1.3.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5dd58846a1f582215370384c3090c62c9ef188e9d798ffc67ea90d0a1a8a3b8" checksum = "2550a0bce7273b278894ef3ccc5a6869e7031b6870042f3cc6826ed9faa980a6"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
] ]
[[package]] [[package]]
@ -1469,9 +1470,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.9.4" version = "1.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -1481,9 +1482,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.3.7" version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -1588,9 +1589,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.9" version = "0.38.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453"
dependencies = [ dependencies = [
"bitflags 2.4.0", "bitflags 2.4.0",
"errno", "errno",
@ -1683,7 +1684,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
] ]
[[package]] [[package]]
@ -1705,7 +1706,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
] ]
[[package]] [[package]]
@ -1734,7 +1735,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"serde_with_macros", "serde_with_macros",
"time 0.3.27", "time 0.3.28",
] ]
[[package]] [[package]]
@ -1746,7 +1747,7 @@ dependencies = [
"darling", "darling",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
] ]
[[package]] [[package]]
@ -1799,7 +1800,7 @@ dependencies = [
"num-bigint", "num-bigint",
"num-traits", "num-traits",
"thiserror", "thiserror",
"time 0.3.27", "time 0.3.28",
] ]
[[package]] [[package]]
@ -2110,9 +2111,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.29" version = "2.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2134,22 +2135,22 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.47" version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.47" version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
] ]
[[package]] [[package]]
@ -2165,9 +2166,9 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.27" version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bb39ee79a6d8de55f48f2293a830e040392f1c5f16e336bdd1788cd0aadce07" checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48"
dependencies = [ dependencies = [
"deranged", "deranged",
"itoa", "itoa",
@ -2184,9 +2185,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
[[package]] [[package]]
name = "time-macros" name = "time-macros"
version = "0.2.13" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "733d258752e9303d392b94b75230d07b0b9c489350c69b851fc6c065fde3e8f9" checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572"
dependencies = [ dependencies = [
"time-core", "time-core",
] ]
@ -2233,7 +2234,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
] ]
[[package]] [[package]]
@ -2338,7 +2339,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
] ]
[[package]] [[package]]
@ -2447,9 +2448,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]] [[package]]
name = "url" name = "url"
version = "2.4.0" version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
dependencies = [ dependencies = [
"form_urlencoded", "form_urlencoded",
"idna", "idna",
@ -2516,7 +2517,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -2550,7 +2551,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.29", "syn 2.0.31",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]

View File

@ -1,7 +1,7 @@
[package] [package]
name = "chorus" name = "chorus"
description = "A library for interacting with multiple Spacebar-compatible Instances at once." description = "A library for interacting with multiple Spacebar-compatible Instances at once."
version = "0.4.0" version = "0.9.0"
license = "AGPL-3.0" license = "AGPL-3.0"
edition = "2021" edition = "2021"
repository = "https://github.com/polyphony-chat/chorus" repository = "https://github.com/polyphony-chat/chorus"
@ -50,7 +50,7 @@ thiserror = "1.0.47"
jsonwebtoken = "8.3.0" jsonwebtoken = "8.3.0"
log = "0.4.20" log = "0.4.20"
async-trait = "0.1.73" async-trait = "0.1.73"
chorus-macros = { path = "chorus-macros", version = "0.1.0" } chorus-macros = "0.2.0"
[dev-dependencies] [dev-dependencies]
tokio = { version = "1.32.0", features = ["full"] } tokio = { version = "1.32.0", features = ["full"] }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "chorus-macros" name = "chorus-macros"
version = "0.1.0" version = "0.2.0"
edition = "2021" edition = "2021"
license = "AGPL-3.0" license = "AGPL-3.0"
description = "Macros for the chorus crate." description = "Macros for the chorus crate."

View File

@ -37,6 +37,25 @@ pub fn jsonfield_macro_derive(input: TokenStream) -> TokenStream {
.into() .into()
} }
#[proc_macro_derive(SourceUrlField)]
pub fn source_url_macro_derive(input: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(input).unwrap();
let name = &ast.ident;
// No need for macro hygiene, we're only using this in chorus
quote! {
impl SourceUrlField for #name {
fn get_source_url(&self) -> String {
self.source_url.clone()
}
fn set_source_url(&mut self, url: String) {
self.source_url = url;
}
}
}
.into()
}
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn observe_option(_args: TokenStream, input: TokenStream) -> TokenStream { pub fn observe_option(_args: TokenStream, input: TokenStream) -> TokenStream {
input input

View File

@ -3,24 +3,23 @@ use std::sync::{Arc, RwLock};
use reqwest::Client; use reqwest::Client;
use serde_json::to_string; use serde_json::to_string;
use crate::api::LimitType;
use crate::errors::ChorusResult; use crate::errors::ChorusResult;
use crate::gateway::Gateway; use crate::gateway::Gateway;
use crate::instance::{ChorusUser, Instance}; use crate::instance::{ChorusUser, Instance};
use crate::ratelimiter::ChorusRequest; use crate::ratelimiter::ChorusRequest;
use crate::types::{GatewayIdentifyPayload, LoginResult, LoginSchema}; use crate::types::{GatewayIdentifyPayload, LimitType, LoginResult, LoginSchema};
impl Instance { impl Instance {
/// Logs into an existing account on the spacebar server. /// Logs into an existing account on the spacebar server.
/// ///
/// # Reference /// # Reference
/// See <https://docs.spacebar.chat/routes/#post-/auth/login/> /// See <https://docs.spacebar.chat/routes/#post-/auth/login/>
pub async fn login_account(&mut self, login_schema: &LoginSchema) -> ChorusResult<ChorusUser> { pub async fn login_account(mut self, login_schema: LoginSchema) -> ChorusResult<ChorusUser> {
let endpoint_url = self.urls.api.clone() + "/auth/login"; let endpoint_url = self.urls.api.clone() + "/auth/login";
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request: Client::new() request: Client::new()
.post(endpoint_url) .post(endpoint_url)
.body(to_string(login_schema).unwrap()) .body(to_string(&login_schema).unwrap())
.header("Content-Type", "application/json"), .header("Content-Type", "application/json"),
limit_type: LimitType::AuthLogin, limit_type: LimitType::AuthLogin,
}; };
@ -46,7 +45,7 @@ impl Instance {
self.clone_limits_if_some(), self.clone_limits_if_some(),
login_result.settings, login_result.settings,
Arc::new(RwLock::new(object)), Arc::new(RwLock::new(object)),
Arc::new(gateway), gateway,
); );
Ok(user) Ok(user)
} }

View File

@ -1,5 +1,41 @@
use std::sync::{Arc, RwLock};
pub use login::*; pub use login::*;
pub use register::*; pub use register::*;
use crate::{
errors::ChorusResult,
gateway::Gateway,
instance::{ChorusUser, Instance},
types::{GatewayIdentifyPayload, User},
};
pub mod login; pub mod login;
pub mod register; pub mod register;
impl Instance {
/// Logs into an existing account on the spacebar server, using only a token.
pub async fn login_with_token(&mut self, token: String) -> ChorusResult<ChorusUser> {
let object_result = self.get_user(token.clone(), None).await;
if let Err(e) = object_result {
return Result::Err(e);
}
let user_settings = User::get_settings(&token, &self.urls.api, &mut self.clone())
.await
.unwrap();
let mut identify = GatewayIdentifyPayload::common();
let gateway = Gateway::new(self.urls.wss.clone()).await.unwrap();
identify.token = token.clone();
gateway.send_identify(identify).await;
let user = ChorusUser::new(
Arc::new(RwLock::new(self.clone())),
token.clone(),
self.clone_limits_if_some(),
Arc::new(RwLock::new(user_settings)),
Arc::new(RwLock::new(object_result.unwrap())),
gateway,
);
Ok(user)
}
}

View File

@ -6,10 +6,10 @@ use serde_json::to_string;
use crate::gateway::Gateway; use crate::gateway::Gateway;
use crate::types::GatewayIdentifyPayload; use crate::types::GatewayIdentifyPayload;
use crate::{ use crate::{
api::policies::instance::LimitType,
errors::ChorusResult, errors::ChorusResult,
instance::{ChorusUser, Instance, Token}, instance::{ChorusUser, Instance, Token},
ratelimiter::ChorusRequest, ratelimiter::ChorusRequest,
types::LimitType,
types::RegisterSchema, types::RegisterSchema,
}; };
@ -19,14 +19,14 @@ impl Instance {
/// # Reference /// # Reference
/// See <https://docs.spacebar.chat/routes/#post-/auth/register/> /// See <https://docs.spacebar.chat/routes/#post-/auth/register/>
pub async fn register_account( pub async fn register_account(
&mut self, mut self,
register_schema: &RegisterSchema, register_schema: RegisterSchema,
) -> ChorusResult<ChorusUser> { ) -> ChorusResult<ChorusUser> {
let endpoint_url = self.urls.api.clone() + "/auth/register"; let endpoint_url = self.urls.api.clone() + "/auth/register";
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request: Client::new() request: Client::new()
.post(endpoint_url) .post(endpoint_url)
.body(to_string(register_schema).unwrap()) .body(to_string(&register_schema).unwrap())
.header("Content-Type", "application/json"), .header("Content-Type", "application/json"),
limit_type: LimitType::AuthRegister, limit_type: LimitType::AuthRegister,
}; };
@ -43,7 +43,7 @@ impl Instance {
self.limits_information.as_mut().unwrap().ratelimits = shell.limits.unwrap(); self.limits_information.as_mut().unwrap().ratelimits = shell.limits.unwrap();
} }
let user_object = self.get_user(token.clone(), None).await.unwrap(); let user_object = self.get_user(token.clone(), None).await.unwrap();
let settings = ChorusUser::get_settings(&token, &self.urls.api.clone(), self).await?; let settings = ChorusUser::get_settings(&token, &self.urls.api.clone(), &mut self).await?;
let mut identify = GatewayIdentifyPayload::common(); let mut identify = GatewayIdentifyPayload::common();
let gateway = Gateway::new(self.urls.wss.clone()).await.unwrap(); let gateway = Gateway::new(self.urls.wss.clone()).await.unwrap();
identify.token = token.clone(); identify.token = token.clone();
@ -54,7 +54,7 @@ impl Instance {
self.clone_limits_if_some(), self.clone_limits_if_some(),
Arc::new(RwLock::new(settings)), Arc::new(RwLock::new(settings)),
Arc::new(RwLock::new(user_object)), Arc::new(RwLock::new(user_object)),
Arc::new(gateway), gateway,
); );
Ok(user) Ok(user)
} }

View File

@ -3,11 +3,12 @@ use serde_json::to_string;
use crate::types::{AddChannelRecipientSchema, ModifyChannelPositionsSchema}; use crate::types::{AddChannelRecipientSchema, ModifyChannelPositionsSchema};
use crate::{ use crate::{
api::LimitType,
errors::{ChorusError, ChorusResult}, errors::{ChorusError, ChorusResult},
instance::ChorusUser, instance::ChorusUser,
ratelimiter::ChorusRequest, ratelimiter::ChorusRequest,
types::{Channel, ChannelModifySchema, GetChannelMessagesSchema, Message, Snowflake}, types::{
Channel, ChannelModifySchema, GetChannelMessagesSchema, LimitType, Message, Snowflake,
},
}; };
impl Channel { impl Channel {

View File

@ -3,13 +3,12 @@ use http::HeaderMap;
use reqwest::{multipart, Client}; use reqwest::{multipart, Client};
use serde_json::{from_value, to_string, Value}; use serde_json::{from_value, to_string, Value};
use crate::api::LimitType;
use crate::errors::{ChorusError, ChorusResult}; use crate::errors::{ChorusError, ChorusResult};
use crate::instance::ChorusUser; use crate::instance::ChorusUser;
use crate::ratelimiter::ChorusRequest; use crate::ratelimiter::ChorusRequest;
use crate::types::{ use crate::types::{
Channel, CreateGreetMessage, Message, MessageAck, MessageModifySchema, MessageSearchEndpoint, Channel, CreateGreetMessage, LimitType, Message, MessageAck, MessageModifySchema,
MessageSearchQuery, MessageSendSchema, Snowflake, MessageSearchEndpoint, MessageSearchQuery, MessageSendSchema, Snowflake,
}; };
impl Message { impl Message {

View File

@ -2,11 +2,10 @@ use reqwest::Client;
use serde_json::to_string; use serde_json::to_string;
use crate::{ use crate::{
api::LimitType,
errors::{ChorusError, ChorusResult}, errors::{ChorusError, ChorusResult},
instance::ChorusUser, instance::ChorusUser,
ratelimiter::ChorusRequest, ratelimiter::ChorusRequest,
types::{self, PermissionOverwrite, Snowflake}, types::{self, LimitType, PermissionOverwrite, Snowflake},
}; };
impl types::Channel { impl types::Channel {

View File

@ -1,9 +1,8 @@
use crate::{ use crate::{
api::LimitType,
errors::ChorusResult, errors::ChorusResult,
instance::ChorusUser, instance::ChorusUser,
ratelimiter::ChorusRequest, ratelimiter::ChorusRequest,
types::{self, PublicUser, Snowflake}, types::{self, LimitType, PublicUser, Snowflake},
}; };
/// Useful metadata for working with [`types::Reaction`], bundled together nicely. /// Useful metadata for working with [`types::Reaction`], bundled together nicely.

View File

@ -2,14 +2,13 @@ use reqwest::Client;
use serde_json::from_str; use serde_json::from_str;
use serde_json::to_string; use serde_json::to_string;
use crate::api::LimitType;
use crate::errors::ChorusError; use crate::errors::ChorusError;
use crate::errors::ChorusResult; use crate::errors::ChorusResult;
use crate::instance::ChorusUser; use crate::instance::ChorusUser;
use crate::ratelimiter::ChorusRequest; use crate::ratelimiter::ChorusRequest;
use crate::types::{ use crate::types::{
Channel, ChannelCreateSchema, Guild, GuildBanCreateSchema, GuildBansQuery, GuildCreateSchema, Channel, ChannelCreateSchema, Guild, GuildBanCreateSchema, GuildBansQuery, GuildCreateSchema,
GuildMember, GuildMemberSearchSchema, GuildModifySchema, GuildPreview, GuildMember, GuildMemberSearchSchema, GuildModifySchema, GuildPreview, LimitType,
ModifyGuildMemberProfileSchema, ModifyGuildMemberSchema, UserProfileMetadata, ModifyGuildMemberProfileSchema, ModifyGuildMemberSchema, UserProfileMetadata,
}; };
use crate::types::{GuildBan, Snowflake}; use crate::types::{GuildBan, Snowflake};

View File

@ -1,11 +1,10 @@
use reqwest::Client; use reqwest::Client;
use crate::{ use crate::{
api::LimitType,
errors::ChorusResult, errors::ChorusResult,
instance::ChorusUser, instance::ChorusUser,
ratelimiter::ChorusRequest, ratelimiter::ChorusRequest,
types::{self, GuildMember, Snowflake}, types::{self, GuildMember, LimitType, Snowflake},
}; };
impl types::GuildMember { impl types::GuildMember {

View File

@ -2,11 +2,12 @@ use reqwest::Client;
use serde_json::to_string; use serde_json::to_string;
use crate::{ use crate::{
api::LimitType,
errors::{ChorusError, ChorusResult}, errors::{ChorusError, ChorusResult},
instance::ChorusUser, instance::ChorusUser,
ratelimiter::ChorusRequest, ratelimiter::ChorusRequest,
types::{self, RoleCreateModifySchema, RoleObject, RolePositionUpdateSchema, Snowflake}, types::{
self, LimitType, RoleCreateModifySchema, RoleObject, RolePositionUpdateSchema, Snowflake,
},
}; };
impl types::RoleObject { impl types::RoleObject {

View File

@ -4,7 +4,7 @@ use serde_json::to_string;
use crate::errors::ChorusResult; use crate::errors::ChorusResult;
use crate::instance::ChorusUser; use crate::instance::ChorusUser;
use crate::ratelimiter::ChorusRequest; use crate::ratelimiter::ChorusRequest;
use crate::types::{CreateChannelInviteSchema, GuildInvite, Invite, Snowflake}; use crate::types::{CreateChannelInviteSchema, GuildInvite, Invite, LimitType, Snowflake};
impl ChorusUser { impl ChorusUser {
/// Accepts an invite to a guild, group DM, or DM. /// Accepts an invite to a guild, group DM, or DM.
@ -26,7 +26,7 @@ impl ChorusUser {
invite_code invite_code
)) ))
.header("Authorization", self.token()), .header("Authorization", self.token()),
limit_type: super::LimitType::Global, limit_type: LimitType::Global,
}; };
if session_id.is_some() { if session_id.is_some() {
request.request = request request.request = request
@ -53,7 +53,7 @@ impl ChorusUser {
.body(to_string(&code).unwrap()) .body(to_string(&code).unwrap())
.header("Authorization", self.token()) .header("Authorization", self.token())
.header("Content-Type", "application/json"), .header("Content-Type", "application/json"),
limit_type: super::LimitType::Global, limit_type: LimitType::Global,
} }
.deserialize_response::<Invite>(self) .deserialize_response::<Invite>(self)
.await .await
@ -81,7 +81,7 @@ impl ChorusUser {
.header("Authorization", self.token()) .header("Authorization", self.token())
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.body(to_string(&create_channel_invite_schema).unwrap()), .body(to_string(&create_channel_invite_schema).unwrap()),
limit_type: super::LimitType::Channel(channel_id), limit_type: LimitType::Channel(channel_id),
} }
.deserialize_response::<GuildInvite>(self) .deserialize_response::<GuildInvite>(self)
.await .await

View File

@ -3,7 +3,6 @@ pub use channels::messages::*;
pub use guilds::*; pub use guilds::*;
pub use invites::*; pub use invites::*;
pub use policies::instance::instance::*; pub use policies::instance::instance::*;
pub use policies::instance::ratelimits::*;
pub use users::*; pub use users::*;
pub mod auth; pub mod auth;

View File

@ -19,7 +19,7 @@ impl Instance {
Err(e) => { Err(e) => {
return Err(ChorusError::RequestFailed { return Err(ChorusError::RequestFailed {
url: endpoint_url, url: endpoint_url,
error: e, error: e.to_string(),
}); });
} }
}; };

View File

@ -1,5 +1,3 @@
pub use instance::*; pub use instance::*;
pub use ratelimits::*;
pub mod instance; pub mod instance;
pub mod ratelimits;

View File

@ -1,3 +1 @@
pub use instance::ratelimits::*;
pub mod instance; pub mod instance;

View File

@ -2,11 +2,10 @@ use reqwest::Client;
use serde_json::to_string; use serde_json::to_string;
use crate::{ use crate::{
api::LimitType,
errors::ChorusResult, errors::ChorusResult,
instance::ChorusUser, instance::ChorusUser,
ratelimiter::ChorusRequest, ratelimiter::ChorusRequest,
types::{Channel, PrivateChannelCreateSchema}, types::{Channel, LimitType, PrivateChannelCreateSchema},
}; };
impl ChorusUser { impl ChorusUser {

View File

@ -1,11 +1,10 @@
use reqwest::Client; use reqwest::Client;
use serde_json::to_string; use serde_json::to_string;
use crate::api::LimitType;
use crate::errors::ChorusResult; use crate::errors::ChorusResult;
use crate::instance::ChorusUser; use crate::instance::ChorusUser;
use crate::ratelimiter::ChorusRequest; use crate::ratelimiter::ChorusRequest;
use crate::types::{GetUserGuildSchema, Guild, Snowflake}; use crate::types::{GetUserGuildSchema, Guild, LimitType, Snowflake};
impl ChorusUser { impl ChorusUser {
/// Leaves a given guild. /// Leaves a given guild.
@ -26,7 +25,7 @@ impl ChorusUser {
.header("Authorization", self.token()) .header("Authorization", self.token())
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.body(to_string(&lurking).unwrap()), .body(to_string(&lurking).unwrap()),
limit_type: crate::api::LimitType::Guild(*guild_id), limit_type: LimitType::Guild(*guild_id),
} }
.handle_request_as_result(self) .handle_request_as_result(self)
.await .await

View File

@ -2,12 +2,12 @@ use reqwest::Client;
use serde_json::to_string; use serde_json::to_string;
use crate::{ use crate::{
api::LimitType,
errors::ChorusResult, errors::ChorusResult,
instance::ChorusUser, instance::ChorusUser,
ratelimiter::ChorusRequest, ratelimiter::ChorusRequest,
types::{ types::{
self, CreateUserRelationshipSchema, FriendRequestSendSchema, RelationshipType, Snowflake, self, CreateUserRelationshipSchema, FriendRequestSendSchema, LimitType, RelationshipType,
Snowflake,
}, },
}; };

View File

@ -4,11 +4,10 @@ use reqwest::Client;
use serde_json::to_string; use serde_json::to_string;
use crate::{ use crate::{
api::LimitType,
errors::{ChorusError, ChorusResult}, errors::{ChorusError, ChorusResult},
instance::{ChorusUser, Instance}, instance::{ChorusUser, Instance},
ratelimiter::ChorusRequest, ratelimiter::ChorusRequest,
types::{User, UserModifySchema, UserSettings}, types::{LimitType, User, UserModifySchema, UserSettings},
}; };
impl ChorusUser { impl ChorusUser {

View File

@ -1,11 +1,10 @@
//! Contains all the errors that can be returned by the library. //! Contains all the errors that can be returned by the library.
use custom_error::custom_error; use custom_error::custom_error;
use reqwest::Error;
use crate::types::WebSocketEvent; use crate::types::WebSocketEvent;
custom_error! { custom_error! {
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq, Clone, Hash)]
pub RegistrationError pub RegistrationError
Consent = "Consent must be 'true' to register.", Consent = "Consent must be 'true' to register.",
} }
@ -13,11 +12,12 @@ custom_error! {
pub type ChorusResult<T> = std::result::Result<T, ChorusError>; pub type ChorusResult<T> = std::result::Result<T, ChorusError>;
custom_error! { custom_error! {
#[derive(Clone, Hash, PartialEq, Eq)]
pub ChorusError pub ChorusError
/// Server did not respond. /// Server did not respond.
NoResponse = "Did not receive a response from the Server.", NoResponse = "Did not receive a response from the Server.",
/// Reqwest returned an Error instead of a Response object. /// Reqwest returned an Error instead of a Response object.
RequestFailed{url:String, error: Error} = "An error occured while trying to GET from {url}: {error}", RequestFailed{url:String, error: String} = "An error occured while trying to GET from {url}: {error}",
/// Response received, however, it was not of the successful responses type. Used when no other, special case applies. /// Response received, however, it was not of the successful responses type. Used when no other, special case applies.
ReceivedErrorCode{error_code: u16, error: String} = "Received the following error code while requesting from the route: {error_code}", ReceivedErrorCode{error_code: u16, error: String} = "Received the following error code while requesting from the route: {error_code}",
/// Used when there is likely something wrong with the instance, the request was directed to. /// Used when there is likely something wrong with the instance, the request was directed to.

View File

@ -5,7 +5,7 @@ use crate::gateway::events::Events;
use crate::types::{ use crate::types::{
self, AutoModerationRule, AutoModerationRuleUpdate, Channel, ChannelCreate, ChannelDelete, self, AutoModerationRule, AutoModerationRuleUpdate, Channel, ChannelCreate, ChannelDelete,
ChannelUpdate, Composite, Guild, GuildRoleCreate, GuildRoleUpdate, JsonField, RoleObject, ChannelUpdate, Composite, Guild, GuildRoleCreate, GuildRoleUpdate, JsonField, RoleObject,
Snowflake, ThreadUpdate, UpdateMessage, WebSocketEvent, Snowflake, SourceUrlField, ThreadUpdate, UpdateMessage, WebSocketEvent,
}; };
use async_trait::async_trait; use async_trait::async_trait;
use std::any::Any; use std::any::Any;
@ -158,7 +158,7 @@ pub type ObservableObject = dyn Send + Sync + Any;
/// [`GatewayEvents`](GatewayEvent), which you can subscribe to. Gateway events include all currently /// [`GatewayEvents`](GatewayEvent), which you can subscribe to. Gateway events include all currently
/// implemented types with the trait [`WebSocketEvent`] /// implemented types with the trait [`WebSocketEvent`]
/// Using this handle you can also send Gateway Events directly. /// Using this handle you can also send Gateway Events directly.
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct GatewayHandle { pub struct GatewayHandle {
pub url: String, pub url: String,
pub events: Arc<Mutex<Events>>, pub events: Arc<Mutex<Events>>,
@ -170,7 +170,6 @@ pub struct GatewayHandle {
>, >,
>, >,
>, >,
pub handle: JoinHandle<()>,
/// Tells gateway tasks to close /// Tells gateway tasks to close
kill_send: tokio::sync::broadcast::Sender<()>, kill_send: tokio::sync::broadcast::Sender<()>,
pub(crate) store: Arc<Mutex<HashMap<Snowflake, Arc<RwLock<ObservableObject>>>>>, pub(crate) store: Arc<Mutex<HashMap<Snowflake, Arc<RwLock<ObservableObject>>>>>,
@ -293,7 +292,7 @@ impl GatewayHandle {
/// Sends an update voice state to the server /// Sends an update voice state to the server
pub async fn send_update_voice_state(&self, to_send: types::UpdateVoiceState) { pub async fn send_update_voice_state(&self, to_send: types::UpdateVoiceState) {
let to_send_value = serde_json::to_value(&to_send).unwrap(); let to_send_value = serde_json::to_value(to_send).unwrap();
trace!("GW: Sending Update Voice State.."); trace!("GW: Sending Update Voice State..");
@ -344,6 +343,7 @@ pub struct Gateway {
websocket_receive: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>, websocket_receive: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>,
kill_send: tokio::sync::broadcast::Sender<()>, kill_send: tokio::sync::broadcast::Sender<()>,
store: Arc<Mutex<HashMap<Snowflake, Arc<RwLock<ObservableObject>>>>>, store: Arc<Mutex<HashMap<Snowflake, Arc<RwLock<ObservableObject>>>>>,
url: String,
} }
impl Gateway { impl Gateway {
@ -407,10 +407,11 @@ impl Gateway {
websocket_receive, websocket_receive,
kill_send: kill_send.clone(), kill_send: kill_send.clone(),
store: store.clone(), store: store.clone(),
url: websocket_url.clone(),
}; };
// Now we can continuously check for messages in a different task, since we aren't going to receive another hello // Now we can continuously check for messages in a different task, since we aren't going to receive another hello
let handle: JoinHandle<()> = task::spawn(async move { task::spawn(async move {
gateway.gateway_listen_task().await; gateway.gateway_listen_task().await;
}); });
@ -418,7 +419,6 @@ impl Gateway {
url: websocket_url.clone(), url: websocket_url.clone(),
events: shared_events, events: shared_events,
websocket_send: shared_websocket_send.clone(), websocket_send: shared_websocket_send.clone(),
handle,
kill_send: kill_send.clone(), kill_send: kill_send.clone(),
store, store,
}) })
@ -501,7 +501,7 @@ impl Gateway {
GATEWAY_DISPATCH => { GATEWAY_DISPATCH => {
let Some(event_name) = gateway_payload.event_name else { let Some(event_name) = gateway_payload.event_name else {
warn!("Gateway dispatch op without event_name"); warn!("Gateway dispatch op without event_name");
return return;
}; };
trace!("Gateway: Received {event_name}"); trace!("Gateway: Received {event_name}");
@ -536,6 +536,7 @@ impl Gateway {
let downcasted = unsafe { Arc::from_raw(ptr as *const RwLock<$update_type>).clone() }; let downcasted = unsafe { Arc::from_raw(ptr as *const RwLock<$update_type>).clone() };
drop(inner_object); drop(inner_object);
message.set_json(json.to_string()); message.set_json(json.to_string());
message.set_source_url(self.url.clone());
message.update(downcasted.clone()); message.update(downcasted.clone());
} else { } else {
warn!("Received {} for {}, but it has been observed to be a different type!", $name, id) warn!("Received {} for {}, but it has been observed to be a different type!", $name, id)
@ -916,7 +917,7 @@ impl<T: WebSocketEvent> GatewayEvent<T> {
} }
} }
mod events { pub mod events {
use super::*; use super::*;
#[derive(Default, Debug)] #[derive(Default, Debug)]

View File

@ -8,15 +8,14 @@ use std::sync::{Arc, RwLock};
use reqwest::Client; use reqwest::Client;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::api::{Limit, LimitType};
use crate::errors::ChorusResult; use crate::errors::ChorusResult;
use crate::gateway::{Gateway, GatewayHandle}; use crate::gateway::{Gateway, GatewayHandle};
use crate::ratelimiter::ChorusRequest; use crate::ratelimiter::ChorusRequest;
use crate::types::types::subconfigs::limits::rates::RateLimits; use crate::types::types::subconfigs::limits::rates::RateLimits;
use crate::types::{GeneralConfiguration, User, UserSettings}; use crate::types::{GeneralConfiguration, Limit, LimitType, User, UserSettings};
use crate::UrlBundle; use crate::UrlBundle;
#[derive(Debug, Clone)] #[derive(Debug, Clone, Default)]
/// The [`Instance`]; what you will be using to perform all sorts of actions on the Spacebar server. /// The [`Instance`]; what you will be using to perform all sorts of actions on the Spacebar server.
/// If `limits_information` is `None`, then the instance will not be rate limited. /// If `limits_information` is `None`, then the instance will not be rate limited.
pub struct Instance { pub struct Instance {
@ -26,7 +25,7 @@ pub struct Instance {
pub client: Client, pub client: Client,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct LimitsInformation { pub struct LimitsInformation {
pub ratelimits: HashMap<LimitType, Limit>, pub ratelimits: HashMap<LimitType, Limit>,
pub configuration: RateLimits, pub configuration: RateLimits,
@ -94,7 +93,7 @@ pub struct ChorusUser {
pub limits: Option<HashMap<LimitType, Limit>>, pub limits: Option<HashMap<LimitType, Limit>>,
pub settings: Arc<RwLock<UserSettings>>, pub settings: Arc<RwLock<UserSettings>>,
pub object: Arc<RwLock<User>>, pub object: Arc<RwLock<User>>,
pub gateway: Arc<GatewayHandle>, // TODO: Can this be an Arc<GatewayHandle>? That way we could have Clone implemented on ChorusUser pub gateway: GatewayHandle,
} }
impl ChorusUser { impl ChorusUser {
@ -117,7 +116,7 @@ impl ChorusUser {
limits: Option<HashMap<LimitType, Limit>>, limits: Option<HashMap<LimitType, Limit>>,
settings: Arc<RwLock<UserSettings>>, settings: Arc<RwLock<UserSettings>>,
object: Arc<RwLock<User>>, object: Arc<RwLock<User>>,
gateway: Arc<GatewayHandle>, gateway: GatewayHandle,
) -> ChorusUser { ) -> ChorusUser {
ChorusUser { ChorusUser {
belongs_to, belongs_to,
@ -139,7 +138,7 @@ impl ChorusUser {
let object = Arc::new(RwLock::new(User::default())); let object = Arc::new(RwLock::new(User::default()));
let wss_url = instance.read().unwrap().urls.wss.clone(); let wss_url = instance.read().unwrap().urls.wss.clone();
// Dummy gateway object // Dummy gateway object
let gateway = Arc::new(Gateway::new(wss_url).await.unwrap()); let gateway = Gateway::new(wss_url).await.unwrap();
ChorusUser { ChorusUser {
token, token,
belongs_to: instance.clone(), belongs_to: instance.clone(),

View File

@ -30,7 +30,7 @@ pub mod types;
#[cfg(feature = "client")] #[cfg(feature = "client")]
pub mod voice; pub mod voice;
#[derive(Clone, Default, Debug, PartialEq, Eq)] #[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
/// A URLBundle bundles together the API-, Gateway- and CDN-URLs of a Spacebar instance. /// A URLBundle bundles together the API-, Gateway- and CDN-URLs of a Spacebar instance.
/// ///
/// # Notes /// # Notes

View File

@ -8,10 +8,9 @@ use serde::Deserialize;
use serde_json::from_str; use serde_json::from_str;
use crate::{ use crate::{
api::{Limit, LimitType},
errors::{ChorusError, ChorusResult}, errors::{ChorusError, ChorusResult},
instance::ChorusUser, instance::ChorusUser,
types::{types::subconfigs::limits::rates::RateLimits, LimitsConfiguration}, types::{types::subconfigs::limits::rates::RateLimits, Limit, LimitType, LimitsConfiguration},
}; };
/// Chorus' request struct. This struct is used to send rate-limited requests to the Spacebar server. /// Chorus' request struct. This struct is used to send rate-limited requests to the Spacebar server.
@ -92,7 +91,7 @@ impl ChorusRequest {
log::warn!("Request failed: {:?}", error); log::warn!("Request failed: {:?}", error);
return Err(ChorusError::RequestFailed { return Err(ChorusError::RequestFailed {
url: error.url().unwrap().to_string(), url: error.url().unwrap().to_string(),
error, error: error.to_string(),
}); });
} }
}; };
@ -360,7 +359,7 @@ impl ChorusRequest {
Err(e) => { Err(e) => {
return Err(ChorusError::RequestFailed { return Err(ChorusError::RequestFailed {
url: url_api.to_string(), url: url_api.to_string(),
error: e, error: e.to_string(),
}) })
} }
}; };

View File

@ -18,7 +18,7 @@ use crate::types::config::types::subconfigs::guild::{
}; };
use crate::types::{Error, GuildError}; use crate::types::{Error, GuildError};
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Hash)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum GuildFeatures { pub enum GuildFeatures {
ActivitiesAlpha, ActivitiesAlpha,
@ -139,7 +139,7 @@ pub enum GuildFeatures {
InvitesClosed, InvitesClosed,
} }
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, Eq)] #[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, Eq, Hash)]
pub struct GuildFeaturesList(Vec<GuildFeatures>); pub struct GuildFeaturesList(Vec<GuildFeatures>);
impl Deref for GuildFeaturesList { impl Deref for GuildFeaturesList {

View File

@ -2,11 +2,9 @@ use std::collections::HashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::types::{
api::LimitType, config::types::subconfigs::limits::ratelimits::{route::RouteRateLimit, RateLimitOptions},
types::config::types::subconfigs::limits::ratelimits::{ LimitType,
route::RouteRateLimit, RateLimitOptions,
},
}; };
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]

View File

@ -1,13 +1,18 @@
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
#[cfg(feature = "client")]
use crate::gateway::Updateable; use crate::gateway::Updateable;
#[cfg(feature = "client")]
use chorus_macros::Updateable; use chorus_macros::Updateable;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::types::utils::Snowflake; use crate::types::utils::Snowflake;
#[derive(Serialize, Deserialize, Debug, Default, Clone, Updateable)] #[cfg_attr(feature = "client", derive(Updateable))]
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
/// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object> /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object>
pub struct AutoModerationRule { pub struct AutoModerationRule {
pub id: Snowflake, pub id: Snowflake,

View File

@ -1,21 +1,28 @@
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use chorus_macros::{observe_option_vec, Composite, Updateable};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_aux::prelude::deserialize_string_from_number; use serde_aux::prelude::deserialize_string_from_number;
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
use std::fmt::Debug; use std::fmt::Debug;
use crate::gateway::{GatewayHandle, Updateable};
use crate::types::{ use crate::types::{
entities::{GuildMember, User}, entities::{GuildMember, User},
utils::Snowflake, utils::Snowflake,
Composite,
}; };
#[derive(Default, Debug, Serialize, Deserialize, Clone, Updateable, Composite)] #[cfg(feature = "client")]
use crate::types::Composite;
#[cfg(feature = "client")]
use crate::gateway::{GatewayHandle, Updateable};
#[cfg(feature = "client")]
use chorus_macros::{observe_option_vec, Composite, Updateable};
#[derive(Default, Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
#[cfg_attr(feature = "client", derive(Updateable, Composite))]
/// Represents a guild or private channel /// Represents a guild or private channel
/// ///
/// # Reference /// # Reference
@ -60,13 +67,13 @@ pub struct Channel {
#[cfg(feature = "sqlx")] #[cfg(feature = "sqlx")]
pub permission_overwrites: Option<sqlx::types::Json<Vec<PermissionOverwrite>>>, pub permission_overwrites: Option<sqlx::types::Json<Vec<PermissionOverwrite>>>,
#[cfg(not(feature = "sqlx"))] #[cfg(not(feature = "sqlx"))]
#[observe_option_vec] #[cfg_attr(feature = "client", observe_option_vec)]
pub permission_overwrites: Option<Vec<Arc<RwLock<PermissionOverwrite>>>>, pub permission_overwrites: Option<Vec<Arc<RwLock<PermissionOverwrite>>>>,
pub permissions: Option<String>, pub permissions: Option<String>,
pub position: Option<i32>, pub position: Option<i32>,
pub rate_limit_per_user: Option<i32>, pub rate_limit_per_user: Option<i32>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
#[observe_option_vec] #[cfg_attr(feature = "client", observe_option_vec)]
pub recipients: Option<Vec<Arc<RwLock<User>>>>, pub recipients: Option<Vec<Arc<RwLock<User>>>>,
pub rtc_region: Option<String>, pub rtc_region: Option<String>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
@ -126,9 +133,8 @@ pub struct Tag {
pub emoji_name: Option<String>, pub emoji_name: Option<String>,
} }
#[derive( #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd)]
Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Updateable, Composite, #[cfg_attr(feature = "client", derive(Updateable, Composite))]
)]
pub struct PermissionOverwrite { pub struct PermissionOverwrite {
pub id: Snowflake, pub id: Snowflake,
#[serde(rename = "type")] #[serde(rename = "type")]

View File

@ -1,14 +1,22 @@
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use chorus_macros::{Composite, Updateable};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::gateway::{GatewayHandle, Updateable};
use crate::types::entities::User; use crate::types::entities::User;
use crate::types::{Composite, Snowflake}; use crate::types::Snowflake;
#[derive(Debug, Clone, Deserialize, Serialize, Default, Updateable, Composite)] #[cfg(feature = "client")]
use crate::types::Composite;
#[cfg(feature = "client")]
use crate::gateway::{GatewayHandle, Updateable};
#[cfg(feature = "client")]
use chorus_macros::{Composite, Updateable};
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[cfg_attr(feature = "client", derive(Updateable, Composite))]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// # Reference /// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/emoji#emoji-object> /// See <https://discord-userdoccers.vercel.app/resources/emoji#emoji-object>
@ -27,6 +35,19 @@ pub struct Emoji {
pub available: Option<bool>, pub available: Option<bool>,
} }
impl std::hash::Hash for Emoji {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.name.hash(state);
self.roles.hash(state);
self.roles.hash(state);
self.require_colons.hash(state);
self.managed.hash(state);
self.animated.hash(state);
self.available.hash(state);
}
}
impl PartialEq for Emoji { impl PartialEq for Emoji {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
!(self.id != other.id !(self.id != other.id

View File

@ -1,25 +1,32 @@
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use chorus_macros::{observe_option_vec, observe_vec, Composite, Updateable};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::gateway::{GatewayHandle, Updateable};
use crate::types::types::guild_configuration::GuildFeaturesList; use crate::types::types::guild_configuration::GuildFeaturesList;
use crate::types::{ use crate::types::{
entities::{Channel, Emoji, RoleObject, Sticker, User, VoiceState, Webhook}, entities::{Channel, Emoji, RoleObject, Sticker, User, VoiceState, Webhook},
interfaces::WelcomeScreenObject, interfaces::WelcomeScreenObject,
utils::Snowflake, utils::Snowflake,
Composite,
}; };
use bitflags::bitflags; use bitflags::bitflags;
use super::PublicUser; use super::PublicUser;
#[cfg(feature = "client")]
use crate::gateway::{GatewayHandle, Updateable};
#[cfg(feature = "client")]
use chorus_macros::{observe_option_vec, observe_vec, Composite, Updateable};
#[cfg(feature = "client")]
use crate::types::Composite;
/// See <https://discord.com/developers/docs/resources/guild> /// See <https://discord.com/developers/docs/resources/guild>
#[derive(Serialize, Deserialize, Debug, Default, Clone, Updateable, Composite)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "client", derive(Updateable, Composite))]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct Guild { pub struct Guild {
pub afk_channel_id: Option<Snowflake>, pub afk_channel_id: Option<Snowflake>,
@ -34,14 +41,14 @@ pub struct Guild {
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub bans: Option<Vec<GuildBan>>, pub bans: Option<Vec<GuildBan>>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
#[observe_option_vec] #[cfg_attr(feature = "client", observe_option_vec)]
pub channels: Option<Vec<Arc<RwLock<Channel>>>>, pub channels: Option<Vec<Arc<RwLock<Channel>>>>,
pub default_message_notifications: Option<MessageNotificationLevel>, pub default_message_notifications: Option<MessageNotificationLevel>,
pub description: Option<String>, pub description: Option<String>,
pub discovery_splash: Option<String>, pub discovery_splash: Option<String>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
#[cfg_attr(feature = "client", observe_vec)]
#[serde(default)] #[serde(default)]
#[observe_vec]
pub emojis: Vec<Arc<RwLock<Emoji>>>, pub emojis: Vec<Arc<RwLock<Emoji>>>,
pub explicit_content_filter: Option<i32>, pub explicit_content_filter: Option<i32>,
//#[cfg_attr(feature = "sqlx", sqlx(try_from = "String"))] //#[cfg_attr(feature = "sqlx", sqlx(try_from = "String"))]
@ -77,7 +84,7 @@ pub struct Guild {
pub public_updates_channel_id: Option<Snowflake>, pub public_updates_channel_id: Option<Snowflake>,
pub region: Option<String>, pub region: Option<String>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
#[observe_option_vec] #[cfg_attr(feature = "client", observe_option_vec)]
pub roles: Option<Vec<Arc<RwLock<RoleObject>>>>, pub roles: Option<Vec<Arc<RwLock<RoleObject>>>>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub rules_channel: Option<String>, pub rules_channel: Option<String>,
@ -91,10 +98,10 @@ pub struct Guild {
pub vanity_url_code: Option<String>, pub vanity_url_code: Option<String>,
pub verification_level: Option<VerificationLevel>, pub verification_level: Option<VerificationLevel>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
#[observe_option_vec] #[cfg_attr(feature = "client", observe_option_vec)]
pub voice_states: Option<Vec<Arc<RwLock<VoiceState>>>>, pub voice_states: Option<Vec<Arc<RwLock<VoiceState>>>>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
#[observe_option_vec] #[cfg_attr(feature = "client", observe_option_vec)]
pub webhooks: Option<Vec<Arc<RwLock<Webhook>>>>, pub webhooks: Option<Vec<Arc<RwLock<Webhook>>>>,
#[cfg(feature = "sqlx")] #[cfg(feature = "sqlx")]
pub welcome_screen: Option<sqlx::types::Json<WelcomeScreenObject>>, pub welcome_screen: Option<sqlx::types::Json<WelcomeScreenObject>>,
@ -104,8 +111,113 @@ pub struct Guild {
pub widget_enabled: Option<bool>, pub widget_enabled: Option<bool>,
} }
impl std::hash::Hash for Guild {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.afk_channel_id.hash(state);
self.afk_timeout.hash(state);
self.application_id.hash(state);
self.approximate_member_count.hash(state);
self.approximate_presence_count.hash(state);
self.banner.hash(state);
self.bans.hash(state);
self.default_message_notifications.hash(state);
self.description.hash(state);
self.discovery_splash.hash(state);
self.explicit_content_filter.hash(state);
self.features.hash(state);
self.icon.hash(state);
self.icon_hash.hash(state);
self.id.hash(state);
self.invites.hash(state);
self.joined_at.hash(state);
self.large.hash(state);
self.max_members.hash(state);
self.max_presences.hash(state);
self.max_stage_video_channel_users.hash(state);
self.max_video_channel_users.hash(state);
self.mfa_level.hash(state);
self.name.hash(state);
self.nsfw_level.hash(state);
self.owner.hash(state);
self.owner_id.hash(state);
self.permissions.hash(state);
self.preferred_locale.hash(state);
self.premium_progress_bar_enabled.hash(state);
self.premium_subscription_count.hash(state);
self.premium_tier.hash(state);
self.primary_category_id.hash(state);
self.public_updates_channel_id.hash(state);
self.region.hash(state);
self.rules_channel.hash(state);
self.rules_channel_id.hash(state);
self.splash.hash(state);
self.stickers.hash(state);
self.system_channel_flags.hash(state);
self.system_channel_id.hash(state);
self.vanity_url_code.hash(state);
self.verification_level.hash(state);
self.welcome_screen.hash(state);
self.welcome_screen.hash(state);
self.widget_channel_id.hash(state);
self.widget_enabled.hash(state);
}
}
impl std::cmp::PartialEq for Guild {
fn eq(&self, other: &Self) -> bool {
self.afk_channel_id == other.afk_channel_id
&& self.afk_timeout == other.afk_timeout
&& self.application_id == other.application_id
&& self.approximate_member_count == other.approximate_member_count
&& self.approximate_presence_count == other.approximate_presence_count
&& self.banner == other.banner
&& self.bans == other.bans
&& self.default_message_notifications == other.default_message_notifications
&& self.description == other.description
&& self.discovery_splash == other.discovery_splash
&& self.explicit_content_filter == other.explicit_content_filter
&& self.features == other.features
&& self.icon == other.icon
&& self.icon_hash == other.icon_hash
&& self.id == other.id
&& self.joined_at == other.joined_at
&& self.large == other.large
&& self.max_members == other.max_members
&& self.max_presences == other.max_presences
&& self.max_stage_video_channel_users == other.max_stage_video_channel_users
&& self.max_video_channel_users == other.max_video_channel_users
&& self.mfa_level == other.mfa_level
&& self.name == other.name
&& self.nsfw_level == other.nsfw_level
&& self.owner == other.owner
&& self.owner_id == other.owner_id
&& self.permissions == other.permissions
&& self.preferred_locale == other.preferred_locale
&& self.premium_progress_bar_enabled == other.premium_progress_bar_enabled
&& self.premium_subscription_count == other.premium_subscription_count
&& self.premium_tier == other.premium_tier
&& self.primary_category_id == other.primary_category_id
&& self.public_updates_channel_id == other.public_updates_channel_id
&& self.region == other.region
&& self.rules_channel == other.rules_channel
&& self.rules_channel_id == other.rules_channel_id
&& self.splash == other.splash
&& self.stickers == other.stickers
&& self.system_channel_flags == other.system_channel_flags
&& self.system_channel_id == other.system_channel_id
&& self.vanity_url_code == other.vanity_url_code
&& self.verification_level == other.verification_level
&& self.welcome_screen == other.welcome_screen
&& self.welcome_screen == other.welcome_screen
&& self.widget_channel_id == other.widget_channel_id
&& self.widget_enabled == other.widget_enabled
}
}
impl std::cmp::Eq for Guild {}
/// See <https://docs.spacebar.chat/routes/#get-/guilds/-guild_id-/bans/-user-> /// See <https://docs.spacebar.chat/routes/#get-/guilds/-guild_id-/bans/-user->
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)] #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct GuildBan { pub struct GuildBan {
pub user: PublicUser, pub user: PublicUser,
@ -135,10 +247,29 @@ pub struct GuildInvite {
pub vanity_url: Option<bool>, pub vanity_url: Option<bool>,
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] impl std::hash::Hash for GuildInvite {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.code.hash(state);
self.temporary.hash(state);
self.uses.hash(state);
self.max_uses.hash(state);
self.max_age.hash(state);
self.created_at.hash(state);
self.expires_at.hash(state);
self.guild_id.hash(state);
self.channel_id.hash(state);
self.inviter_id.hash(state);
self.target_user_id.hash(state);
self.target_user.hash(state);
self.target_user_type.hash(state);
self.vanity_url.hash(state);
}
}
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Hash)]
pub struct UnavailableGuild { pub struct UnavailableGuild {
id: Snowflake, pub id: Snowflake,
unavailable: bool, pub unavailable: bool,
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
@ -202,7 +333,7 @@ pub struct GuildScheduledEventEntityMetadata {
pub location: Option<String>, pub location: Option<String>,
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct VoiceRegion { pub struct VoiceRegion {
id: String, id: String,
name: String, name: String,
@ -211,7 +342,7 @@ pub struct VoiceRegion {
custom: bool, custom: bool,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq)] #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See <https://discord-userdoccers.vercel.app/resources/guild#message-notification-level> /// See <https://discord-userdoccers.vercel.app/resources/guild#message-notification-level>
@ -221,7 +352,7 @@ pub enum MessageNotificationLevel {
OnlyMentions = 1, OnlyMentions = 1,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq)] #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See <https://discord-userdoccers.vercel.app/resources/guild#explicit-content-filter-level> /// See <https://discord-userdoccers.vercel.app/resources/guild#explicit-content-filter-level>
@ -232,7 +363,7 @@ pub enum ExplicitContentFilterLevel {
AllMembers = 2, AllMembers = 2,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq)] #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See <https://discord-userdoccers.vercel.app/resources/guild#verification-level> /// See <https://discord-userdoccers.vercel.app/resources/guild#verification-level>
@ -245,7 +376,7 @@ pub enum VerificationLevel {
VeryHigh = 4, VeryHigh = 4,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq)] #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See <https://discord-userdoccers.vercel.app/resources/guild#verification-level> /// See <https://discord-userdoccers.vercel.app/resources/guild#verification-level>
@ -255,7 +386,7 @@ pub enum MFALevel {
Elevated = 1, Elevated = 1,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq)] #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See <https://discord-userdoccers.vercel.app/resources/guild#verification-level> /// See <https://discord-userdoccers.vercel.app/resources/guild#verification-level>
@ -267,7 +398,7 @@ pub enum NSFWLevel {
AgeRestricted = 3, AgeRestricted = 3,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq)] #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See <https://discord-userdoccers.vercel.app/resources/guild#verification-level> /// See <https://discord-userdoccers.vercel.app/resources/guild#verification-level>
@ -280,7 +411,7 @@ pub enum PremiumTier {
} }
bitflags! { bitflags! {
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
/// # Reference /// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/guild#system-channel-flags> /// See <https://discord-userdoccers.vercel.app/resources/guild#system-channel-flags>
pub struct SystemChannelFlags: u64 { pub struct SystemChannelFlags: u64 {

View File

@ -10,6 +10,7 @@ pub use guild_member::*;
pub use integration::*; pub use integration::*;
pub use invite::*; pub use invite::*;
pub use message::*; pub use message::*;
pub use ratelimits::*;
pub use relationship::*; pub use relationship::*;
pub use role::*; pub use role::*;
pub use security_key::*; pub use security_key::*;
@ -22,9 +23,16 @@ pub use user_settings::*;
pub use voice_state::*; pub use voice_state::*;
pub use webhook::*; pub use webhook::*;
#[cfg(feature = "client")]
use crate::gateway::{GatewayHandle, Updateable}; use crate::gateway::{GatewayHandle, Updateable};
#[cfg(feature = "client")]
use async_trait::async_trait; use async_trait::async_trait;
#[cfg(feature = "client")]
use std::fmt::Debug; use std::fmt::Debug;
#[cfg(feature = "client")]
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
mod application; mod application;
@ -39,6 +47,7 @@ mod guild_member;
mod integration; mod integration;
mod invite; mod invite;
mod message; mod message;
mod ratelimits;
mod relationship; mod relationship;
mod role; mod role;
mod security_key; mod security_key;
@ -51,6 +60,7 @@ mod user_settings;
mod voice_state; mod voice_state;
mod webhook; mod webhook;
#[cfg(feature = "client")]
#[async_trait(?Send)] #[async_trait(?Send)]
pub trait Composite<T: Updateable + Clone + Debug> { pub trait Composite<T: Updateable + Clone + Debug> {
async fn watch_whole(self, gateway: &GatewayHandle) -> Self; async fn watch_whole(self, gateway: &GatewayHandle) -> Self;

View File

@ -1,13 +1,21 @@
use bitflags::bitflags; use bitflags::bitflags;
use chorus_macros::{Composite, Updateable};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_aux::prelude::{deserialize_option_number_from_string, deserialize_string_from_number}; use serde_aux::prelude::{deserialize_option_number_from_string, deserialize_string_from_number};
use std::fmt::Debug; use std::fmt::Debug;
use crate::gateway::{GatewayHandle, Updateable}; use crate::types::utils::Snowflake;
use crate::types::{utils::Snowflake, Composite};
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Updateable, Composite)] #[cfg(feature = "client")]
use chorus_macros::{Composite, Updateable};
#[cfg(feature = "client")]
use crate::gateway::{GatewayHandle, Updateable};
#[cfg(feature = "client")]
use crate::types::Composite;
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
#[cfg_attr(feature = "client", derive(Updateable, Composite))]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// See <https://discord.com/developers/docs/topics/permissions#role-object> /// See <https://discord.com/developers/docs/topics/permissions#role-object>
pub struct RoleObject { pub struct RoleObject {

View File

@ -28,6 +28,22 @@ pub struct Sticker {
pub sort_value: Option<u8>, pub sort_value: Option<u8>,
} }
impl std::hash::Hash for Sticker {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.pack_id.hash(state);
self.name.hash(state);
self.description.hash(state);
self.tags.hash(state);
self.asset.hash(state);
self.sticker_type.hash(state);
self.format_type.hash(state);
self.available.hash(state);
self.guild_id.hash(state);
self.sort_value.hash(state);
}
}
impl PartialEq for Sticker { impl PartialEq for Sticker {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.id == other.id self.id == other.id

View File

@ -1,11 +1,17 @@
use chorus_macros::{Composite, Updateable}; use crate::types::utils::Snowflake;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_aux::prelude::deserialize_option_number_from_string; use serde_aux::prelude::deserialize_option_number_from_string;
use std::fmt::Debug; use std::fmt::Debug;
#[cfg(feature = "client")]
use crate::gateway::{GatewayHandle, Updateable}; use crate::gateway::{GatewayHandle, Updateable};
use crate::types::{utils::Snowflake, Composite};
#[cfg(feature = "client")]
use crate::types::Composite;
#[cfg(feature = "client")]
use chorus_macros::{Composite, Updateable};
use super::Emoji; use super::Emoji;
@ -21,7 +27,8 @@ impl User {
PublicUser::from(self) PublicUser::from(self)
} }
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Updateable, Composite)] #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "client", derive(Updateable, Composite))]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct User { pub struct User {
pub id: Snowflake, pub id: Snowflake,
@ -56,7 +63,7 @@ pub struct User {
pub disabled: Option<bool>, pub disabled: Option<bool>,
} }
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct PublicUser { pub struct PublicUser {
pub id: Snowflake, pub id: Snowflake,
pub username: Option<String>, pub username: Option<String>,

View File

@ -53,15 +53,17 @@ pub struct UserSettings {
pub friend_source_flags: sqlx::types::Json<FriendSourceFlags>, pub friend_source_flags: sqlx::types::Json<FriendSourceFlags>,
#[cfg(not(feature = "sqlx"))] #[cfg(not(feature = "sqlx"))]
pub friend_source_flags: FriendSourceFlags, pub friend_source_flags: FriendSourceFlags,
pub gateway_connected: bool, pub gateway_connected: Option<bool>,
pub gif_auto_play: bool, pub gif_auto_play: bool,
#[cfg(feature = "sqlx")] #[cfg(feature = "sqlx")]
pub guild_folders: sqlx::types::Json<Vec<GuildFolder>>, pub guild_folders: sqlx::types::Json<Vec<GuildFolder>>,
#[cfg(not(feature = "sqlx"))] #[cfg(not(feature = "sqlx"))]
pub guild_folders: Vec<GuildFolder>, pub guild_folders: Vec<GuildFolder>,
#[cfg(feature = "sqlx")] #[cfg(feature = "sqlx")]
#[serde(default)]
pub guild_positions: sqlx::types::Json<Vec<String>>, pub guild_positions: sqlx::types::Json<Vec<String>>,
#[cfg(not(feature = "sqlx"))] #[cfg(not(feature = "sqlx"))]
#[serde(default)]
pub guild_positions: Vec<String>, pub guild_positions: Vec<String>,
pub inline_attachment_media: bool, pub inline_attachment_media: bool,
pub inline_embed_media: bool, pub inline_embed_media: bool,
@ -98,7 +100,7 @@ impl Default for UserSettings {
enable_tts_command: false, enable_tts_command: false,
explicit_content_filter: 0, explicit_content_filter: 0,
friend_source_flags: Default::default(), friend_source_flags: Default::default(),
gateway_connected: false, gateway_connected: Some(false),
gif_auto_play: false, gif_auto_play: false,
guild_folders: Default::default(), guild_folders: Default::default(),
guild_positions: Default::default(), guild_positions: Default::default(),

View File

@ -1,20 +1,27 @@
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
#[cfg(feature = "client")]
use chorus_macros::{Composite, Updateable}; use chorus_macros::{Composite, Updateable};
#[cfg(feature = "client")]
use crate::types::Composite;
#[cfg(feature = "client")]
use crate::gateway::{GatewayHandle, Updateable};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Debug; use std::fmt::Debug;
use crate::gateway::{GatewayHandle, Updateable};
use crate::types::{ use crate::types::{
entities::{Guild, GuildMember}, entities::{Guild, GuildMember},
utils::Snowflake, utils::Snowflake,
Composite,
}; };
/// See <https://docs.spacebar.chat/routes/#cmp--schemas-voicestate> /// See <https://docs.spacebar.chat/routes/#cmp--schemas-voicestate>
#[derive(Serialize, Deserialize, Debug, Default, Clone, Updateable, Composite)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
#[cfg_attr(feature = "client", derive(Updateable, Composite))]
pub struct VoiceState { pub struct VoiceState {
pub guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
pub guild: Option<Guild>, pub guild: Option<Guild>,

View File

@ -1,18 +1,25 @@
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use chorus_macros::{Composite, Updateable};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg(feature = "client")]
use crate::gateway::{GatewayHandle, Updateable}; use crate::gateway::{GatewayHandle, Updateable};
#[cfg(feature = "client")]
use chorus_macros::{Composite, Updateable};
#[cfg(feature = "client")]
use crate::types::Composite;
use crate::types::{ use crate::types::{
entities::{Guild, User}, entities::{Guild, User},
utils::Snowflake, utils::Snowflake,
Composite,
}; };
/// See <https://docs.spacebar.chat/routes/#cmp--schemas-webhook> /// See <https://docs.spacebar.chat/routes/#cmp--schemas-webhook>
#[derive(Serialize, Deserialize, Debug, Default, Clone, Updateable, Composite)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "client", derive(Updateable, Composite))]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct Webhook { pub struct Webhook {
pub id: Snowflake, pub id: Snowflake,

View File

@ -1,5 +1,5 @@
use crate::types::JsonField; use crate::types::{JsonField, SourceUrlField};
use chorus_macros::JsonField; use chorus_macros::{JsonField, SourceUrlField};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::{ use crate::types::{
@ -7,6 +7,7 @@ use crate::types::{
WebSocketEvent, WebSocketEvent,
}; };
#[cfg(feature = "client")]
use super::UpdateMessage; use super::UpdateMessage;
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
@ -18,15 +19,18 @@ pub struct AutoModerationRuleCreate {
impl WebSocketEvent for AutoModerationRuleCreate {} impl WebSocketEvent for AutoModerationRuleCreate {}
#[derive(Debug, Deserialize, Serialize, Default, Clone, JsonField)] #[derive(Debug, Deserialize, Serialize, Default, Clone, JsonField, SourceUrlField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-update> /// See <https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-update>
pub struct AutoModerationRuleUpdate { pub struct AutoModerationRuleUpdate {
#[serde(flatten)] #[serde(flatten)]
pub rule: AutoModerationRule, pub rule: AutoModerationRule,
#[serde(skip)] #[serde(skip)]
pub json: String, pub json: String,
#[serde(skip)]
pub source_url: String,
} }
#[cfg(feature = "client")]
impl UpdateMessage<AutoModerationRule> for AutoModerationRuleUpdate { impl UpdateMessage<AutoModerationRule> for AutoModerationRuleUpdate {
fn id(&self) -> Option<Snowflake> { fn id(&self) -> Option<Snowflake> {
Some(self.rule.id) Some(self.rule.id)

View File

@ -1,14 +1,18 @@
use std::sync::{Arc, RwLock};
use crate::types::events::WebSocketEvent; use crate::types::events::WebSocketEvent;
use crate::types::Guild; use crate::types::{entities::Channel, JsonField, Snowflake, SourceUrlField};
use crate::types::{entities::Channel, JsonField, Snowflake}; use chorus_macros::{JsonField, SourceUrlField};
use chorus_macros::JsonField;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg(feature = "client")]
use super::UpdateMessage; use super::UpdateMessage;
#[cfg(feature = "client")]
use std::sync::{Arc, RwLock};
#[cfg(feature = "client")]
use crate::types::Guild;
#[derive(Debug, Default, Deserialize, Serialize)] #[derive(Debug, Default, Deserialize, Serialize)]
/// See <https://discord.com/developers/docs/topics/gateway-events#channel-pins-update> /// See <https://discord.com/developers/docs/topics/gateway-events#channel-pins-update>
pub struct ChannelPinsUpdate { pub struct ChannelPinsUpdate {
@ -19,17 +23,20 @@ pub struct ChannelPinsUpdate {
impl WebSocketEvent for ChannelPinsUpdate {} impl WebSocketEvent for ChannelPinsUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField)] #[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#channel-create> /// See <https://discord.com/developers/docs/topics/gateway-events#channel-create>
pub struct ChannelCreate { pub struct ChannelCreate {
#[serde(flatten)] #[serde(flatten)]
pub channel: Channel, pub channel: Channel,
#[serde(skip)] #[serde(skip)]
pub json: String, pub json: String,
#[serde(skip)]
pub source_url: String,
} }
impl WebSocketEvent for ChannelCreate {} impl WebSocketEvent for ChannelCreate {}
#[cfg(feature = "client")]
impl UpdateMessage<Guild> for ChannelCreate { impl UpdateMessage<Guild> for ChannelCreate {
fn id(&self) -> Option<Snowflake> { fn id(&self) -> Option<Snowflake> {
self.channel.guild_id self.channel.guild_id
@ -46,17 +53,20 @@ impl UpdateMessage<Guild> for ChannelCreate {
} }
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField)] #[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#channel-update> /// See <https://discord.com/developers/docs/topics/gateway-events#channel-update>
pub struct ChannelUpdate { pub struct ChannelUpdate {
#[serde(flatten)] #[serde(flatten)]
pub channel: Channel, pub channel: Channel,
#[serde(skip)] #[serde(skip)]
pub json: String, pub json: String,
#[serde(skip)]
pub source_url: String,
} }
impl WebSocketEvent for ChannelUpdate {} impl WebSocketEvent for ChannelUpdate {}
#[cfg(feature = "client")]
impl UpdateMessage<Channel> for ChannelUpdate { impl UpdateMessage<Channel> for ChannelUpdate {
fn update(&mut self, object_to_update: Arc<RwLock<Channel>>) { fn update(&mut self, object_to_update: Arc<RwLock<Channel>>) {
let mut write = object_to_update.write().unwrap(); let mut write = object_to_update.write().unwrap();
@ -87,15 +97,18 @@ pub struct ChannelUnreadUpdateObject {
impl WebSocketEvent for ChannelUnreadUpdate {} impl WebSocketEvent for ChannelUnreadUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField)] #[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#channel-delete> /// See <https://discord.com/developers/docs/topics/gateway-events#channel-delete>
pub struct ChannelDelete { pub struct ChannelDelete {
#[serde(flatten)] #[serde(flatten)]
pub channel: Channel, pub channel: Channel,
#[serde(skip)] #[serde(skip)]
pub json: String, pub json: String,
#[serde(skip)]
pub source_url: String,
} }
#[cfg(feature = "client")]
impl UpdateMessage<Guild> for ChannelDelete { impl UpdateMessage<Guild> for ChannelDelete {
fn id(&self) -> Option<Snowflake> { fn id(&self) -> Option<Snowflake> {
self.channel.guild_id self.channel.guild_id
@ -111,11 +124,7 @@ impl UpdateMessage<Guild> for ChannelDelete {
} }
for (iteration, item) in (0_u32..).zip(write.channels.as_mut().unwrap().iter()) { for (iteration, item) in (0_u32..).zip(write.channels.as_mut().unwrap().iter()) {
if item.read().unwrap().id == self.id().unwrap() { if item.read().unwrap().id == self.id().unwrap() {
write write.channels.as_mut().unwrap().remove(iteration as usize);
.channels
.as_mut()
.unwrap()
.swap_remove(iteration as usize);
return; return;
} }
} }

View File

@ -1,6 +1,4 @@
use std::sync::{Arc, RwLock}; use chorus_macros::{JsonField, SourceUrlField};
use chorus_macros::JsonField;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -8,18 +6,38 @@ use crate::types::entities::{Guild, PublicUser, UnavailableGuild};
use crate::types::events::WebSocketEvent; use crate::types::events::WebSocketEvent;
use crate::types::{ use crate::types::{
AuditLogEntry, Emoji, GuildMember, GuildScheduledEvent, JsonField, RoleObject, Snowflake, AuditLogEntry, Emoji, GuildMember, GuildScheduledEvent, JsonField, RoleObject, Snowflake,
Sticker, SourceUrlField, Sticker,
}; };
use super::{PresenceUpdate, UpdateMessage}; use super::PresenceUpdate;
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[cfg(feature = "client")]
use super::UpdateMessage;
#[cfg(feature = "client")]
use std::sync::{Arc, RwLock};
#[derive(Debug, Deserialize, Serialize, Default, Clone, SourceUrlField, JsonField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-create>; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-create>;
/// Received to give data about a guild; /// Received to give data about a guild;
// This one is particularly painful, it can be a Guild object with an extra field or an unavailable guild object // This one is particularly painful, it can be a Guild object with an extra field or an unavailable guild object
pub struct GuildCreate { pub struct GuildCreate {
#[serde(flatten)] #[serde(flatten)]
pub d: GuildCreateDataOption, pub d: GuildCreateDataOption,
#[serde(skip)]
pub source_url: String,
#[serde(skip)]
pub json: String,
}
impl UpdateMessage<Guild> for GuildCreate {
fn id(&self) -> Option<Snowflake> {
match &self.d {
GuildCreateDataOption::UnavailableGuild(unavailable) => Some(unavailable.id),
GuildCreateDataOption::Guild(guild) => Some(guild.id),
}
}
fn update(&mut self, _: Arc<RwLock<Guild>>) {}
} }
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
@ -57,22 +75,43 @@ pub struct GuildBanRemove {
impl WebSocketEvent for GuildBanRemove {} impl WebSocketEvent for GuildBanRemove {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone, SourceUrlField, JsonField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-update>; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-update>;
/// Received to give info about a guild being updated; /// Received to give info about a guild being updated;
pub struct GuildUpdate { pub struct GuildUpdate {
#[serde(flatten)] #[serde(flatten)]
pub guild: Guild, pub guild: Guild,
#[serde(skip)]
pub source_url: String,
#[serde(skip)]
pub json: String,
} }
impl WebSocketEvent for GuildUpdate {} impl WebSocketEvent for GuildUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] impl UpdateMessage<Guild> for GuildUpdate {
fn id(&self) -> Option<Snowflake> {
Some(self.guild.id)
}
}
#[derive(Debug, Default, Deserialize, Serialize, Clone, SourceUrlField, JsonField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-delete>; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-delete>;
/// Received to tell the client about a guild being deleted; /// Received to tell the client about a guild being deleted;
pub struct GuildDelete { pub struct GuildDelete {
#[serde(flatten)] #[serde(flatten)]
pub guild: UnavailableGuild, pub guild: UnavailableGuild,
#[serde(skip)]
pub source_url: String,
#[serde(skip)]
pub json: String,
}
impl UpdateMessage<Guild> for GuildDelete {
fn id(&self) -> Option<Snowflake> {
Some(self.guild.id)
}
fn update(&mut self, _: Arc<RwLock<Guild>>) {}
} }
impl WebSocketEvent for GuildDelete {} impl WebSocketEvent for GuildDelete {}
@ -168,17 +207,20 @@ pub struct GuildMembersChunk {
impl WebSocketEvent for GuildMembersChunk {} impl WebSocketEvent for GuildMembersChunk {}
#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField)] #[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-role-create> /// See <https://discord.com/developers/docs/topics/gateway-events#guild-role-create>
pub struct GuildRoleCreate { pub struct GuildRoleCreate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub role: RoleObject, pub role: RoleObject,
#[serde(skip)] #[serde(skip)]
pub json: String, pub json: String,
#[serde(skip)]
pub source_url: String,
} }
impl WebSocketEvent for GuildRoleCreate {} impl WebSocketEvent for GuildRoleCreate {}
#[cfg(feature = "client")]
impl UpdateMessage<Guild> for GuildRoleCreate { impl UpdateMessage<Guild> for GuildRoleCreate {
fn id(&self) -> Option<Snowflake> { fn id(&self) -> Option<Snowflake> {
Some(self.guild_id) Some(self.guild_id)
@ -198,17 +240,20 @@ impl UpdateMessage<Guild> for GuildRoleCreate {
} }
} }
#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField)] #[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#guild-role-update> /// See <https://discord.com/developers/docs/topics/gateway-events#guild-role-update>
pub struct GuildRoleUpdate { pub struct GuildRoleUpdate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub role: RoleObject, pub role: RoleObject,
#[serde(skip)] #[serde(skip)]
pub json: String, pub json: String,
#[serde(skip)]
pub source_url: String,
} }
impl WebSocketEvent for GuildRoleUpdate {} impl WebSocketEvent for GuildRoleUpdate {}
#[cfg(feature = "client")]
impl UpdateMessage<RoleObject> for GuildRoleUpdate { impl UpdateMessage<RoleObject> for GuildRoleUpdate {
fn id(&self) -> Option<Snowflake> { fn id(&self) -> Option<Snowflake> {
Some(self.role.id) Some(self.role.id)

View File

@ -1,12 +1,5 @@
use std::sync::{Arc, RwLock};
use std::collections::HashMap;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::{from_str, from_value, to_value, Value};
pub use application::*; pub use application::*;
pub use auto_moderation::*; pub use auto_moderation::*;
pub use call::*; pub use call::*;
@ -34,9 +27,24 @@ pub use voice::*;
pub use webhooks::*; pub use webhooks::*;
pub use webrtc::*; pub use webrtc::*;
#[cfg(feature = "client")]
use super::Snowflake;
#[cfg(feature = "client")]
use crate::gateway::Updateable; use crate::gateway::Updateable;
use super::Snowflake; #[cfg(feature = "client")]
use serde_json::{from_str, from_value, to_value, Value};
#[cfg(feature = "client")]
use std::collections::HashMap;
use std::fmt::Debug;
#[cfg(feature = "client")]
use std::sync::{Arc, RwLock};
#[cfg(feature = "client")]
use serde::de::DeserializeOwned;
mod application; mod application;
mod auto_moderation; mod auto_moderation;
@ -66,7 +74,7 @@ mod webhooks;
mod webrtc; mod webrtc;
pub trait WebSocketEvent {} pub trait WebSocketEvent: Send + Sync + Debug {}
#[derive(Debug, Default, Serialize, Clone)] #[derive(Debug, Default, Serialize, Clone)]
/// The payload used for sending events to the gateway /// The payload used for sending events to the gateway
@ -107,6 +115,7 @@ pub struct GatewayReceivePayload<'a> {
impl<'a> WebSocketEvent for GatewayReceivePayload<'a> {} impl<'a> WebSocketEvent for GatewayReceivePayload<'a> {}
#[cfg(feature = "client")]
/// An [`UpdateMessage<T>`] represents a received Gateway Message which contains updated /// An [`UpdateMessage<T>`] represents a received Gateway Message which contains updated
/// information for an [`Updateable`] of Type T. /// information for an [`Updateable`] of Type T.
/// # Example: /// # Example:
@ -119,7 +128,7 @@ impl<'a> WebSocketEvent for GatewayReceivePayload<'a> {}
/// This would imply, that the [`WebSocketEvent`] "[`ChannelUpdate`]" contains new/updated information /// This would imply, that the [`WebSocketEvent`] "[`ChannelUpdate`]" contains new/updated information
/// about a [`Channel`]. The update method describes how this new information will be turned into /// about a [`Channel`]. The update method describes how this new information will be turned into
/// a [`Channel`] object. /// a [`Channel`] object.
pub(crate) trait UpdateMessage<T>: Clone + JsonField pub(crate) trait UpdateMessage<T>: Clone + JsonField + SourceUrlField
where where
T: Updateable + Serialize + DeserializeOwned + Clone, T: Updateable + Serialize + DeserializeOwned + Clone,
{ {
@ -134,6 +143,12 @@ pub(crate) trait JsonField: Clone {
fn get_json(&self) -> String; fn get_json(&self) -> String;
} }
pub trait SourceUrlField: Clone {
fn set_source_url(&mut self, url: String);
fn get_source_url(&self) -> String;
}
#[cfg(feature = "client")]
/// Only applicable for events where the Update struct is the same as the Entity struct /// Only applicable for events where the Update struct is the same as the Entity struct
pub(crate) fn update_object( pub(crate) fn update_object(
value: String, value: String,

View File

@ -1,10 +1,11 @@
use chorus_macros::JsonField; use chorus_macros::{JsonField, SourceUrlField};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::entities::{Channel, ThreadMember}; use crate::types::entities::{Channel, ThreadMember};
use crate::types::events::WebSocketEvent; use crate::types::events::WebSocketEvent;
use crate::types::{JsonField, Snowflake}; use crate::types::{JsonField, Snowflake, SourceUrlField};
#[cfg(feature = "client")]
use super::UpdateMessage; use super::UpdateMessage;
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
@ -16,17 +17,20 @@ pub struct ThreadCreate {
impl WebSocketEvent for ThreadCreate {} impl WebSocketEvent for ThreadCreate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField)] #[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#thread-update> /// See <https://discord.com/developers/docs/topics/gateway-events#thread-update>
pub struct ThreadUpdate { pub struct ThreadUpdate {
#[serde(flatten)] #[serde(flatten)]
pub thread: Channel, pub thread: Channel,
#[serde(skip)] #[serde(skip)]
pub json: String, pub json: String,
#[serde(skip)]
pub source_url: String,
} }
impl WebSocketEvent for ThreadUpdate {} impl WebSocketEvent for ThreadUpdate {}
#[cfg(feature = "client")]
impl UpdateMessage<Channel> for ThreadUpdate { impl UpdateMessage<Channel> for ThreadUpdate {
fn id(&self) -> Option<Snowflake> { fn id(&self) -> Option<Snowflake> {
Some(self.thread.id) Some(self.thread.id)

View File

@ -2,14 +2,14 @@ use serde::{Deserialize, Serialize};
use crate::types::utils::Snowflake; use crate::types::utils::Snowflake;
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Hash)]
pub struct WelcomeScreenObject { pub struct WelcomeScreenObject {
pub enabled: bool, pub enabled: bool,
pub description: Option<String>, pub description: Option<String>,
pub welcome_channels: Vec<WelcomeScreenChannel>, pub welcome_channels: Vec<WelcomeScreenChannel>,
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Hash)]
pub struct WelcomeScreenChannel { pub struct WelcomeScreenChannel {
pub channel_id: Snowflake, pub channel_id: Snowflake,
pub description: String, pub description: String,

View File

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)] #[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub struct RegisterSchema { pub struct RegisterSchema {
pub username: String, pub username: String,
@ -15,7 +15,7 @@ pub struct RegisterSchema {
pub promotional_email_opt_in: Option<bool>, pub promotional_email_opt_in: Option<bool>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub struct LoginSchema { pub struct LoginSchema {
/// For Discord, usernames must be between 2 and 32 characters, /// For Discord, usernames must be between 2 and 32 characters,

View File

@ -4,13 +4,13 @@ mod common;
#[tokio::test] #[tokio::test]
async fn test_registration() { async fn test_registration() {
let mut bundle = common::setup().await; let bundle = common::setup().await;
let reg = RegisterSchema { let reg = RegisterSchema {
username: "Hiiii".into(), username: "Hiiii".into(),
date_of_birth: Some("2000-01-01".to_string()), date_of_birth: Some("2000-01-01".to_string()),
consent: true, consent: true,
..Default::default() ..Default::default()
}; };
bundle.instance.register_account(&reg).await.unwrap(); bundle.instance.clone().register_account(reg).await.unwrap();
common::teardown(bundle).await; common::teardown(bundle).await;
} }

View File

@ -31,7 +31,8 @@ impl TestBundle {
..Default::default() ..Default::default()
}; };
self.instance self.instance
.register_account(&register_schema) .clone()
.register_account(register_schema)
.await .await
.unwrap() .unwrap()
} }
@ -42,7 +43,7 @@ impl TestBundle {
limits: self.user.limits.clone(), limits: self.user.limits.clone(),
settings: self.user.settings.clone(), settings: self.user.settings.clone(),
object: self.user.object.clone(), object: self.user.object.clone(),
gateway: Arc::new(Gateway::new(self.instance.urls.wss.clone()).await.unwrap()), gateway: Gateway::new(self.instance.urls.wss.clone()).await.unwrap(),
} }
} }
} }
@ -54,7 +55,7 @@ pub(crate) async fn setup() -> TestBundle {
"ws://localhost:3001".to_string(), "ws://localhost:3001".to_string(),
"http://localhost:3001".to_string(), "http://localhost:3001".to_string(),
); );
let mut instance = Instance::new(urls.clone(), true).await.unwrap(); let instance = Instance::new(urls.clone(), true).await.unwrap();
// Requires the existance of the below user. // Requires the existance of the below user.
let reg = RegisterSchema { let reg = RegisterSchema {
username: "integrationtestuser".into(), username: "integrationtestuser".into(),
@ -91,7 +92,7 @@ pub(crate) async fn setup() -> TestBundle {
default_thread_rate_limit_per_user: Some(0), default_thread_rate_limit_per_user: Some(0),
video_quality_mode: None, video_quality_mode: None,
}; };
let mut user = instance.register_account(&reg).await.unwrap(); let mut user = instance.clone().register_account(reg).await.unwrap();
let guild = Guild::create(&mut user, guild_create_schema).await.unwrap(); let guild = Guild::create(&mut user, guild_create_schema).await.unwrap();
let channel = Channel::create(&mut user, guild.id, None, channel_create_schema) let channel = Channel::create(&mut user, guild.id, None, channel_create_schema)
.await .await