Skip to content

Commit

Permalink
Components and Composites (#175)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bitfl0wer authored Aug 4, 2023
2 parents 80dac3b + f74214e commit a51d524
Show file tree
Hide file tree
Showing 28 changed files with 284 additions and 135 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Generated by Cargo
# will have compiled files and executables
/target/
/**/target/

# These are backup files generated by rustfmt
**/*.rs.bk
Expand Down
26 changes: 17 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ backend = ["poem", "sqlx"]
client = []

[dependencies]
tokio = {version = "1.29.1", features = ["macros"]}
serde = {version = "1.0.171", features = ["derive"]}
serde_json = {version= "1.0.103", features = ["raw_value"]}
tokio = { version = "1.29.1", features = ["macros"] }
serde = { version = "1.0.171", features = ["derive", "rc"] }
serde_json = { version = "1.0.103", features = ["raw_value"] }
serde-aux = "4.2.0"
serde_with = "3.0.0"
serde_repr = "0.1.14"
reqwest = {version = "0.11.18", features = ["multipart"]}
reqwest = { version = "0.11.18", features = ["multipart"] }
url = "2.4.0"
chrono = {version = "0.4.26", features = ["serde"]}
chrono = { version = "0.4.26", features = ["serde"] }
regex = "1.9.1"
custom_error = "1.9.2"
native-tls = "0.2.11"
tokio-tungstenite = {version = "0.19.0", features = ["native-tls"]}
tokio-tungstenite = { version = "0.19.0", features = ["native-tls"] }
futures-util = "0.3.28"
http = "0.2.9"
openssl = "0.10.55"
Expand All @@ -31,14 +31,22 @@ hostname = "0.3.1"
bitflags = { version = "2.3.3", features = ["serde"] }
lazy_static = "1.4.0"
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"
jsonwebtoken = "8.3.0"
log = "0.4.19"
async-trait = "0.1.71"
chorus-macros = {path = "chorus-macros"}
chorus-macros = { path = "chorus-macros" }

[dev-dependencies]
tokio = {version = "1.29.1", features = ["full"]}
tokio = { version = "1.29.1", features = ["full"] }
lazy_static = "1.4.0"
rusty-hook = "0.11.2"
3 changes: 2 additions & 1 deletion src/api/auth/login.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::{Arc, Mutex};

use reqwest::Client;
use serde_json::to_string;
Expand Down Expand Up @@ -45,7 +46,7 @@ impl Instance {
login_result.token,
self.clone_limits_if_some(),
login_result.settings,
object,
Arc::new(Mutex::new(object)),
gateway,
);
Ok(user)
Expand Down
5 changes: 3 additions & 2 deletions src/api/auth/register.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::sync::{Arc, Mutex};
use std::{cell::RefCell, rc::Rc};

use reqwest::Client;
Expand Down Expand Up @@ -51,8 +52,8 @@ impl Instance {
Rc::new(RefCell::new(self.clone())),
token.clone(),
self.clone_limits_if_some(),
settings,
user_object,
Arc::new(Mutex::new(settings)),
Arc::new(Mutex::new(user_object)),
gateway,
);
Ok(user)
Expand Down
3 changes: 2 additions & 1 deletion src/api/users/users.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::sync::{Arc, Mutex};
use std::{cell::RefCell, rc::Rc};

use reqwest::Client;
Expand Down Expand Up @@ -59,7 +60,7 @@ impl UserMeta {
.deserialize_response::<User>(self)
.await
.unwrap();
let _ = std::mem::replace(&mut self.object, user_updated.clone());
self.object = Arc::new(Mutex::new(user_updated.clone()));
Ok(user_updated)
}

Expand Down
13 changes: 7 additions & 6 deletions src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use std::rc::Rc;
use std::sync::{Arc, Mutex};

use reqwest::Client;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -90,8 +91,8 @@ pub struct UserMeta {
pub belongs_to: Rc<RefCell<Instance>>,
pub token: String,
pub limits: Option<HashMap<LimitType, Limit>>,
pub settings: UserSettings,
pub object: User,
pub settings: Arc<Mutex<UserSettings>>,
pub object: Arc<Mutex<User>>,
pub gateway: GatewayHandle,
}

Expand All @@ -113,8 +114,8 @@ impl UserMeta {
belongs_to: Rc<RefCell<Instance>>,
token: String,
limits: Option<HashMap<LimitType, Limit>>,
settings: UserSettings,
object: User,
settings: Arc<Mutex<UserSettings>>,
object: Arc<Mutex<User>>,
gateway: GatewayHandle,
) -> UserMeta {
UserMeta {
Expand All @@ -133,8 +134,8 @@ impl UserMeta {
/// need to make a RateLimited request. To use the [`GatewayHandle`], you will have to identify
/// first.
pub(crate) async fn shell(instance: Rc<RefCell<Instance>>, token: String) -> UserMeta {
let settings = UserSettings::default();
let object = User::default();
let settings = Arc::new(Mutex::new(UserSettings::default()));
let object = Arc::new(Mutex::new(User::default()));
let wss_url = instance.borrow().urls.wss.clone();
// Dummy gateway object
let gateway = Gateway::new(wss_url).await.unwrap();
Expand Down
34 changes: 18 additions & 16 deletions src/types/entities/application.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};

use bitflags::bitflags;
use serde::{Deserialize, Serialize};
use serde_json::Value;
Expand All @@ -6,7 +8,7 @@ use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::types::utils::Snowflake;
use crate::types::{Team, User};

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// # Reference
/// See <https://discord.com/developers/docs/resources/application#application-resource>
Expand All @@ -25,7 +27,7 @@ pub struct Application {
pub bot_require_code_grant: bool,
pub verify_key: String,
#[cfg_attr(feature = "sqlx", sqlx(skip))]
pub owner: User,
pub owner: Arc<Mutex<User>>,
pub flags: u64,
#[cfg(feature = "sqlx")]
pub redirect_uris: Option<sqlx::types::Json<Vec<String>>>,
Expand All @@ -47,7 +49,7 @@ pub struct Application {
#[cfg(feature = "sqlx")]
pub install_params: Option<sqlx::types::Json<InstallParams>>,
#[cfg(not(feature = "sqlx"))]
pub install_params: Option<InstallParams>,
pub install_params: Option<Arc<Mutex<InstallParams>>>,
pub terms_of_service_url: Option<String>,
pub privacy_policy_url: Option<String>,
#[cfg_attr(feature = "sqlx", sqlx(skip))]
Expand Down Expand Up @@ -103,7 +105,7 @@ pub struct InstallParams {
}

bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
/// # Reference
/// See <https://discord.com/developers/docs/resources/application#application-object-application-flags>
pub struct ApplicationFlags: u64 {
Expand Down Expand Up @@ -132,18 +134,18 @@ bitflags! {
}
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
/// # Reference
/// See <https://discord.com/developers/docs/interactions/application-commands#application-command-object>
pub struct ApplicationCommand {
pub id: Snowflake,
pub application_id: Snowflake,
pub name: 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
/// See <https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure>
pub struct ApplicationCommandOption {
Expand All @@ -152,7 +154,7 @@ pub struct ApplicationCommandOption {
pub description: String,
pub required: bool,
pub choices: Vec<ApplicationCommandOptionChoice>,
pub options: Vec<ApplicationCommandOption>,
pub options: Arc<Mutex<Vec<ApplicationCommandOption>>>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
Expand All @@ -161,7 +163,7 @@ pub struct ApplicationCommandOptionChoice {
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))]
#[repr(i32)]
/// # Reference
Expand All @@ -184,27 +186,27 @@ pub enum ApplicationCommandOptionType {
Attachment = 11,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApplicationCommandInteractionData {
pub id: Snowflake,
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 name: String,
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>
pub struct GuildApplicationCommandPermissions {
pub id: Snowflake,
pub application_id: Snowflake,
pub guild_id: Snowflake,
pub permissions: Vec<ApplicationCommandPermission>,
pub permissions: Vec<Arc<Mutex<ApplicationCommandPermission>>>,
}

#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
Expand All @@ -217,7 +219,7 @@ pub struct ApplicationCommandPermission {
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")]
#[repr(u8)]
/// See <https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permission-type>
Expand Down
4 changes: 3 additions & 1 deletion src/types/entities/audit_log.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};

use serde::{Deserialize, Serialize};

use crate::types::utils::Snowflake;
Expand All @@ -6,7 +8,7 @@ use crate::types::utils::Snowflake;
/// See <https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object>
pub struct AuditLogEntry {
pub target_id: Option<String>,
pub changes: Option<Vec<AuditLogChange>>,
pub changes: Option<Vec<Arc<Mutex<AuditLogChange>>>>,
pub user_id: Option<Snowflake>,
pub id: Snowflake,
// to:do implement an enum for these types
Expand Down
8 changes: 5 additions & 3 deletions src/types/entities/auto_moderation.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};

use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};

Expand All @@ -12,8 +14,8 @@ pub struct AutoModerationRule {
pub creator_id: Snowflake,
pub event_type: AutoModerationRuleEventType,
pub trigger_type: AutoModerationRuleTriggerType,
pub trigger_metadata: AutoModerationRuleTriggerMetadata,
pub actions: Vec<AutoModerationAction>,
pub trigger_metadata: Arc<Mutex<AutoModerationRuleTriggerMetadata>>,
pub actions: Vec<Arc<Mutex<AutoModerationAction>>>,
pub enabled: bool,
pub exempt_roles: Vec<Snowflake>,
pub exempt_channels: Vec<Snowflake>,
Expand Down Expand Up @@ -90,7 +92,7 @@ pub enum AutoModerationRuleKeywordPresetType {
pub struct AutoModerationAction {
#[serde(rename = "type")]
pub action_type: AutoModerationActionType,
pub metadata: Option<AutoModerationActionMetadata>,
pub metadata: Option<Arc<Mutex<AutoModerationActionMetadata>>>,
}

#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)]
Expand Down
Loading

0 comments on commit a51d524

Please sign in to comment.