Components and Composites (#175)

As described in #165 , Gateway induced changes of entity structs do not
get propagated to other structs holding the "same" object which got
updated. This is bad because it means that structs still hold
potentially outdated info.

My proposed solution is to create components and composites. A component
is an object with information which is supposed to be the same in at
least 2 structs, such as a Channel object ("channels" field in Guild
struct and lone Channel object for example). These components should be
shared instead of cloned, to make sure that an update to this shared
structs fields is reflected everywhere the struct is being used.

We can do this by using `Arc<Mutex<T>>`. Mutex can be the
std::sync::Mutex, as long as locks on the components themselves are not
being held across .await points. ~~This draft is not yet finished, but~~
all instances of components in composite entity structs have been
replaced with their `Arc<Mutex<T>>` counterparts already.
This commit is contained in:
Flori 2023-08-04 15:55:47 +02:00 committed by GitHub
commit 1aa8bcc6d2
28 changed files with 284 additions and 135 deletions

2
.gitignore vendored
View File

@ -1,6 +1,6 @@
# Generated by Cargo # Generated by Cargo
# will have compiled files and executables # will have compiled files and executables
/target/ /**/target/
# These are backup files generated by rustfmt # These are backup files generated by rustfmt
**/*.rs.bk **/*.rs.bk

View File

@ -11,7 +11,7 @@ client = []
[dependencies] [dependencies]
tokio = { version = "1.29.1", features = ["macros"] } tokio = { version = "1.29.1", features = ["macros"] }
serde = {version = "1.0.171", features = ["derive"]} serde = { version = "1.0.171", features = ["derive", "rc"] }
serde_json = { version = "1.0.103", features = ["raw_value"] } serde_json = { version = "1.0.103", features = ["raw_value"] }
serde-aux = "4.2.0" serde-aux = "4.2.0"
serde_with = "3.0.0" serde_with = "3.0.0"
@ -31,7 +31,15 @@ hostname = "0.3.1"
bitflags = { version = "2.3.3", features = ["serde"] } bitflags = { version = "2.3.3", features = ["serde"] }
lazy_static = "1.4.0" lazy_static = "1.4.0"
poem = { version = "1.3.56", optional = true } poem = { version = "1.3.56", optional = true }
sqlx = { git = "https://github.com/zert3x/sqlx", branch="feature/skip", features = ["mysql", "sqlite", "json", "chrono", "ipnetwork", "runtime-tokio-native-tls", "any"], optional = true } sqlx = { git = "https://github.com/zert3x/sqlx", branch = "feature/skip", features = [
"mysql",
"sqlite",
"json",
"chrono",
"ipnetwork",
"runtime-tokio-native-tls",
"any",
], optional = true }
thiserror = "1.0.43" thiserror = "1.0.43"
jsonwebtoken = "8.3.0" jsonwebtoken = "8.3.0"
log = "0.4.19" log = "0.4.19"

View File

@ -1,5 +1,6 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use std::sync::{Arc, Mutex};
use reqwest::Client; use reqwest::Client;
use serde_json::to_string; use serde_json::to_string;
@ -45,7 +46,7 @@ impl Instance {
login_result.token, login_result.token,
self.clone_limits_if_some(), self.clone_limits_if_some(),
login_result.settings, login_result.settings,
object, Arc::new(Mutex::new(object)),
gateway, gateway,
); );
Ok(user) Ok(user)

View File

@ -1,3 +1,4 @@
use std::sync::{Arc, Mutex};
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use reqwest::Client; use reqwest::Client;
@ -51,8 +52,8 @@ impl Instance {
Rc::new(RefCell::new(self.clone())), Rc::new(RefCell::new(self.clone())),
token.clone(), token.clone(),
self.clone_limits_if_some(), self.clone_limits_if_some(),
settings, Arc::new(Mutex::new(settings)),
user_object, Arc::new(Mutex::new(user_object)),
gateway, gateway,
); );
Ok(user) Ok(user)

View File

@ -1,3 +1,4 @@
use std::sync::{Arc, Mutex};
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use reqwest::Client; use reqwest::Client;
@ -59,7 +60,7 @@ impl UserMeta {
.deserialize_response::<User>(self) .deserialize_response::<User>(self)
.await .await
.unwrap(); .unwrap();
let _ = std::mem::replace(&mut self.object, user_updated.clone()); self.object = Arc::new(Mutex::new(user_updated.clone()));
Ok(user_updated) Ok(user_updated)
} }

View File

@ -2,6 +2,7 @@ use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::rc::Rc; use std::rc::Rc;
use std::sync::{Arc, Mutex};
use reqwest::Client; use reqwest::Client;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -90,8 +91,8 @@ pub struct UserMeta {
pub belongs_to: Rc<RefCell<Instance>>, pub belongs_to: Rc<RefCell<Instance>>,
pub token: String, pub token: String,
pub limits: Option<HashMap<LimitType, Limit>>, pub limits: Option<HashMap<LimitType, Limit>>,
pub settings: UserSettings, pub settings: Arc<Mutex<UserSettings>>,
pub object: User, pub object: Arc<Mutex<User>>,
pub gateway: GatewayHandle, pub gateway: GatewayHandle,
} }
@ -113,8 +114,8 @@ impl UserMeta {
belongs_to: Rc<RefCell<Instance>>, belongs_to: Rc<RefCell<Instance>>,
token: String, token: String,
limits: Option<HashMap<LimitType, Limit>>, limits: Option<HashMap<LimitType, Limit>>,
settings: UserSettings, settings: Arc<Mutex<UserSettings>>,
object: User, object: Arc<Mutex<User>>,
gateway: GatewayHandle, gateway: GatewayHandle,
) -> UserMeta { ) -> UserMeta {
UserMeta { UserMeta {
@ -133,8 +134,8 @@ impl UserMeta {
/// need to make a RateLimited request. To use the [`GatewayHandle`], you will have to identify /// need to make a RateLimited request. To use the [`GatewayHandle`], you will have to identify
/// first. /// first.
pub(crate) async fn shell(instance: Rc<RefCell<Instance>>, token: String) -> UserMeta { pub(crate) async fn shell(instance: Rc<RefCell<Instance>>, token: String) -> UserMeta {
let settings = UserSettings::default(); let settings = Arc::new(Mutex::new(UserSettings::default()));
let object = User::default(); let object = Arc::new(Mutex::new(User::default()));
let wss_url = instance.borrow().urls.wss.clone(); let wss_url = instance.borrow().urls.wss.clone();
// Dummy gateway object // Dummy gateway object
let gateway = Gateway::new(wss_url).await.unwrap(); let gateway = Gateway::new(wss_url).await.unwrap();

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use bitflags::bitflags; use bitflags::bitflags;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
@ -6,7 +8,7 @@ use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::types::utils::Snowflake; use crate::types::utils::Snowflake;
use crate::types::{Team, User}; use crate::types::{Team, User};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// # Reference /// # Reference
/// See <https://discord.com/developers/docs/resources/application#application-resource> /// See <https://discord.com/developers/docs/resources/application#application-resource>
@ -25,7 +27,7 @@ pub struct Application {
pub bot_require_code_grant: bool, pub bot_require_code_grant: bool,
pub verify_key: String, pub verify_key: String,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub owner: User, pub owner: Arc<Mutex<User>>,
pub flags: u64, pub flags: u64,
#[cfg(feature = "sqlx")] #[cfg(feature = "sqlx")]
pub redirect_uris: Option<sqlx::types::Json<Vec<String>>>, pub redirect_uris: Option<sqlx::types::Json<Vec<String>>>,
@ -47,7 +49,7 @@ pub struct Application {
#[cfg(feature = "sqlx")] #[cfg(feature = "sqlx")]
pub install_params: Option<sqlx::types::Json<InstallParams>>, pub install_params: Option<sqlx::types::Json<InstallParams>>,
#[cfg(not(feature = "sqlx"))] #[cfg(not(feature = "sqlx"))]
pub install_params: Option<InstallParams>, pub install_params: Option<Arc<Mutex<InstallParams>>>,
pub terms_of_service_url: Option<String>, pub terms_of_service_url: Option<String>,
pub privacy_policy_url: Option<String>, pub privacy_policy_url: Option<String>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
@ -103,7 +105,7 @@ pub struct InstallParams {
} }
bitflags! { bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
/// # Reference /// # Reference
/// See <https://discord.com/developers/docs/resources/application#application-object-application-flags> /// See <https://discord.com/developers/docs/resources/application#application-object-application-flags>
pub struct ApplicationFlags: u64 { pub struct ApplicationFlags: u64 {
@ -132,7 +134,7 @@ bitflags! {
} }
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
/// # Reference /// # Reference
/// See <https://discord.com/developers/docs/interactions/application-commands#application-command-object> /// See <https://discord.com/developers/docs/interactions/application-commands#application-command-object>
pub struct ApplicationCommand { pub struct ApplicationCommand {
@ -140,10 +142,10 @@ pub struct ApplicationCommand {
pub application_id: Snowflake, pub application_id: Snowflake,
pub name: String, pub name: String,
pub description: String, pub description: String,
pub options: Vec<ApplicationCommandOption>, pub options: Vec<Arc<Mutex<ApplicationCommandOption>>>,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
/// Reference /// Reference
/// See <https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure> /// See <https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure>
pub struct ApplicationCommandOption { pub struct ApplicationCommandOption {
@ -152,7 +154,7 @@ pub struct ApplicationCommandOption {
pub description: String, pub description: String,
pub required: bool, pub required: bool,
pub choices: Vec<ApplicationCommandOptionChoice>, pub choices: Vec<ApplicationCommandOptionChoice>,
pub options: Vec<ApplicationCommandOption>, pub options: Arc<Mutex<Vec<ApplicationCommandOption>>>,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@ -161,7 +163,7 @@ pub struct ApplicationCommandOptionChoice {
pub value: Value, pub value: Value,
} }
#[derive(Debug, Clone, Copy, PartialEq, Serialize_repr, Deserialize_repr)] #[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[repr(i32)] #[repr(i32)]
/// # Reference /// # Reference
@ -184,27 +186,27 @@ pub enum ApplicationCommandOptionType {
Attachment = 11, Attachment = 11,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApplicationCommandInteractionData { pub struct ApplicationCommandInteractionData {
pub id: Snowflake, pub id: Snowflake,
pub name: String, pub name: String,
pub options: Vec<ApplicationCommandInteractionDataOption>, pub options: Vec<Arc<Mutex<ApplicationCommandInteractionDataOption>>>,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApplicationCommandInteractionDataOption { pub struct ApplicationCommandInteractionDataOption {
pub name: String, pub name: String,
pub value: Value, pub value: Value,
pub options: Vec<ApplicationCommandInteractionDataOption>, pub options: Vec<Arc<Mutex<ApplicationCommandInteractionDataOption>>>,
} }
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Default, Clone, Serialize, Deserialize)]
/// See <https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-guild-application-command-permissions-structure> /// See <https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-guild-application-command-permissions-structure>
pub struct GuildApplicationCommandPermissions { pub struct GuildApplicationCommandPermissions {
pub id: Snowflake, pub id: Snowflake,
pub application_id: Snowflake, pub application_id: Snowflake,
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub permissions: Vec<ApplicationCommandPermission>, pub permissions: Vec<Arc<Mutex<ApplicationCommandPermission>>>,
} }
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
@ -217,7 +219,7 @@ pub struct ApplicationCommandPermission {
pub permission: bool, pub permission: bool,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, PartialEq)] #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, PartialEq, Eq, Hash)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[repr(u8)] #[repr(u8)]
/// See <https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permission-type> /// See <https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permission-type>

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::utils::Snowflake; use crate::types::utils::Snowflake;
@ -6,7 +8,7 @@ use crate::types::utils::Snowflake;
/// See <https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object> /// See <https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object>
pub struct AuditLogEntry { pub struct AuditLogEntry {
pub target_id: Option<String>, pub target_id: Option<String>,
pub changes: Option<Vec<AuditLogChange>>, pub changes: Option<Vec<Arc<Mutex<AuditLogChange>>>>,
pub user_id: Option<Snowflake>, pub user_id: Option<Snowflake>,
pub id: Snowflake, pub id: Snowflake,
// to:do implement an enum for these types // to:do implement an enum for these types

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
@ -12,8 +14,8 @@ pub struct AutoModerationRule {
pub creator_id: Snowflake, pub creator_id: Snowflake,
pub event_type: AutoModerationRuleEventType, pub event_type: AutoModerationRuleEventType,
pub trigger_type: AutoModerationRuleTriggerType, pub trigger_type: AutoModerationRuleTriggerType,
pub trigger_metadata: AutoModerationRuleTriggerMetadata, pub trigger_metadata: Arc<Mutex<AutoModerationRuleTriggerMetadata>>,
pub actions: Vec<AutoModerationAction>, pub actions: Vec<Arc<Mutex<AutoModerationAction>>>,
pub enabled: bool, pub enabled: bool,
pub exempt_roles: Vec<Snowflake>, pub exempt_roles: Vec<Snowflake>,
pub exempt_channels: Vec<Snowflake>, pub exempt_channels: Vec<Snowflake>,
@ -90,7 +92,7 @@ pub enum AutoModerationRuleKeywordPresetType {
pub struct AutoModerationAction { pub struct AutoModerationAction {
#[serde(rename = "type")] #[serde(rename = "type")]
pub action_type: AutoModerationActionType, pub action_type: AutoModerationActionType,
pub metadata: Option<AutoModerationActionMetadata>, pub metadata: Option<Arc<Mutex<AutoModerationActionMetadata>>>,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)]

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use chorus_macros::Updateable; use chorus_macros::Updateable;
use chrono::Utc; use chrono::Utc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -10,7 +12,7 @@ use crate::types::{
utils::Snowflake, utils::Snowflake,
}; };
#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Updateable)] #[derive(Default, Debug, Serialize, Deserialize, Clone, Updateable)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// Represents a guild of private channel /// Represents a guild of private channel
/// ///
@ -46,7 +48,7 @@ pub struct Channel {
pub last_pin_timestamp: Option<String>, pub last_pin_timestamp: Option<String>,
pub managed: Option<bool>, pub managed: Option<bool>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub member: Option<ThreadMember>, pub member: Option<Arc<Mutex<ThreadMember>>>,
pub member_count: Option<i32>, pub member_count: Option<i32>,
pub message_count: Option<i32>, pub message_count: Option<i32>,
pub name: Option<String>, pub name: Option<String>,
@ -56,12 +58,12 @@ 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"))]
pub permission_overwrites: Option<Vec<PermissionOverwrite>>, pub permission_overwrites: Option<Vec<Arc<Mutex<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))]
pub recipients: Option<Vec<User>>, pub recipients: Option<Vec<Arc<Mutex<User>>>>,
pub rtc_region: Option<String>, pub rtc_region: Option<String>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub thread_metadata: Option<ThreadMetadata>, pub thread_metadata: Option<ThreadMetadata>,
@ -71,7 +73,41 @@ pub struct Channel {
pub video_quality_mode: Option<i32>, pub video_quality_mode: Option<i32>,
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] impl PartialEq for Channel {
fn eq(&self, other: &Self) -> bool {
self.application_id == other.application_id
&& self.bitrate == other.bitrate
&& self.channel_type == other.channel_type
&& self.created_at == other.created_at
&& self.default_auto_archive_duration == other.default_auto_archive_duration
&& self.default_forum_layout == other.default_forum_layout
&& self.default_sort_order == other.default_sort_order
&& self.default_thread_rate_limit_per_user == other.default_thread_rate_limit_per_user
&& self.flags == other.flags
&& self.guild_id == other.guild_id
&& self.icon == other.icon
&& self.id == other.id
&& self.last_message_id == other.last_message_id
&& self.last_pin_timestamp == other.last_pin_timestamp
&& self.managed == other.managed
&& self.member_count == other.member_count
&& self.message_count == other.message_count
&& self.name == other.name
&& self.nsfw == other.nsfw
&& self.owner_id == other.owner_id
&& self.parent_id == other.parent_id
&& self.permissions == other.permissions
&& self.position == other.position
&& self.rate_limit_per_user == other.rate_limit_per_user
&& self.rtc_region == other.rtc_region
&& self.topic == other.topic
&& self.total_message_sent == other.total_message_sent
&& self.user_limit == other.user_limit
&& self.video_quality_mode == other.video_quality_mode
}
}
#[derive(Debug, Deserialize, Serialize, Clone)]
/// A tag that can be applied to a thread in a [ChannelType::GuildForum] or [ChannelType::GuildMedia] channel. /// A tag that can be applied to a thread in a [ChannelType::GuildForum] or [ChannelType::GuildMedia] channel.
/// ///
/// # Reference /// # Reference
@ -112,7 +148,7 @@ pub struct ThreadMetadata {
pub create_timestamp: Option<String>, pub create_timestamp: Option<String>,
} }
#[derive(Default, Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] #[derive(Default, Debug, Deserialize, Serialize, Clone)]
/// # Reference /// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/channel#thread-member-object> /// See <https://discord-userdoccers.vercel.app/resources/channel#thread-member-object>
pub struct ThreadMember { pub struct ThreadMember {
@ -120,7 +156,7 @@ pub struct ThreadMember {
pub user_id: Option<Snowflake>, pub user_id: Option<Snowflake>,
pub join_timestamp: Option<String>, pub join_timestamp: Option<String>,
pub flags: Option<u64>, pub flags: Option<u64>,
pub member: Option<GuildMember>, pub member: Option<Arc<Mutex<GuildMember>>>,
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
@ -134,7 +170,7 @@ pub struct DefaultReaction {
pub emoji_name: Option<String>, pub emoji_name: Option<String>,
} }
#[derive(Default, Clone, Copy, Debug, Serialize_repr, Deserialize_repr, PartialEq, Eq)] #[derive(Default, Clone, Copy, Debug, Serialize_repr, Deserialize_repr, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[repr(i32)] #[repr(i32)]

View File

@ -1,9 +1,11 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::entities::User; use crate::types::entities::User;
use crate::types::Snowflake; use crate::types::Snowflake;
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Default)] #[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[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>
@ -15,7 +17,7 @@ pub struct Emoji {
#[cfg(not(feature = "sqlx"))] #[cfg(not(feature = "sqlx"))]
pub roles: Option<Vec<Snowflake>>, pub roles: Option<Vec<Snowflake>>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub user: Option<User>, pub user: Option<Arc<Mutex<User>>>,
pub require_colons: Option<bool>, pub require_colons: Option<bool>,
pub managed: Option<bool>, pub managed: Option<bool>,
pub animated: Option<bool>, pub animated: Option<bool>,

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
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};
@ -10,7 +12,7 @@ use crate::types::{
}; };
/// See <https://discord.com/developers/docs/resources/guild> /// See <https://discord.com/developers/docs/resources/guild>
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[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>,
@ -25,13 +27,13 @@ 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))]
pub channels: Option<Vec<Channel>>, pub channels: Option<Vec<Arc<Mutex<Channel>>>>,
pub default_message_notifications: Option<i32>, pub default_message_notifications: Option<i32>,
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))]
#[serde(default)] #[serde(default)]
pub emojis: Vec<Emoji>, pub emojis: Vec<Arc<Mutex<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"))]
pub features: Option<GuildFeaturesList>, pub features: Option<GuildFeaturesList>,
@ -40,7 +42,7 @@ pub struct Guild {
pub icon_hash: Option<String>, pub icon_hash: Option<String>,
pub id: Snowflake, pub id: Snowflake,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub invites: Option<Vec<GuildInvite>>, pub invites: Option<Vec<Arc<Mutex<GuildInvite>>>>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub joined_at: Option<String>, pub joined_at: Option<String>,
pub large: Option<bool>, pub large: Option<bool>,
@ -66,7 +68,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))]
pub roles: Option<Vec<RoleObject>>, pub roles: Option<Vec<Arc<Mutex<RoleObject>>>>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub rules_channel: Option<String>, pub rules_channel: Option<String>,
pub rules_channel_id: Option<Snowflake>, pub rules_channel_id: Option<Snowflake>,
@ -79,13 +81,13 @@ pub struct Guild {
pub vanity_url_code: Option<String>, pub vanity_url_code: Option<String>,
pub verification_level: Option<i32>, pub verification_level: Option<i32>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub voice_states: Option<Vec<VoiceState>>, pub voice_states: Option<Vec<Arc<Mutex<VoiceState>>>>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub webhooks: Option<Vec<Webhook>>, pub webhooks: Option<Vec<Arc<Mutex<Webhook>>>>,
#[cfg(feature = "sqlx")] #[cfg(feature = "sqlx")]
pub welcome_screen: Option<sqlx::types::Json<WelcomeScreenObject>>, pub welcome_screen: Option<sqlx::types::Json<WelcomeScreenObject>>,
#[cfg(not(feature = "sqlx"))] #[cfg(not(feature = "sqlx"))]
pub welcome_screen: Option<WelcomeScreenObject>, pub welcome_screen: Option<Arc<Mutex<WelcomeScreenObject>>>,
pub widget_channel_id: Option<Snowflake>, pub widget_channel_id: Option<Snowflake>,
pub widget_enabled: Option<bool>, pub widget_enabled: Option<bool>,
} }
@ -100,7 +102,7 @@ pub struct GuildBan {
} }
/// See <https://docs.spacebar.chat/routes/#cmp--schemas-invite> /// See <https://docs.spacebar.chat/routes/#cmp--schemas-invite>
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct GuildInvite { pub struct GuildInvite {
pub code: String, pub code: String,
@ -111,11 +113,11 @@ pub struct GuildInvite {
pub created_at: DateTime<Utc>, pub created_at: DateTime<Utc>,
pub expires_at: Option<DateTime<Utc>>, pub expires_at: Option<DateTime<Utc>>,
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub guild: Option<Guild>, pub guild: Option<Arc<Mutex<Guild>>>,
pub channel_id: Snowflake, pub channel_id: Snowflake,
pub channel: Option<Channel>, pub channel: Option<Arc<Mutex<Channel>>>,
pub inviter_id: Option<Snowflake>, pub inviter_id: Option<Snowflake>,
pub inviter: Option<User>, pub inviter: Option<Arc<Mutex<User>>>,
pub target_user_id: Option<Snowflake>, pub target_user_id: Option<Snowflake>,
pub target_user: Option<String>, pub target_user: Option<String>,
pub target_user_type: Option<i32>, pub target_user_type: Option<i32>,
@ -149,7 +151,7 @@ pub struct GuildScheduledEvent {
pub entity_type: GuildScheduledEventEntityType, pub entity_type: GuildScheduledEventEntityType,
pub entity_id: Option<Snowflake>, pub entity_id: Option<Snowflake>,
pub entity_metadata: Option<GuildScheduledEventEntityMetadata>, pub entity_metadata: Option<GuildScheduledEventEntityMetadata>,
pub creator: Option<User>, pub creator: Option<Arc<Mutex<User>>>,
pub user_count: Option<u64>, pub user_count: Option<u64>,
pub image: Option<String>, pub image: Option<String>,
} }

View File

@ -1,14 +1,16 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::{entities::PublicUser, Snowflake}; use crate::types::{entities::PublicUser, Snowflake};
#[derive(Debug, Deserialize, Default, Serialize, Clone, PartialEq, Eq)] #[derive(Debug, Deserialize, Default, Serialize, Clone)]
/// Represents a participating user in a guild. /// Represents a participating user in a guild.
/// ///
/// # Reference /// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/guild#guild-member-object> /// See <https://discord-userdoccers.vercel.app/resources/guild#guild-member-object>
pub struct GuildMember { pub struct GuildMember {
pub user: Option<PublicUser>, pub user: Option<Arc<Mutex<PublicUser>>>,
pub nick: Option<String>, pub nick: Option<String>,
pub avatar: Option<String>, pub avatar: Option<String>,
pub roles: Vec<Snowflake>, pub roles: Vec<Snowflake>,

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -21,14 +23,14 @@ pub struct Integration {
pub expire_behaviour: Option<u8>, pub expire_behaviour: Option<u8>,
pub expire_grace_period: Option<u16>, pub expire_grace_period: Option<u16>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub user: Option<User>, pub user: Option<Arc<Mutex<User>>>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub account: IntegrationAccount, pub account: IntegrationAccount,
pub synced_at: Option<DateTime<Utc>>, pub synced_at: Option<DateTime<Utc>>,
pub subscriber_count: Option<f64>, pub subscriber_count: Option<f64>,
pub revoked: Option<bool>, pub revoked: Option<bool>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub application: Option<Application>, pub application: Option<Arc<Mutex<Application>>>,
pub scopes: Option<Vec<String>>, pub scopes: Option<Vec<String>>,
} }

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -68,7 +70,7 @@ pub enum NSFWLevel {
/// See <https://discord-userdoccers.vercel.app/resources/invite#invite-stage-instance-object> /// See <https://discord-userdoccers.vercel.app/resources/invite#invite-stage-instance-object>
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct InviteStageInstance { pub struct InviteStageInstance {
pub members: Vec<GuildMember>, pub members: Vec<Arc<Mutex<GuildMember>>>,
pub participant_count: i32, pub participant_count: i32,
pub speaker_count: i32, pub speaker_count: i32,
pub topic: String, pub topic: String,

View File

@ -8,7 +8,7 @@ use crate::types::{
utils::Snowflake, utils::Snowflake,
}; };
#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq)] #[derive(Debug, Serialize, Deserialize, Default, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// Represents a message sent in a channel. /// Represents a message sent in a channel.
/// ///
@ -77,7 +77,7 @@ pub struct MessageReference {
pub fail_if_not_exists: Option<bool>, pub fail_if_not_exists: Option<bool>,
} }
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MessageInteraction { pub struct MessageInteraction {
pub id: Snowflake, pub id: Snowflake,
#[serde(rename = "type")] #[serde(rename = "type")]
@ -112,7 +112,7 @@ pub struct ChannelMention {
name: String, name: String,
} }
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Embed { pub struct Embed {
title: Option<String>, title: Option<String>,
#[serde(rename = "type")] #[serde(rename = "type")]
@ -182,7 +182,7 @@ pub struct EmbedField {
inline: Option<bool>, inline: Option<bool>,
} }
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Reaction { pub struct Reaction {
pub count: u32, pub count: u32,
pub burst_count: u32, pub burst_count: u32,

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
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};
@ -6,17 +8,26 @@ use crate::types::Snowflake;
use super::PublicUser; use super::PublicUser;
#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialEq, Eq)] #[derive(Debug, Deserialize, Serialize, Clone, Default)]
/// See <https://discord-userdoccers.vercel.app/resources/user#relationship-structure> /// See <https://discord-userdoccers.vercel.app/resources/user#relationship-structure>
pub struct Relationship { pub struct Relationship {
pub id: Snowflake, pub id: Snowflake,
#[serde(rename = "type")] #[serde(rename = "type")]
pub relationship_type: RelationshipType, pub relationship_type: RelationshipType,
pub nickname: Option<String>, pub nickname: Option<String>,
pub user: PublicUser, pub user: Arc<Mutex<PublicUser>>,
pub since: Option<DateTime<Utc>>, pub since: Option<DateTime<Utc>>,
} }
impl PartialEq for Relationship {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.relationship_type == other.relationship_type
&& self.since == other.since
&& self.nickname == other.nickname
}
}
#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default, Eq, PartialEq)] #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default, Eq, PartialEq)]
#[repr(u8)] #[repr(u8)]
/// See <https://discord-userdoccers.vercel.app/resources/user#relationship-type> /// See <https://discord-userdoccers.vercel.app/resources/user#relationship-type>

View File

@ -34,7 +34,7 @@ pub struct RoleSubscriptionData {
pub is_renewal: bool, pub is_renewal: bool,
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash)]
/// See <https://discord.com/developers/docs/topics/permissions#role-object-role-tags-structure> /// See <https://discord.com/developers/docs/topics/permissions#role-object-role-tags-structure>
pub struct RoleTags { pub struct RoleTags {
#[serde(default)] #[serde(default)]
@ -53,7 +53,7 @@ pub struct RoleTags {
} }
bitflags! { bitflags! {
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[derive(Debug, Default, Clone, Hash, Serialize, Deserialize, PartialEq, Eq)]
/// Permissions limit what users of certain roles can do on a Guild to Guild basis. /// Permissions limit what users of certain roles can do on a Guild to Guild basis.
/// ///
/// # Reference: /// # Reference:

View File

@ -1,8 +1,10 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::{entities::User, utils::Snowflake}; use crate::types::{entities::User, utils::Snowflake};
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// Represents a sticker that can be sent in messages. /// Represents a sticker that can be sent in messages.
/// ///
@ -22,7 +24,7 @@ pub struct Sticker {
pub available: Option<bool>, pub available: Option<bool>,
pub guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub user: Option<User>, pub user: Option<Arc<Mutex<User>>>,
pub sort_value: Option<u8>, pub sort_value: Option<u8>,
} }

View File

@ -1,9 +1,11 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::entities::User; use crate::types::entities::User;
use crate::types::Snowflake; use crate::types::Snowflake;
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct Team { pub struct Team {
pub icon: Option<String>, pub icon: Option<String>,
@ -14,10 +16,10 @@ pub struct Team {
pub owner_user_id: Snowflake, pub owner_user_id: Snowflake,
} }
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub struct TeamMember { pub struct TeamMember {
pub membership_state: u8, pub membership_state: u8,
pub permissions: Vec<String>, pub permissions: Vec<String>,
pub team_id: Snowflake, pub team_id: Snowflake,
pub user: User, pub user: Arc<Mutex<User>>,
} }

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -7,7 +9,7 @@ use crate::types::{
}; };
/// See <https://docs.spacebar.chat/routes/#cmp--schemas-template> /// See <https://docs.spacebar.chat/routes/#cmp--schemas-template>
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct GuildTemplate { pub struct GuildTemplate {
pub code: String, pub code: String,
@ -16,13 +18,13 @@ pub struct GuildTemplate {
pub usage_count: Option<u64>, pub usage_count: Option<u64>,
pub creator_id: Snowflake, pub creator_id: Snowflake,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub creator: User, pub creator: Arc<Mutex<User>>,
pub created_at: DateTime<Utc>, pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>, pub updated_at: DateTime<Utc>,
pub source_guild_id: Snowflake, pub source_guild_id: Snowflake,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub source_guild: Vec<Guild>, pub source_guild: Vec<Arc<Mutex<Guild>>>,
// Unsure how a {recursive: Guild} looks like, might be a Vec? // Unsure how a {recursive: Guild} looks like, might be a Vec?
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub serialized_source_guild: Vec<Guild>, pub serialized_source_guild: Vec<Arc<Mutex<Guild>>>,
} }

View File

@ -91,7 +91,7 @@ impl From<User> for PublicUser {
const CUSTOM_USER_FLAG_OFFSET: u64 = 1 << 32; const CUSTOM_USER_FLAG_OFFSET: u64 = 1 << 32;
bitflags::bitflags! { bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
pub struct UserFlags: u64 { pub struct UserFlags: u64 {
const DISCORD_EMPLOYEE = 1 << 0; const DISCORD_EMPLOYEE = 1 << 0;

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use chrono::{serde::ts_milliseconds_option, Utc}; use chrono::{serde::ts_milliseconds_option, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -28,7 +30,7 @@ pub enum UserTheme {
Light, Light,
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct UserSettings { pub struct UserSettings {
pub afk_timeout: u16, pub afk_timeout: u16,
@ -73,7 +75,7 @@ pub struct UserSettings {
#[cfg(not(feature = "sqlx"))] #[cfg(not(feature = "sqlx"))]
pub restricted_guilds: Vec<String>, pub restricted_guilds: Vec<String>,
pub show_current_game: bool, pub show_current_game: bool,
pub status: UserStatus, pub status: Arc<Mutex<UserStatus>>,
pub stream_notifications_enabled: bool, pub stream_notifications_enabled: bool,
pub theme: UserTheme, pub theme: UserTheme,
pub timezone_offset: i16, pub timezone_offset: i16,
@ -109,7 +111,7 @@ impl Default for UserSettings {
render_reactions: true, render_reactions: true,
restricted_guilds: Default::default(), restricted_guilds: Default::default(),
show_current_game: true, show_current_game: true,
status: UserStatus::Online, status: Arc::new(Mutex::new(UserStatus::Online)),
stream_notifications_enabled: false, stream_notifications_enabled: false,
theme: UserTheme::Dark, theme: UserTheme::Dark,
timezone_offset: 0, timezone_offset: 0,
@ -138,7 +140,7 @@ impl Default for FriendSourceFlags {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GuildFolder { pub struct GuildFolder {
pub color: u32, pub color: u32,
pub guild_ids: Vec<String>, pub guild_ids: Vec<String>,
@ -149,5 +151,5 @@ pub struct GuildFolder {
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct LoginResult { pub struct LoginResult {
pub token: String, pub token: String,
pub settings: UserSettings, pub settings: Arc<Mutex<UserSettings>>,
} }

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -7,14 +9,14 @@ use crate::types::{
}; };
/// See <https://docs.spacebar.chat/routes/#cmp--schemas-voicestate> /// See <https://docs.spacebar.chat/routes/#cmp--schemas-voicestate>
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct VoiceState { pub struct VoiceState {
pub guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
pub guild: Option<Guild>, pub guild: Option<Guild>,
pub channel_id: Option<Snowflake>, pub channel_id: Option<Snowflake>,
pub user_id: Snowflake, pub user_id: Snowflake,
pub member: Option<GuildMember>, pub member: Option<Arc<Mutex<GuildMember>>>,
pub session_id: Snowflake, pub session_id: Snowflake,
pub token: Option<String>, pub token: Option<String>,
pub deaf: bool, pub deaf: bool,

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::{ use crate::types::{
@ -6,7 +8,7 @@ use crate::types::{
}; };
/// See <https://docs.spacebar.chat/routes/#cmp--schemas-webhook> /// See <https://docs.spacebar.chat/routes/#cmp--schemas-webhook>
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[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,
@ -20,10 +22,10 @@ pub struct Webhook {
pub application_id: Snowflake, pub application_id: Snowflake,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub user: Option<User>, pub user: Option<Arc<Mutex<User>>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub source_guild: Option<Guild>, pub source_guild: Option<Arc<Mutex<Guild>>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>, pub url: Option<String>,
} }

View File

@ -59,8 +59,9 @@ async fn modify_channel() {
PermissionFlags::MANAGE_CHANNELS, PermissionFlags::MANAGE_CHANNELS,
PermissionFlags::MANAGE_MESSAGES, PermissionFlags::MANAGE_MESSAGES,
])); ]));
let user_id: types::Snowflake = bundle.user.object.lock().unwrap().id;
let permission_override = PermissionOverwrite { let permission_override = PermissionOverwrite {
id: bundle.user.object.id, id: user_id,
overwrite_type: "1".to_string(), overwrite_type: "1".to_string(),
allow: permission_override, allow: permission_override,
deny: "0".to_string(), deny: "0".to_string(),
@ -143,7 +144,7 @@ async fn create_dm() {
let other_user = bundle.create_user("integrationtestuser2").await; let other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user; let user = &mut bundle.user;
let private_channel_create_schema = PrivateChannelCreateSchema { let private_channel_create_schema = PrivateChannelCreateSchema {
recipients: Some(Vec::from([other_user.object.id])), recipients: Some(Vec::from([other_user.object.lock().unwrap().id])),
access_tokens: None, access_tokens: None,
nicks: None, nicks: None,
}; };
@ -153,26 +154,47 @@ async fn create_dm() {
.unwrap(); .unwrap();
assert!(dm_channel.recipients.is_some()); assert!(dm_channel.recipients.is_some());
assert_eq!( assert_eq!(
dm_channel.recipients.as_ref().unwrap().get(0).unwrap().id, dm_channel
other_user.object.id .recipients
.as_ref()
.unwrap()
.get(0)
.unwrap()
.lock()
.unwrap()
.id
.clone(),
other_user.object.lock().unwrap().id
); );
assert_eq!( assert_eq!(
dm_channel.recipients.as_ref().unwrap().get(1).unwrap().id, dm_channel
user.object.id .recipients
.as_ref()
.unwrap()
.get(1)
.unwrap()
.lock()
.unwrap()
.id
.clone(),
user.object.lock().unwrap().id.clone()
); );
common::teardown(bundle).await; common::teardown(bundle).await;
} }
// #[tokio::test] // #[tokio::test]
// This test currently is broken due to an issue with the Spacebar Server. // TODO This test currently is broken due to an issue with the Spacebar Server.
#[allow(dead_code)] #[allow(dead_code)]
async fn remove_add_person_from_to_dm() { async fn remove_add_person_from_to_dm() {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await; let mut other_user = bundle.create_user("integrationtestuser2").await;
let mut third_user = bundle.create_user("integrationtestuser3").await; let mut third_user = bundle.create_user("integrationtestuser3").await;
let third_user_id = third_user.object.lock().unwrap().id;
let other_user_id = other_user.object.lock().unwrap().id;
let user_id = bundle.user.object.lock().unwrap().id;
let user = &mut bundle.user; let user = &mut bundle.user;
let private_channel_create_schema = PrivateChannelCreateSchema { let private_channel_create_schema = PrivateChannelCreateSchema {
recipients: Some(Vec::from([other_user.object.id, third_user.object.id])), recipients: Some(Vec::from([other_user_id, third_user_id])),
access_tokens: None, access_tokens: None,
nicks: None, nicks: None,
}; };
@ -181,36 +203,52 @@ async fn remove_add_person_from_to_dm() {
.await .await
.unwrap(); // Creates the Channel and stores the response Channel object .unwrap(); // Creates the Channel and stores the response Channel object
dm_channel dm_channel
.remove_channel_recipient(other_user.object.id, user) .remove_channel_recipient(other_user_id, user)
.await .await
.unwrap(); .unwrap();
assert!(dm_channel.recipients.as_ref().unwrap().get(1).is_none()); assert!(dm_channel.recipients.as_ref().unwrap().get(1).is_none());
other_user other_user
.modify_user_relationship(user.object.id, RelationshipType::Friends) .modify_user_relationship(user_id, RelationshipType::Friends)
.await .await
.unwrap(); .unwrap();
user.modify_user_relationship(other_user.object.id, RelationshipType::Friends) user.modify_user_relationship(other_user_id, RelationshipType::Friends)
.await .await
.unwrap(); .unwrap();
third_user third_user
.modify_user_relationship(user.object.id, RelationshipType::Friends) .modify_user_relationship(user_id, RelationshipType::Friends)
.await .await
.unwrap(); .unwrap();
user.modify_user_relationship(third_user.object.id, RelationshipType::Friends) user.modify_user_relationship(third_user_id, RelationshipType::Friends)
.await .await
.unwrap(); .unwrap();
// Users 1-2 and 1-3 are now friends // Users 1-2 and 1-3 are now friends
dm_channel dm_channel
.add_channel_recipient(other_user.object.id, user, None) .add_channel_recipient(other_user_id, user, None)
.await .await
.unwrap(); .unwrap();
assert!(dm_channel.recipients.is_some()); assert!(dm_channel.recipients.is_some());
assert_eq!( assert_eq!(
dm_channel.recipients.as_ref().unwrap().get(0).unwrap().id, dm_channel
other_user.object.id .recipients
.as_ref()
.unwrap()
.get(0)
.unwrap()
.lock()
.unwrap()
.id,
other_user_id
); );
assert_eq!( assert_eq!(
dm_channel.recipients.as_ref().unwrap().get(1).unwrap().id, dm_channel
user.object.id .recipients
.as_ref()
.unwrap()
.get(1)
.unwrap()
.lock()
.unwrap()
.id,
user_id
); );
} }

View File

@ -7,7 +7,7 @@ async fn add_remove_role() -> ChorusResult<()> {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let guild = bundle.guild.id; let guild = bundle.guild.id;
let role = bundle.role.id; let role = bundle.role.id;
let member_id = bundle.user.object.id; let member_id = bundle.user.object.lock().unwrap().id;
GuildMember::add_role(&mut bundle.user, guild, member_id, role).await?; GuildMember::add_role(&mut bundle.user, guild, member_id, role).await?;
let member = GuildMember::get(&mut bundle.user, guild, member_id) let member = GuildMember::get(&mut bundle.user, guild, member_id)
.await .await

View File

@ -7,15 +7,18 @@ async fn test_get_mutual_relationships() {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await; let mut other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user; let user = &mut bundle.user;
let username = user.object.lock().unwrap().username.clone();
let discriminator = user.object.lock().unwrap().discriminator.clone();
let other_user_id: types::Snowflake = other_user.object.lock().unwrap().id;
let friend_request_schema = types::FriendRequestSendSchema { let friend_request_schema = types::FriendRequestSendSchema {
username: user.object.username.clone(), username,
discriminator: Some(user.object.discriminator.clone()), discriminator: Some(discriminator),
}; };
let _ = other_user.send_friend_request(friend_request_schema).await; other_user
let relationships = user .send_friend_request(friend_request_schema)
.get_mutual_relationships(other_user.object.id)
.await .await
.unwrap(); .unwrap();
let relationships = user.get_mutual_relationships(other_user_id).await.unwrap();
println!("{:?}", relationships); println!("{:?}", relationships);
common::teardown(bundle).await common::teardown(bundle).await
} }
@ -25,16 +28,21 @@ async fn test_get_relationships() {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await; let mut other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user; let user = &mut bundle.user;
let username = user.object.lock().unwrap().username.clone();
let discriminator = user.object.lock().unwrap().discriminator.clone();
let friend_request_schema = types::FriendRequestSendSchema { let friend_request_schema = types::FriendRequestSendSchema {
username: user.object.username.clone(), username,
discriminator: Some(user.object.discriminator.clone()), discriminator: Some(discriminator),
}; };
other_user other_user
.send_friend_request(friend_request_schema) .send_friend_request(friend_request_schema)
.await .await
.unwrap(); .unwrap();
let relationships = user.get_relationships().await.unwrap(); let relationships = user.get_relationships().await.unwrap();
assert_eq!(relationships.get(0).unwrap().id, other_user.object.id); assert_eq!(
relationships.get(0).unwrap().id,
other_user.object.lock().unwrap().id
);
common::teardown(bundle).await common::teardown(bundle).await
} }
@ -43,23 +51,33 @@ async fn test_modify_relationship_friends() {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await; let mut other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user; let user = &mut bundle.user;
let _ = other_user let user_id: types::Snowflake = user.object.lock().unwrap().id;
.modify_user_relationship(user.object.id, types::RelationshipType::Friends) let other_user_id: types::Snowflake = other_user.object.lock().unwrap().id;
.await;
other_user
.modify_user_relationship(user_id, types::RelationshipType::Friends)
.await
.unwrap();
let relationships = user.get_relationships().await.unwrap(); let relationships = user.get_relationships().await.unwrap();
assert_eq!(relationships.get(0).unwrap().id, other_user.object.id); assert_eq!(
relationships.get(0).unwrap().id,
other_user.object.lock().unwrap().id
);
assert_eq!( assert_eq!(
relationships.get(0).unwrap().relationship_type, relationships.get(0).unwrap().relationship_type,
RelationshipType::Incoming RelationshipType::Incoming
); );
let relationships = other_user.get_relationships().await.unwrap(); let relationships = other_user.get_relationships().await.unwrap();
assert_eq!(relationships.get(0).unwrap().id, user.object.id); assert_eq!(
relationships.get(0).unwrap().id,
user.object.lock().unwrap().id
);
assert_eq!( assert_eq!(
relationships.get(0).unwrap().relationship_type, relationships.get(0).unwrap().relationship_type,
RelationshipType::Outgoing RelationshipType::Outgoing
); );
let _ = user let _ = user
.modify_user_relationship(other_user.object.id, RelationshipType::Friends) .modify_user_relationship(other_user_id, RelationshipType::Friends)
.await; .await;
assert_eq!( assert_eq!(
other_user other_user
@ -71,7 +89,7 @@ async fn test_modify_relationship_friends() {
.relationship_type, .relationship_type,
RelationshipType::Friends RelationshipType::Friends
); );
let _ = user.remove_relationship(other_user.object.id).await; let _ = user.remove_relationship(other_user_id).await;
assert_eq!( assert_eq!(
other_user.get_relationships().await.unwrap(), other_user.get_relationships().await.unwrap(),
Vec::<Relationship>::new() Vec::<Relationship>::new()
@ -84,18 +102,24 @@ async fn test_modify_relationship_block() {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await; let mut other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user; let user = &mut bundle.user;
let _ = other_user let user_id: types::Snowflake = user.object.lock().unwrap().id;
.modify_user_relationship(user.object.id, types::RelationshipType::Blocked)
.await; other_user
.modify_user_relationship(user_id, types::RelationshipType::Blocked)
.await
.unwrap();
let relationships = user.get_relationships().await.unwrap(); let relationships = user.get_relationships().await.unwrap();
assert_eq!(relationships, Vec::<Relationship>::new()); assert_eq!(relationships, Vec::<Relationship>::new());
let relationships = other_user.get_relationships().await.unwrap(); let relationships = other_user.get_relationships().await.unwrap();
assert_eq!(relationships.get(0).unwrap().id, user.object.id); assert_eq!(
relationships.get(0).unwrap().id,
user.object.lock().unwrap().id
);
assert_eq!( assert_eq!(
relationships.get(0).unwrap().relationship_type, relationships.get(0).unwrap().relationship_type,
RelationshipType::Blocked RelationshipType::Blocked
); );
let _ = other_user.remove_relationship(user.object.id).await; other_user.remove_relationship(user_id).await.unwrap();
assert_eq!( assert_eq!(
other_user.get_relationships().await.unwrap(), other_user.get_relationships().await.unwrap(),
Vec::<Relationship>::new() Vec::<Relationship>::new()