From c7af410b2ba8cc3023c7b68bb6cce970864c8276 Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Fri, 19 Apr 2024 17:13:36 +0200 Subject: [PATCH 001/162] add WebSocketEvent macro derive, bump chorus-macros to 0.3.0 (#490) * feat: add WebSocketEvent derive, bump to 0.2.1 * change license, version of macros --- chorus-macros/Cargo.lock | 2 +- chorus-macros/Cargo.toml | 4 ++-- chorus-macros/src/lib.rs | 12 ++++++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/chorus-macros/Cargo.lock b/chorus-macros/Cargo.lock index 17404a2d..9f146197 100644 --- a/chorus-macros/Cargo.lock +++ b/chorus-macros/Cargo.lock @@ -15,7 +15,7 @@ dependencies = [ [[package]] name = "chorus-macros" -version = "0.1.0" +version = "0.2.1" dependencies = [ "async-trait", "quote", diff --git a/chorus-macros/Cargo.toml b/chorus-macros/Cargo.toml index 272d99f5..530ad7ef 100644 --- a/chorus-macros/Cargo.toml +++ b/chorus-macros/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "chorus-macros" -version = "0.2.0" +version = "0.3.0" edition = "2021" -license = "AGPL-3.0" +license = "MPL-2.0" description = "Macros for the chorus crate." [lib] diff --git a/chorus-macros/src/lib.rs b/chorus-macros/src/lib.rs index ba8f27e6..436fd68c 100644 --- a/chorus-macros/src/lib.rs +++ b/chorus-macros/src/lib.rs @@ -6,6 +6,18 @@ use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, Data, DeriveInput, Field, Fields, FieldsNamed}; +#[proc_macro_derive(WebSocketEvent)] +pub fn websocket_event_macro_derive(input: TokenStream) -> TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + + let name = &ast.ident; + + quote! { + impl WebSocketEvent for #name {} + } + .into() +} + #[proc_macro_derive(Updateable)] pub fn updateable_macro_derive(input: TokenStream) -> TokenStream { let ast: syn::DeriveInput = syn::parse(input).unwrap(); From 319748c0a7a224b41541dc25648b64c777720936 Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Sun, 28 Apr 2024 08:32:05 +0200 Subject: [PATCH 002/162] Use WebSocketEvent derive instead of impl WebSocketEvent for .. (#491) use derive macro instead of manual impl blocks --- Cargo.lock | 4 +- Cargo.toml | 2 +- src/errors.rs | 12 +-- src/types/events/application.rs | 5 +- src/types/events/auto_moderation.rs | 23 ++--- src/types/events/call.rs | 16 ++-- src/types/events/channel.rs | 19 ++--- src/types/events/guild.rs | 84 +++++-------------- src/types/events/heartbeat.rs | 7 +- src/types/events/hello.rs | 8 +- src/types/events/identify.rs | 6 +- src/types/events/integration.rs | 12 +-- src/types/events/interaction.rs | 4 +- src/types/events/invalid_session.rs | 3 +- src/types/events/invite.rs | 8 +- src/types/events/lazy_request.rs | 4 +- src/types/events/message.rs | 45 +++------- src/types/events/mod.rs | 6 +- src/types/events/passive_update.rs | 3 +- src/types/events/presence.rs | 5 +- src/types/events/ready.rs | 8 +- src/types/events/reconnect.rs | 3 +- src/types/events/relationship.rs | 7 +- src/types/events/request_members.rs | 3 +- src/types/events/resume.rs | 3 +- src/types/events/session.rs | 4 +- src/types/events/stage_instance.rs | 12 +-- src/types/events/thread.rs | 23 ++--- src/types/events/user.rs | 8 +- src/types/events/voice.rs | 11 +-- .../events/voice_gateway/client_connect.rs | 8 +- .../events/voice_gateway/client_disconnect.rs | 4 +- src/types/events/voice_gateway/hello.rs | 4 +- src/types/events/voice_gateway/identify.rs | 4 +- .../events/voice_gateway/media_sink_wants.rs | 4 +- src/types/events/voice_gateway/mod.rs | 4 +- src/types/events/voice_gateway/ready.rs | 4 +- .../voice_gateway/session_description.rs | 8 +- src/types/events/voice_gateway/speaking.rs | 5 +- .../events/voice_gateway/ssrc_definition.rs | 4 +- .../voice_gateway/voice_backend_version.rs | 4 +- src/types/events/webhooks.rs | 8 +- 42 files changed, 135 insertions(+), 284 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 456ae439..46b87f96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -252,9 +252,9 @@ dependencies = [ [[package]] name = "chorus-macros" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a81545a60b926f815517dadbbd40cd502294ae2baea25fa8194d854d607512b0" +checksum = "de4221700bc486c6e6bc261fdea478936d33067a06325895f5d2a8cde5917272" dependencies = [ "async-trait", "quote", diff --git a/Cargo.toml b/Cargo.toml index 45060d45..a31a9da8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ thiserror = "1.0.56" jsonwebtoken = "8.3.0" log = "0.4.20" async-trait = "0.1.77" -chorus-macros = "0.2.0" +chorus-macros = "0.3.0" sqlx = { version = "0.7.3", features = [ "mysql", "sqlite", diff --git a/src/errors.rs b/src/errors.rs index a2f174d8..722921a9 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -6,6 +6,7 @@ use custom_error::custom_error; use crate::types::WebSocketEvent; +use chorus_macros::WebSocketEvent; custom_error! { #[derive(PartialEq, Eq, Clone, Hash)] @@ -72,7 +73,7 @@ custom_error! { /// Supposed to be sent as numbers, though they are sent as string most of the time? /// /// Also includes errors when initiating a connection and unexpected opcodes - #[derive(PartialEq, Eq, Default, Clone)] + #[derive(PartialEq, Eq, Default, Clone, WebSocketEvent)] pub GatewayError // Errors we have received from the gateway #[default] @@ -99,15 +100,13 @@ custom_error! { UnexpectedOpcodeReceived{opcode: u8} = "Received an opcode we weren't expecting to receive: {opcode}", } -impl WebSocketEvent for GatewayError {} - custom_error! { /// Voice Gateway errors /// /// Similar to [GatewayError]. /// /// See ; - #[derive(Clone, Default, PartialEq, Eq)] + #[derive(Clone, Default, PartialEq, Eq, WebSocketEvent)] pub VoiceGatewayError // Errors we receive #[default] @@ -132,11 +131,9 @@ custom_error! { UnexpectedOpcodeReceived{opcode: u8} = "Received an opcode we weren't expecting to receive: {opcode}", } -impl WebSocketEvent for VoiceGatewayError {} - custom_error! { /// Voice UDP errors. - #[derive(Clone, PartialEq, Eq)] + #[derive(Clone, PartialEq, Eq, WebSocketEvent)] pub VoiceUdpError // General errors @@ -155,4 +152,3 @@ custom_error! { CannotConnect{error: String} = "Cannot connect due to a UDP error: {error}", } -impl WebSocketEvent for VoiceUdpError {} diff --git a/src/types/events/application.rs b/src/types/events/application.rs index 43537edf..c39b8963 100644 --- a/src/types/events/application.rs +++ b/src/types/events/application.rs @@ -5,12 +5,11 @@ use serde::{Deserialize, Serialize}; use crate::types::{GuildApplicationCommandPermissions, WebSocketEvent}; +use chorus_macros::WebSocketEvent; -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// See pub struct ApplicationCommandPermissionsUpdate { #[serde(flatten)] pub permissions: GuildApplicationCommandPermissions, } - -impl WebSocketEvent for ApplicationCommandPermissionsUpdate {} diff --git a/src/types/events/auto_moderation.rs b/src/types/events/auto_moderation.rs index fd422077..a7e3a341 100644 --- a/src/types/events/auto_moderation.rs +++ b/src/types/events/auto_moderation.rs @@ -2,28 +2,27 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use crate::types::{JsonField, SourceUrlField}; -use chorus_macros::{JsonField, SourceUrlField}; +use crate::types::{JsonField, SourceUrlField, WebSocketEvent}; +use chorus_macros::{JsonField, SourceUrlField, WebSocketEvent}; use serde::{Deserialize, Serialize}; use crate::types::{ AutoModerationAction, AutoModerationRule, AutoModerationRuleTriggerType, Snowflake, - WebSocketEvent, }; #[cfg(feature = "client")] use super::UpdateMessage; -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// See pub struct AutoModerationRuleCreate { #[serde(flatten)] pub rule: AutoModerationRule, } -impl WebSocketEvent for AutoModerationRuleCreate {} - -#[derive(Debug, Deserialize, Serialize, Default, Clone, JsonField, SourceUrlField)] +#[derive( + Debug, Deserialize, Serialize, Default, Clone, JsonField, SourceUrlField, WebSocketEvent, +)] /// See pub struct AutoModerationRuleUpdate { #[serde(flatten)] @@ -43,18 +42,14 @@ impl UpdateMessage for AutoModerationRuleUpdate { } } -impl WebSocketEvent for AutoModerationRuleUpdate {} - -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// See pub struct AutoModerationRuleDelete { #[serde(flatten)] pub rule: AutoModerationRule, } -impl WebSocketEvent for AutoModerationRuleDelete {} - -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// See pub struct AutoModerationActionExecution { pub guild_id: Snowflake, @@ -69,5 +64,3 @@ pub struct AutoModerationActionExecution { pub matched_keyword: Option, pub matched_content: Option, } - -impl WebSocketEvent for AutoModerationActionExecution {} diff --git a/src/types/events/call.rs b/src/types/events/call.rs index 11a88017..5dc59113 100644 --- a/src/types/events/call.rs +++ b/src/types/events/call.rs @@ -5,8 +5,9 @@ use serde::{Deserialize, Serialize}; use crate::types::{Snowflake, VoiceState, WebSocketEvent}; +use chorus_macros::WebSocketEvent; -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// Officially Undocumented; /// Is sent to a client by the server to signify a new call being created; /// @@ -23,9 +24,7 @@ pub struct CallCreate { pub channel_id: Snowflake, } -impl WebSocketEvent for CallCreate {} - -#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq, WebSocketEvent)] /// Officially Undocumented; /// Updates the client on which calls are ringing, along with a specific call?; /// @@ -40,9 +39,7 @@ pub struct CallUpdate { pub channel_id: Snowflake, } -impl WebSocketEvent for CallUpdate {} - -#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq, WebSocketEvent)] /// Officially Undocumented; /// Deletes a ringing call; /// Ex: {"t":"CALL_DELETE","s":8,"op":0,"d":{"channel_id":"837609115475771392"}} @@ -50,9 +47,7 @@ pub struct CallDelete { pub channel_id: Snowflake, } -impl WebSocketEvent for CallDelete {} - -#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq, WebSocketEvent)] /// Officially Undocumented; /// See ; /// @@ -61,4 +56,3 @@ pub struct CallSync { pub channel_id: Snowflake, } -impl WebSocketEvent for CallSync {} diff --git a/src/types/events/channel.rs b/src/types/events/channel.rs index 748d04a7..28a96e54 100644 --- a/src/types/events/channel.rs +++ b/src/types/events/channel.rs @@ -18,7 +18,7 @@ use crate::gateway::Shared; #[cfg(feature = "client")] use crate::types::Guild; -#[derive(Debug, Default, Deserialize, Serialize)] +#[derive(Debug, Default, Deserialize, Serialize, WebSocketEvent)] /// See pub struct ChannelPinsUpdate { pub guild_id: Option, @@ -26,9 +26,7 @@ pub struct ChannelPinsUpdate { pub last_pin_timestamp: Option>, } -impl WebSocketEvent for ChannelPinsUpdate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField, WebSocketEvent)] /// See pub struct ChannelCreate { #[serde(flatten)] @@ -39,8 +37,6 @@ pub struct ChannelCreate { pub source_url: String, } -impl WebSocketEvent for ChannelCreate {} - #[cfg(feature = "client")] impl UpdateMessage for ChannelCreate { #[cfg(not(tarpaulin_include))] @@ -59,7 +55,7 @@ impl UpdateMessage for ChannelCreate { } } -#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField, WebSocketEvent)] /// See pub struct ChannelUpdate { #[serde(flatten)] @@ -70,8 +66,6 @@ pub struct ChannelUpdate { pub source_url: String, } -impl WebSocketEvent for ChannelUpdate {} - #[cfg(feature = "client")] impl UpdateMessage for ChannelUpdate { fn update(&mut self, object_to_update: Shared) { @@ -85,7 +79,7 @@ impl UpdateMessage for ChannelUpdate { } } -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// Officially undocumented. /// Sends updates to client about a new message with its id /// {"channel_unread_updates": [{"id": "816412869766938648", "last_message_id": "1085892012085104680"}} @@ -103,9 +97,7 @@ pub struct ChannelUnreadUpdateObject { pub last_pin_timestamp: Option, } -impl WebSocketEvent for ChannelUnreadUpdate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField, WebSocketEvent)] /// See pub struct ChannelDelete { #[serde(flatten)] @@ -140,4 +132,3 @@ impl UpdateMessage for ChannelDelete { } } -impl WebSocketEvent for ChannelDelete {} diff --git a/src/types/events/guild.rs b/src/types/events/guild.rs index 92f46ea4..7271d6ae 100644 --- a/src/types/events/guild.rs +++ b/src/types/events/guild.rs @@ -20,7 +20,7 @@ use super::UpdateMessage; #[cfg(feature = "client")] use crate::gateway::Shared; -#[derive(Debug, Deserialize, Serialize, Default, Clone, SourceUrlField, JsonField)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, SourceUrlField, JsonField, WebSocketEvent)] /// See ; /// 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 @@ -60,9 +60,7 @@ impl Default for GuildCreateDataOption { } } -impl WebSocketEvent for GuildCreate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See ; /// Received to give info about a user being banned from a guild; pub struct GuildBanAdd { @@ -70,9 +68,7 @@ pub struct GuildBanAdd { pub user: PublicUser, } -impl WebSocketEvent for GuildBanAdd {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See ; /// Received to give info about a user being unbanned from a guild; pub struct GuildBanRemove { @@ -80,9 +76,7 @@ pub struct GuildBanRemove { pub user: PublicUser, } -impl WebSocketEvent for GuildBanRemove {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone, SourceUrlField, JsonField)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, SourceUrlField, JsonField, WebSocketEvent)] /// See ; /// Received to give info about a guild being updated; pub struct GuildUpdate { @@ -94,8 +88,6 @@ pub struct GuildUpdate { pub json: String, } -impl WebSocketEvent for GuildUpdate {} - #[cfg(feature = "client")] impl UpdateMessage for GuildUpdate { #[cfg(not(tarpaulin_include))] @@ -104,7 +96,7 @@ impl UpdateMessage for GuildUpdate { } } -#[derive(Debug, Default, Deserialize, Serialize, Clone, SourceUrlField, JsonField)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, SourceUrlField, JsonField, WebSocketEvent)] /// See ; /// Received to tell the client about a guild being deleted; pub struct GuildDelete { @@ -125,9 +117,7 @@ impl UpdateMessage for GuildDelete { fn update(&mut self, _: Shared) {} } -impl WebSocketEvent for GuildDelete {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See ; /// Received to the client about an audit log entry being added; pub struct GuildAuditLogEntryCreate { @@ -135,9 +125,7 @@ pub struct GuildAuditLogEntryCreate { pub entry: AuditLogEntry, } -impl WebSocketEvent for GuildAuditLogEntryCreate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See ; /// Received to tell the client about a change to a guild's emoji list; pub struct GuildEmojisUpdate { @@ -145,9 +133,7 @@ pub struct GuildEmojisUpdate { pub emojis: Vec, } -impl WebSocketEvent for GuildEmojisUpdate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See ; /// Received to tell the client about a change to a guild's sticker list; pub struct GuildStickersUpdate { @@ -155,17 +141,13 @@ pub struct GuildStickersUpdate { pub stickers: Vec, } -impl WebSocketEvent for GuildStickersUpdate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct GuildIntegrationsUpdate { pub guild_id: Snowflake, } -impl WebSocketEvent for GuildIntegrationsUpdate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See ; /// Received to tell the client about a user joining a guild; pub struct GuildMemberAdd { @@ -174,9 +156,7 @@ pub struct GuildMemberAdd { pub guild_id: Snowflake, } -impl WebSocketEvent for GuildMemberAdd {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See ; /// Received to tell the client about a user leaving a guild; pub struct GuildMemberRemove { @@ -184,9 +164,7 @@ pub struct GuildMemberRemove { pub user: PublicUser, } -impl WebSocketEvent for GuildMemberRemove {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct GuildMemberUpdate { pub guild_id: Snowflake, @@ -202,9 +180,7 @@ pub struct GuildMemberUpdate { pub communication_disabled_until: Option>, } -impl WebSocketEvent for GuildMemberUpdate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct GuildMembersChunk { pub guild_id: Snowflake, @@ -216,9 +192,7 @@ pub struct GuildMembersChunk { pub nonce: Option, } -impl WebSocketEvent for GuildMembersChunk {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField, WebSocketEvent)] /// See pub struct GuildRoleCreate { pub guild_id: Snowflake, @@ -229,8 +203,6 @@ pub struct GuildRoleCreate { pub source_url: String, } -impl WebSocketEvent for GuildRoleCreate {} - #[cfg(feature = "client")] impl UpdateMessage for GuildRoleCreate { #[cfg(not(tarpaulin_include))] @@ -252,7 +224,7 @@ impl UpdateMessage for GuildRoleCreate { } } -#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField, WebSocketEvent)] /// See pub struct GuildRoleUpdate { pub guild_id: Snowflake, @@ -263,8 +235,6 @@ pub struct GuildRoleUpdate { pub source_url: String, } -impl WebSocketEvent for GuildRoleUpdate {} - #[cfg(feature = "client")] impl UpdateMessage for GuildRoleUpdate { #[cfg(not(tarpaulin_include))] @@ -278,43 +248,35 @@ impl UpdateMessage for GuildRoleUpdate { } } -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct GuildRoleDelete { pub guild_id: Snowflake, pub role_id: Snowflake, } -impl WebSocketEvent for GuildRoleDelete {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct GuildScheduledEventCreate { #[serde(flatten)] pub event: GuildScheduledEvent, } -impl WebSocketEvent for GuildScheduledEventCreate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct GuildScheduledEventUpdate { #[serde(flatten)] pub event: GuildScheduledEvent, } -impl WebSocketEvent for GuildScheduledEventUpdate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct GuildScheduledEventDelete { #[serde(flatten)] pub event: GuildScheduledEvent, } -impl WebSocketEvent for GuildScheduledEventDelete {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct GuildScheduledEventUserAdd { pub guild_scheduled_event_id: Snowflake, @@ -322,14 +284,10 @@ pub struct GuildScheduledEventUserAdd { pub guild_id: Snowflake, } -impl WebSocketEvent for GuildScheduledEventUserAdd {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct GuildScheduledEventUserRemove { pub guild_scheduled_event_id: Snowflake, pub user_id: Snowflake, pub guild_id: Snowflake, } - -impl WebSocketEvent for GuildScheduledEventUserRemove {} diff --git a/src/types/events/heartbeat.rs b/src/types/events/heartbeat.rs index 2b4141b9..b7a00246 100644 --- a/src/types/events/heartbeat.rs +++ b/src/types/events/heartbeat.rs @@ -5,17 +5,14 @@ use crate::types::events::WebSocketEvent; use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Deserialize, Serialize)] +#[derive(Debug, Default, Deserialize, Serialize, WebSocketEvent)] pub struct GatewayHeartbeat { pub op: u8, pub d: Option, } -impl WebSocketEvent for GatewayHeartbeat {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] pub struct GatewayHeartbeatAck { pub op: i32, } -impl WebSocketEvent for GatewayHeartbeatAck {} diff --git a/src/types/events/hello.rs b/src/types/events/hello.rs index 83542c92..f72720bd 100644 --- a/src/types/events/hello.rs +++ b/src/types/events/hello.rs @@ -3,22 +3,20 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use crate::types::WebSocketEvent; +use chorus_macros::WebSocketEvent; use serde::{Deserialize, Serialize}; /// Received on gateway init, tells the client how often to send heartbeats; -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] pub struct GatewayHello { pub op: i32, pub d: HelloData, } -impl WebSocketEvent for GatewayHello {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, Copy)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, Copy, WebSocketEvent)] /// Contains info on how often the client should send heartbeats to the server; pub struct HelloData { /// How often a client should send heartbeats, in milliseconds pub heartbeat_interval: u64, } -impl WebSocketEvent for HelloData {} diff --git a/src/types/events/identify.rs b/src/types/events/identify.rs index 648b5543..84c46a7a 100644 --- a/src/types/events/identify.rs +++ b/src/types/events/identify.rs @@ -6,7 +6,7 @@ use crate::types::events::{PresenceUpdate, WebSocketEvent}; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, WebSocketEvent)] pub struct GatewayIdentifyPayload { pub token: String, pub properties: GatewayIdentifyConnectionProps, @@ -70,9 +70,7 @@ impl GatewayIdentifyPayload { } } -impl WebSocketEvent for GatewayIdentifyPayload {} - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] #[serde_as] pub struct GatewayIdentifyConnectionProps { /// Almost always sent diff --git a/src/types/events/integration.rs b/src/types/events/integration.rs index 3550c4e1..cf167c90 100644 --- a/src/types/events/integration.rs +++ b/src/types/events/integration.rs @@ -5,8 +5,9 @@ use serde::{Deserialize, Serialize}; use crate::types::{Integration, Snowflake, WebSocketEvent}; +use chorus_macros::WebSocketEvent; -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct IntegrationCreate { #[serde(flatten)] @@ -14,9 +15,7 @@ pub struct IntegrationCreate { pub guild_id: Snowflake, } -impl WebSocketEvent for IntegrationCreate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct IntegrationUpdate { #[serde(flatten)] @@ -24,9 +23,7 @@ pub struct IntegrationUpdate { pub guild_id: Snowflake, } -impl WebSocketEvent for IntegrationUpdate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct IntegrationDelete { pub id: Snowflake, @@ -34,4 +31,3 @@ pub struct IntegrationDelete { pub application_id: Option, } -impl WebSocketEvent for IntegrationDelete {} diff --git a/src/types/events/interaction.rs b/src/types/events/interaction.rs index 48d55263..c90c5190 100644 --- a/src/types/events/interaction.rs +++ b/src/types/events/interaction.rs @@ -5,12 +5,12 @@ use serde::{Deserialize, Serialize}; use crate::types::{Interaction, WebSocketEvent}; +use chorus_macros::WebSocketEvent; -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct InteractionCreate { #[serde(flatten)] pub interaction: Interaction, } -impl WebSocketEvent for InteractionCreate {} diff --git a/src/types/events/invalid_session.rs b/src/types/events/invalid_session.rs index ae618794..ee94eeb3 100644 --- a/src/types/events/invalid_session.rs +++ b/src/types/events/invalid_session.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use super::WebSocketEvent; -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// Your session is now invalid. /// /// Either reauthenticate and reidentify or resume if possible. @@ -14,4 +14,3 @@ pub struct GatewayInvalidSession { pub resumable: bool, } -impl WebSocketEvent for GatewayInvalidSession {} diff --git a/src/types/events/invite.rs b/src/types/events/invite.rs index 01e76ff8..13b91b46 100644 --- a/src/types/events/invite.rs +++ b/src/types/events/invite.rs @@ -5,17 +5,16 @@ use serde::{Deserialize, Serialize}; use crate::types::{GuildInvite, Snowflake, WebSocketEvent}; +use chorus_macros::WebSocketEvent; -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct InviteCreate { #[serde(flatten)] pub invite: GuildInvite, } -impl WebSocketEvent for InviteCreate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct InviteDelete { pub channel_id: Snowflake, @@ -23,4 +22,3 @@ pub struct InviteDelete { pub code: String, } -impl WebSocketEvent for InviteDelete {} diff --git a/src/types/events/lazy_request.rs b/src/types/events/lazy_request.rs index 0c80c13c..6e17b8ed 100644 --- a/src/types/events/lazy_request.rs +++ b/src/types/events/lazy_request.rs @@ -7,10 +7,9 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; use crate::types::Snowflake; - use super::WebSocketEvent; -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// Officially Undocumented /// /// Sent to the server to signify lazy loading of a guild; @@ -31,4 +30,3 @@ pub struct LazyRequest { pub channels: Option>>>, } -impl WebSocketEvent for LazyRequest {} diff --git a/src/types/events/message.rs b/src/types/events/message.rs index 4b1779e2..8f982e55 100644 --- a/src/types/events/message.rs +++ b/src/types/events/message.rs @@ -6,12 +6,12 @@ use serde::{Deserialize, Serialize}; use crate::types::{ entities::{Emoji, GuildMember, Message, PublicUser}, - Snowflake, + Snowflake, WebSocketEvent }; -use super::WebSocketEvent; +use chorus_macros::WebSocketEvent; -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// # Reference /// See pub struct TypingStartEvent { @@ -22,9 +22,7 @@ pub struct TypingStartEvent { pub member: Option, } -impl WebSocketEvent for TypingStartEvent {} - -#[derive(Debug, Serialize, Deserialize, Default, Clone)] +#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] /// See pub struct MessageCreate { #[serde(flatten)] @@ -34,7 +32,7 @@ pub struct MessageCreate { pub mentions: Option>, } -#[derive(Debug, Serialize, Deserialize, Default, Clone)] +#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] /// See pub struct MessageCreateUser { #[serde(flatten)] @@ -42,9 +40,7 @@ pub struct MessageCreateUser { pub member: Option, } -impl WebSocketEvent for MessageCreate {} - -#[derive(Debug, Serialize, Deserialize, Default, Clone)] +#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] /// # Reference /// See pub struct MessageUpdate { @@ -55,9 +51,7 @@ pub struct MessageUpdate { pub mentions: Option>, } -impl WebSocketEvent for MessageUpdate {} - -#[derive(Debug, Serialize, Deserialize, Default, Clone)] +#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] /// # Reference /// See pub struct MessageDelete { @@ -66,9 +60,7 @@ pub struct MessageDelete { pub guild_id: Option, } -impl WebSocketEvent for MessageDelete {} - -#[derive(Debug, Serialize, Deserialize, Default, Clone)] +#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] /// # Reference /// See pub struct MessageDeleteBulk { @@ -77,9 +69,7 @@ pub struct MessageDeleteBulk { pub guild_id: Option, } -impl WebSocketEvent for MessageDeleteBulk {} - -#[derive(Debug, Serialize, Deserialize, Default, Clone)] +#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] /// # Reference /// See pub struct MessageReactionAdd { @@ -91,9 +81,7 @@ pub struct MessageReactionAdd { pub emoji: Emoji, } -impl WebSocketEvent for MessageReactionAdd {} - -#[derive(Debug, Serialize, Deserialize, Default, Clone)] +#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] /// # Reference /// See pub struct MessageReactionRemove { @@ -104,9 +92,7 @@ pub struct MessageReactionRemove { pub emoji: Emoji, } -impl WebSocketEvent for MessageReactionRemove {} - -#[derive(Debug, Serialize, Deserialize, Default, Clone)] +#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] /// # Reference /// See pub struct MessageReactionRemoveAll { @@ -115,9 +101,7 @@ pub struct MessageReactionRemoveAll { pub guild_id: Option, } -impl WebSocketEvent for MessageReactionRemoveAll {} - -#[derive(Debug, Serialize, Deserialize, Default, Clone)] +#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] /// # Reference /// See pub struct MessageReactionRemoveEmoji { @@ -127,9 +111,7 @@ pub struct MessageReactionRemoveEmoji { pub emoji: Emoji, } -impl WebSocketEvent for MessageReactionRemoveEmoji {} - -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// Officially Undocumented /// /// Not documented anywhere unofficially @@ -150,4 +132,3 @@ pub struct MessageACK { pub channel_id: Snowflake, } -impl WebSocketEvent for MessageACK {} diff --git a/src/types/events/mod.rs b/src/types/events/mod.rs index 6faafd1a..38414715 100644 --- a/src/types/events/mod.rs +++ b/src/types/events/mod.rs @@ -33,6 +33,8 @@ pub use voice::*; pub use voice_gateway::*; pub use webhooks::*; +use chorus_macros::WebSocketEvent; + #[cfg(feature = "client")] use super::Snowflake; @@ -84,7 +86,7 @@ mod voice_gateway; pub trait WebSocketEvent: Send + Sync + Debug {} -#[derive(Debug, Default, Serialize, Clone)] +#[derive(Debug, Default, Serialize, Clone, WebSocketEvent)] /// The payload used for sending events to the gateway /// /// Similar to [GatewayReceivePayload], except we send a [serde_json::value::Value] for d whilst we receive a [serde_json::value::RawValue] @@ -102,8 +104,6 @@ pub struct GatewaySendPayload { pub sequence_number: Option, } -impl WebSocketEvent for GatewaySendPayload {} - #[derive(Debug, Default, Deserialize, Clone)] /// The payload used for receiving events from the gateway pub struct GatewayReceivePayload<'a> { diff --git a/src/types/events/passive_update.rs b/src/types/events/passive_update.rs index 0f728a20..a0f99091 100644 --- a/src/types/events/passive_update.rs +++ b/src/types/events/passive_update.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use super::{ChannelUnreadUpdateObject, WebSocketEvent}; use crate::types::{GuildMember, Snowflake, VoiceState}; -#[derive(Debug, Deserialize, Serialize, Default)] +#[derive(Debug, Deserialize, Serialize, Default, WebSocketEvent)] /// Officially Undocumented /// /// Seems to be passively set to update the client on guild details (though, why not just send the update events?) @@ -18,4 +18,3 @@ pub struct PassiveUpdateV1 { pub channels: Vec, } -impl WebSocketEvent for PassiveUpdateV1 {} diff --git a/src/types/events/presence.rs b/src/types/events/presence.rs index afbf6337..9fe7c1eb 100644 --- a/src/types/events/presence.rs +++ b/src/types/events/presence.rs @@ -6,7 +6,7 @@ use crate::types::{events::WebSocketEvent, UserStatus}; use crate::types::{Activity, ClientStatusObject, PublicUser, Snowflake}; use serde::{Deserialize, Serialize}; -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// Sent by the client to update its status and presence; /// See pub struct UpdatePresence { @@ -18,7 +18,7 @@ pub struct UpdatePresence { pub afk: bool, } -#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, WebSocketEvent)] /// Received to tell the client that a user updated their presence / status /// See pub struct PresenceUpdate { @@ -30,4 +30,3 @@ pub struct PresenceUpdate { pub client_status: ClientStatusObject, } -impl WebSocketEvent for PresenceUpdate {} diff --git a/src/types/events/ready.rs b/src/types/events/ready.rs index 7e88bdf5..4faa95dd 100644 --- a/src/types/events/ready.rs +++ b/src/types/events/ready.rs @@ -9,7 +9,7 @@ use crate::types::events::{Session, WebSocketEvent}; use crate::types::interfaces::ClientStatusObject; use crate::types::{Activity, GuildMember, PresenceUpdate, VoiceState}; -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// 1/2 half documented; /// Received after identifying, provides initial user info; /// See @@ -30,9 +30,7 @@ pub struct GatewayReady { pub shard: Option<(u64, u64)>, } -impl WebSocketEvent for GatewayReady {} - -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// Officially Undocumented; /// Sent after the READY event when a client is a user, seems to somehow add onto the ready event; pub struct GatewayReadySupplemental { @@ -45,8 +43,6 @@ pub struct GatewayReadySupplemental { pub disclose: Vec, } -impl WebSocketEvent for GatewayReadySupplemental {} - #[derive(Debug, Deserialize, Serialize, Default, Clone)] pub struct MergedPresences { pub guilds: Vec>, diff --git a/src/types/events/reconnect.rs b/src/types/events/reconnect.rs index d2751cc9..558d9535 100644 --- a/src/types/events/reconnect.rs +++ b/src/types/events/reconnect.rs @@ -2,11 +2,10 @@ use serde::{Deserialize, Serialize}; use super::WebSocketEvent; -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// "The reconnect event is dispatched when a client should reconnect to the Gateway (and resume their existing session, if they have one). This event usually occurs during deploys to migrate sessions gracefully off old hosts" /// /// # Reference /// See pub struct GatewayReconnect {} -impl WebSocketEvent for GatewayReconnect {} diff --git a/src/types/events/relationship.rs b/src/types/events/relationship.rs index 6352d911..b12d73df 100644 --- a/src/types/events/relationship.rs +++ b/src/types/events/relationship.rs @@ -5,7 +5,7 @@ use crate::types::{events::WebSocketEvent, Relationship, RelationshipType, Snowflake}; use serde::{Deserialize, Serialize}; -#[derive(Debug, Deserialize, Serialize, Default)] +#[derive(Debug, Deserialize, Serialize, Default, WebSocketEvent)] /// See pub struct RelationshipAdd { #[serde(flatten)] @@ -13,9 +13,7 @@ pub struct RelationshipAdd { pub should_notify: bool, } -impl WebSocketEvent for RelationshipAdd {} - -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// See pub struct RelationshipRemove { pub id: Snowflake, @@ -23,4 +21,3 @@ pub struct RelationshipRemove { pub relationship_type: RelationshipType, } -impl WebSocketEvent for RelationshipRemove {} diff --git a/src/types/events/request_members.rs b/src/types/events/request_members.rs index 0e4d9dd4..a6cffdf6 100644 --- a/src/types/events/request_members.rs +++ b/src/types/events/request_members.rs @@ -5,7 +5,7 @@ use crate::types::{events::WebSocketEvent, Snowflake}; use serde::{Deserialize, Serialize}; -#[derive(Debug, Deserialize, Serialize, Default)] +#[derive(Debug, Deserialize, Serialize, Default, WebSocketEvent)] /// See pub struct GatewayRequestGuildMembers { pub guild_id: Snowflake, @@ -17,4 +17,3 @@ pub struct GatewayRequestGuildMembers { pub nonce: Option, } -impl WebSocketEvent for GatewayRequestGuildMembers {} diff --git a/src/types/events/resume.rs b/src/types/events/resume.rs index 86b3dff5..2485dc3c 100644 --- a/src/types/events/resume.rs +++ b/src/types/events/resume.rs @@ -5,11 +5,10 @@ use crate::types::events::WebSocketEvent; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, Deserialize, Serialize, Default)] +#[derive(Debug, Clone, Deserialize, Serialize, Default, WebSocketEvent)] pub struct GatewayResume { pub token: String, pub session_id: String, pub seq: String, } -impl WebSocketEvent for GatewayResume {} diff --git a/src/types/events/session.rs b/src/types/events/session.rs index 2e5de7a0..a76ebc3c 100644 --- a/src/types/events/session.rs +++ b/src/types/events/session.rs @@ -2,11 +2,12 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use chorus_macros::WebSocketEvent; use serde::{Deserialize, Serialize}; use crate::types::{Activity, WebSocketEvent}; -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// Officially Undocumented /// Seems like it sends active session info to users on connect /// [{"activities":[],"client_info":{"client":"web","os":"other","version":0},"session_id":"ab5941b50d818b1f8d93b4b1b581b192","status":"online"}] @@ -33,4 +34,3 @@ pub struct ClientInfo { pub version: u8, } -impl WebSocketEvent for SessionsReplace {} diff --git a/src/types/events/stage_instance.rs b/src/types/events/stage_instance.rs index 3a0fa647..32c5a176 100644 --- a/src/types/events/stage_instance.rs +++ b/src/types/events/stage_instance.rs @@ -5,30 +5,26 @@ use serde::{Deserialize, Serialize}; use crate::types::{StageInstance, WebSocketEvent}; +use chorus_macros::WebSocketEvent; -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// See pub struct StageInstanceCreate { #[serde(flatten)] pub stage_instance: StageInstance, } -impl WebSocketEvent for StageInstanceCreate {} - -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// See pub struct StageInstanceUpdate { #[serde(flatten)] pub stage_instance: StageInstance, } -impl WebSocketEvent for StageInstanceUpdate {} - -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// See pub struct StageInstanceDelete { #[serde(flatten)] pub stage_instance: StageInstance, } -impl WebSocketEvent for StageInstanceDelete {} diff --git a/src/types/events/thread.rs b/src/types/events/thread.rs index abfecf9e..bf67e830 100644 --- a/src/types/events/thread.rs +++ b/src/types/events/thread.rs @@ -12,16 +12,14 @@ use crate::types::{JsonField, Snowflake, SourceUrlField}; #[cfg(feature = "client")] use super::UpdateMessage; -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct ThreadCreate { #[serde(flatten)] pub thread: Channel, } -impl WebSocketEvent for ThreadCreate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField, WebSocketEvent)] /// See pub struct ThreadUpdate { #[serde(flatten)] @@ -32,8 +30,6 @@ pub struct ThreadUpdate { pub source_url: String, } -impl WebSocketEvent for ThreadUpdate {} - #[cfg(feature = "client")] impl UpdateMessage for ThreadUpdate { #[cfg(not(tarpaulin_include))] @@ -42,16 +38,14 @@ impl UpdateMessage for ThreadUpdate { } } -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct ThreadDelete { #[serde(flatten)] pub thread: Channel, } -impl WebSocketEvent for ThreadDelete {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct ThreadListSync { pub guild_id: Snowflake, @@ -60,9 +54,7 @@ pub struct ThreadListSync { pub members: Option>, } -impl WebSocketEvent for ThreadListSync {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See /// The inner payload is a thread member object with an extra field. pub struct ThreadMemberUpdate { @@ -71,9 +63,7 @@ pub struct ThreadMemberUpdate { pub guild_id: Snowflake, } -impl WebSocketEvent for ThreadMemberUpdate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] /// See pub struct ThreadMembersUpdate { pub id: Snowflake, @@ -84,4 +74,3 @@ pub struct ThreadMembersUpdate { pub removed_members: Option>, } -impl WebSocketEvent for ThreadMembersUpdate {} diff --git a/src/types/events/user.rs b/src/types/events/user.rs index 130ddd1e..877c96cd 100644 --- a/src/types/events/user.rs +++ b/src/types/events/user.rs @@ -8,7 +8,7 @@ use crate::types::entities::PublicUser; use crate::types::events::WebSocketEvent; use crate::types::utils::Snowflake; -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] /// See ; /// Sent to indicate updates to a user object; (name changes, discriminator changes, etc); pub struct UserUpdate { @@ -16,9 +16,7 @@ pub struct UserUpdate { pub user: PublicUser, } -impl WebSocketEvent for UserUpdate {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] /// Undocumented; /// /// Possibly an update for muted guild / channel settings for the current user; @@ -41,8 +39,6 @@ pub struct UserGuildSettingsUpdate { pub channel_overrides: Vec, } -impl WebSocketEvent for UserGuildSettingsUpdate {} - #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] /// Undocumented; /// diff --git a/src/types/events/voice.rs b/src/types/events/voice.rs index 0a4484fc..a2b80b98 100644 --- a/src/types/events/voice.rs +++ b/src/types/events/voice.rs @@ -5,7 +5,7 @@ use crate::types::{events::WebSocketEvent, Snowflake, VoiceState}; use serde::{Deserialize, Serialize}; -#[derive(Debug, Deserialize, Serialize, Default, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, Copy, PartialEq, Eq, WebSocketEvent)] /// /// Sent to the server to indicate an update of the voice state (leave voice channel, join voice channel, mute, deafen); /// @@ -17,9 +17,7 @@ pub struct UpdateVoiceState { pub self_deaf: bool, } -impl WebSocketEvent for UpdateVoiceState {} - -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// See ; /// /// Received from the server to indicate an update in a user's voice state (leave voice channel, join voice channel, mute, deafen, etc); @@ -30,9 +28,7 @@ pub struct VoiceStateUpdate { pub state: VoiceState, } -impl WebSocketEvent for VoiceStateUpdate {} - -#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq, WebSocketEvent)] /// See ; /// /// Received to indicate which voice endpoint, token and guild_id to use; @@ -45,4 +41,3 @@ pub struct VoiceServerUpdate { pub endpoint: Option, } -impl WebSocketEvent for VoiceServerUpdate {} diff --git a/src/types/events/voice_gateway/client_connect.rs b/src/types/events/voice_gateway/client_connect.rs index 3929275a..b5cbc78c 100644 --- a/src/types/events/voice_gateway/client_connect.rs +++ b/src/types/events/voice_gateway/client_connect.rs @@ -3,9 +3,10 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use crate::types::{Snowflake, WebSocketEvent}; +use chorus_macros::WebSocketEvent; use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Copy)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Copy, WebSocketEvent)] /// Sent when another user connects to the voice server. /// /// Contains the user id and "flags". @@ -21,9 +22,7 @@ pub struct VoiceClientConnectFlags { pub flags: Option, } -impl WebSocketEvent for VoiceClientConnectFlags {} - -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Copy)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Copy, WebSocketEvent)] /// Sent when another user connects to the voice server. /// /// Contains the user id and "platform". @@ -37,4 +36,3 @@ pub struct VoiceClientConnectPlatform { pub platform: u8, } -impl WebSocketEvent for VoiceClientConnectPlatform {} diff --git a/src/types/events/voice_gateway/client_disconnect.rs b/src/types/events/voice_gateway/client_disconnect.rs index cc1d9490..3b6b201b 100644 --- a/src/types/events/voice_gateway/client_disconnect.rs +++ b/src/types/events/voice_gateway/client_disconnect.rs @@ -3,9 +3,10 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use crate::types::{Snowflake, WebSocketEvent}; +use chorus_macros::WebSocketEvent; use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Copy)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Copy, WebSocketEvent)] /// Sent when another user disconnects from the voice server. /// /// When received, the SSRC of the user should be discarded. @@ -15,4 +16,3 @@ pub struct VoiceClientDisconnection { pub user_id: Snowflake, } -impl WebSocketEvent for VoiceClientDisconnection {} diff --git a/src/types/events/voice_gateway/hello.rs b/src/types/events/voice_gateway/hello.rs index 08bd09e1..2bd8c721 100644 --- a/src/types/events/voice_gateway/hello.rs +++ b/src/types/events/voice_gateway/hello.rs @@ -3,9 +3,10 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use crate::types::WebSocketEvent; +use chorus_macros::WebSocketEvent; use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Copy)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Copy, WebSocketEvent)] /// Contains info on how often the client should send heartbeats to the server; /// /// Differs from the normal hello data in that discord sends heartbeat interval as a float. @@ -21,4 +22,3 @@ pub struct VoiceHelloData { pub heartbeat_interval: f64, } -impl WebSocketEvent for VoiceHelloData {} diff --git a/src/types/events/voice_gateway/identify.rs b/src/types/events/voice_gateway/identify.rs index d33cd403..383aabbc 100644 --- a/src/types/events/voice_gateway/identify.rs +++ b/src/types/events/voice_gateway/identify.rs @@ -3,9 +3,10 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use crate::types::{Snowflake, WebSocketEvent}; +use chorus_macros::WebSocketEvent; use serde::{Deserialize, Serialize}; -#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq, WebSocketEvent)] /// The identify payload for the voice gateway connection; /// /// Contains authentication info and context to authenticate to the voice gateway. @@ -22,4 +23,3 @@ pub struct VoiceIdentify { // TODO: Add video streams } -impl WebSocketEvent for VoiceIdentify {} diff --git a/src/types/events/voice_gateway/media_sink_wants.rs b/src/types/events/voice_gateway/media_sink_wants.rs index 1f79edaa..be6a4972 100644 --- a/src/types/events/voice_gateway/media_sink_wants.rs +++ b/src/types/events/voice_gateway/media_sink_wants.rs @@ -3,9 +3,10 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use crate::types::WebSocketEvent; +use chorus_macros::WebSocketEvent; use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Copy)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Copy, WebSocketEvent)] /// What does this do? /// /// {"op":15,"d":{"any":100}} @@ -15,4 +16,3 @@ pub struct VoiceMediaSinkWants { pub any: u16, } -impl WebSocketEvent for VoiceMediaSinkWants {} diff --git a/src/types/events/voice_gateway/mod.rs b/src/types/events/voice_gateway/mod.rs index 0546d29e..bb632e2c 100644 --- a/src/types/events/voice_gateway/mod.rs +++ b/src/types/events/voice_gateway/mod.rs @@ -30,7 +30,7 @@ mod speaking; mod ssrc_definition; mod voice_backend_version; -#[derive(Debug, Default, Serialize, Clone)] +#[derive(Debug, Default, Serialize, Clone, WebSocketEvent)] /// The payload used for sending events to the voice gateway. /// /// Similar to [VoiceGatewayReceivePayload], except we send a [Value] for d whilst we receive a [serde_json::value::RawValue] @@ -42,8 +42,6 @@ pub struct VoiceGatewaySendPayload { pub data: Value, } -impl WebSocketEvent for VoiceGatewaySendPayload {} - #[derive(Debug, Deserialize, Clone)] /// The payload used for receiving events from the voice gateway. /// diff --git a/src/types/events/voice_gateway/ready.rs b/src/types/events/voice_gateway/ready.rs index 1f7f90f5..833f8d5c 100644 --- a/src/types/events/voice_gateway/ready.rs +++ b/src/types/events/voice_gateway/ready.rs @@ -5,11 +5,12 @@ use std::net::Ipv4Addr; use crate::types::WebSocketEvent; +use chorus_macros::WebSocketEvent; use serde::{Deserialize, Serialize}; use super::VoiceEncryptionMode; -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] /// The voice gateway's ready event; /// /// Gives the user info about the UDP connection IP and port, srrc to use, @@ -43,4 +44,3 @@ impl Default for VoiceReady { } } -impl WebSocketEvent for VoiceReady {} diff --git a/src/types/events/voice_gateway/session_description.rs b/src/types/events/voice_gateway/session_description.rs index 9c1b3d42..16b63900 100644 --- a/src/types/events/voice_gateway/session_description.rs +++ b/src/types/events/voice_gateway/session_description.rs @@ -1,8 +1,9 @@ use super::{AudioCodec, VideoCodec, VoiceEncryptionMode}; use crate::types::WebSocketEvent; +use chorus_macros::WebSocketEvent; use serde::{Deserialize, Serialize}; -#[derive(Debug, Deserialize, Serialize, Clone, Default)] +#[derive(Debug, Deserialize, Serialize, Clone, Default, WebSocketEvent)] /// Event that describes our encryption mode and secret key for encryption /// /// See @@ -19,9 +20,7 @@ pub struct SessionDescription { pub keyframe_interval: Option, } -impl WebSocketEvent for SessionDescription {} - -#[derive(Debug, Deserialize, Serialize, Clone, Default)] +#[derive(Debug, Deserialize, Serialize, Clone, Default, WebSocketEvent)] /// Event that might be sent to update session parameters /// /// See @@ -36,4 +35,3 @@ pub struct SessionUpdate { pub new_media_session_id: Option, } -impl WebSocketEvent for SessionUpdate {} diff --git a/src/types/events/voice_gateway/speaking.rs b/src/types/events/voice_gateway/speaking.rs index a18ba77a..64cf2e7a 100644 --- a/src/types/events/voice_gateway/speaking.rs +++ b/src/types/events/voice_gateway/speaking.rs @@ -6,13 +6,14 @@ use bitflags::bitflags; use serde::{Deserialize, Serialize}; use crate::types::{Snowflake, WebSocketEvent}; +use chorus_macros::WebSocketEvent; /// Event that tells the server we are speaking; /// /// Essentially, what allows us to send UDP data and lights up the green circle around your avatar. /// /// See -#[derive(Debug, Deserialize, Serialize, Clone, Default)] +#[derive(Debug, Deserialize, Serialize, Clone, Default, WebSocketEvent)] pub struct Speaking { /// Data about the audio we're transmitting. /// @@ -27,8 +28,6 @@ pub struct Speaking { pub delay: u64, } -impl WebSocketEvent for Speaking {} - bitflags! { /// Bitflags of speaking types; /// diff --git a/src/types/events/voice_gateway/ssrc_definition.rs b/src/types/events/voice_gateway/ssrc_definition.rs index 6692dc92..69c13364 100644 --- a/src/types/events/voice_gateway/ssrc_definition.rs +++ b/src/types/events/voice_gateway/ssrc_definition.rs @@ -3,6 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use crate::types::{Snowflake, WebSocketEvent}; +use chorus_macros::WebSocketEvent; use serde::{Deserialize, Serialize}; /// Defines an event which provides ssrcs for voice and video for a user id. @@ -24,7 +25,7 @@ use serde::{Deserialize, Serialize}; /// ```json /// {"op":12,"d":{"audio_ssrc":2307250864,"video_ssrc":0,"rtx_ssrc":0,"streams":[{"type":"video","rid":"100","ssrc":26595,"active":false,"quality":100,"rtx_ssrc":26596,"max_bitrate":2500000,"max_framerate":30,"max_resolution":{"type":"fixed","width":1280,"height":720}}]}} /// ``` -#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq, WebSocketEvent)] pub struct SsrcDefinition { /// The ssrc used for video communications. /// @@ -50,4 +51,3 @@ pub struct SsrcDefinition { pub streams: Vec, } -impl WebSocketEvent for SsrcDefinition {} diff --git a/src/types/events/voice_gateway/voice_backend_version.rs b/src/types/events/voice_gateway/voice_backend_version.rs index f8ee76ed..0e8ce88e 100644 --- a/src/types/events/voice_gateway/voice_backend_version.rs +++ b/src/types/events/voice_gateway/voice_backend_version.rs @@ -3,9 +3,10 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use crate::types::WebSocketEvent; +use chorus_macros::WebSocketEvent; use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, WebSocketEvent)] /// Received from the voice gateway server to describe the backend version. /// /// See @@ -18,4 +19,3 @@ pub struct VoiceBackendVersion { pub rtc_worker_version: String, } -impl WebSocketEvent for VoiceBackendVersion {} diff --git a/src/types/events/webhooks.rs b/src/types/events/webhooks.rs index 814589c1..3f09492c 100644 --- a/src/types/events/webhooks.rs +++ b/src/types/events/webhooks.rs @@ -4,15 +4,13 @@ use serde::{Deserialize, Serialize}; -use crate::types::Snowflake; +use crate::types::{Snowflake, WebSocketEvent}; +use chorus_macros::WebSocketEvent; -use super::WebSocketEvent; - -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// See pub struct WebhooksUpdate { pub guild_id: Snowflake, pub channel_id: Snowflake, } -impl WebSocketEvent for WebhooksUpdate {} From b2fd3e18cc95d5605ae6a659b4d8ad7d580d9eef Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Sun, 28 Apr 2024 14:15:57 +0200 Subject: [PATCH 003/162] Move Shared to types/mod.rs, bump some dependencies (#492) * deps: bump rustls to 0.21.11 This is done to fix CVE-2024-32650, which practically shouldn't affect us but it's still better not to use vulnerable dependencies. * deps: bump h2 to 0.3.26 This is done to fix another vulnerability, which should also not affect us (non-critical, in h2 servers) * fix: move Shared to types/mod.rs --- Cargo.lock | 8 ++++---- src/gateway/handle.rs | 2 +- src/gateway/mod.rs | 7 ------- src/instance.rs | 4 ++-- src/types/entities/application.rs | 2 +- src/types/entities/audit_log.rs | 2 +- src/types/entities/auto_moderation.rs | 2 +- src/types/entities/channel.rs | 2 +- src/types/entities/emoji.rs | 2 +- src/types/entities/guild.rs | 2 +- src/types/entities/guild_member.rs | 2 +- src/types/entities/integration.rs | 2 +- src/types/entities/invite.rs | 3 +-- src/types/entities/message.rs | 2 +- src/types/entities/mod.rs | 6 +++--- src/types/entities/relationship.rs | 3 +-- src/types/entities/sticker.rs | 3 +-- src/types/entities/team.rs | 2 +- src/types/entities/template.rs | 2 +- src/types/entities/user_settings.rs | 2 +- src/types/entities/voice_state.rs | 4 +++- src/types/entities/webhook.rs | 3 ++- src/types/events/channel.rs | 6 ++++-- src/types/events/guild.rs | 6 ++++-- src/types/events/mod.rs | 2 +- src/types/mod.rs | 10 ++++++++++ tests/common/mod.rs | 4 ++-- 27 files changed, 51 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 46b87f96..53283ccf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -716,9 +716,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -1753,9 +1753,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.10" +version = "0.21.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" dependencies = [ "log", "ring 0.17.7", diff --git a/src/gateway/handle.rs b/src/gateway/handle.rs index 6af5f0d2..bfaeb177 100644 --- a/src/gateway/handle.rs +++ b/src/gateway/handle.rs @@ -8,7 +8,7 @@ use log::*; use std::fmt::Debug; use super::{events::Events, *}; -use crate::types::{self, Composite}; +use crate::types::{self, Composite, Shared}; /// Represents a handle to a Gateway connection. A Gateway connection will create observable /// [`GatewayEvents`](GatewayEvent), which you can subscribe to. Gateway events include all currently diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index 5a5881ad..b48786e9 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -133,10 +133,3 @@ impl GatewayEvent { } } -/// A type alias for [`Arc>`], used to make the public facing API concerned with -/// Composite structs more ergonomic. -/// ## Note -/// -/// While `T` does not have to implement `Composite` to be used with `Shared`, -/// the primary use of `Shared` is with types that implement `Composite`. -pub type Shared = Arc>; diff --git a/src/instance.rs b/src/instance.rs index 16610429..d23a5678 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -13,11 +13,11 @@ use reqwest::Client; use serde::{Deserialize, Serialize}; use crate::errors::ChorusResult; -use crate::gateway::{Gateway, GatewayHandle, Shared}; +use crate::gateway::{Gateway, GatewayHandle}; use crate::ratelimiter::ChorusRequest; use crate::types::types::subconfigs::limits::rates::RateLimits; use crate::types::{ - GeneralConfiguration, Limit, LimitType, LimitsConfiguration, User, UserSettings, + GeneralConfiguration, Limit, LimitType, LimitsConfiguration, Shared, User, UserSettings, }; use crate::UrlBundle; diff --git a/src/types/entities/application.rs b/src/types/entities/application.rs index 4014e557..c7727884 100644 --- a/src/types/entities/application.rs +++ b/src/types/entities/application.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_repr::{Deserialize_repr, Serialize_repr}; -use crate::gateway::Shared; +use crate::types::Shared; use crate::types::utils::Snowflake; use crate::types::{Team, User}; diff --git a/src/types/entities/audit_log.rs b/src/types/entities/audit_log.rs index 477fb20d..566b2231 100644 --- a/src/types/entities/audit_log.rs +++ b/src/types/entities/audit_log.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; -use crate::gateway::Shared; +use crate::types::Shared; use crate::types::utils::Snowflake; #[derive(Serialize, Deserialize, Debug, Default, Clone)] diff --git a/src/types/entities/auto_moderation.rs b/src/types/entities/auto_moderation.rs index cd69bf26..021185ec 100644 --- a/src/types/entities/auto_moderation.rs +++ b/src/types/entities/auto_moderation.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use crate::gateway::Shared; +use crate::types::Shared; #[cfg(feature = "client")] use crate::gateway::Updateable; diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 7d000dcd..fd0c077b 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -8,7 +8,7 @@ use serde_aux::prelude::deserialize_string_from_number; use serde_repr::{Deserialize_repr, Serialize_repr}; use std::fmt::Debug; -use crate::gateway::Shared; +use crate::types::Shared; use crate::types::{ entities::{GuildMember, User}, utils::Snowflake, diff --git a/src/types/entities/emoji.rs b/src/types/entities/emoji.rs index e84b025c..1b68f0dc 100644 --- a/src/types/entities/emoji.rs +++ b/src/types/entities/emoji.rs @@ -6,7 +6,7 @@ use std::fmt::Debug; use serde::{Deserialize, Serialize}; -use crate::gateway::Shared; +use crate::types::Shared; use crate::types::entities::User; use crate::types::Snowflake; diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 52ec5e50..2b7ae441 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -9,7 +9,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use crate::gateway::Shared; +use crate::types::Shared; use crate::types::types::guild_configuration::GuildFeaturesList; use crate::types::{ entities::{Channel, Emoji, RoleObject, Sticker, User, VoiceState, Webhook}, diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index 14414c53..5cd5ad13 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; -use crate::gateway::Shared; +use crate::types::Shared; use crate::types::{entities::PublicUser, Snowflake}; #[derive(Debug, Deserialize, Default, Serialize, Clone)] diff --git a/src/types/entities/integration.rs b/src/types/entities/integration.rs index 97d21c38..db4fecf2 100644 --- a/src/types/entities/integration.rs +++ b/src/types/entities/integration.rs @@ -5,8 +5,8 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::gateway::Shared; use crate::types::{ + Shared, entities::{Application, User}, utils::Snowflake, }; diff --git a/src/types/entities/invite.rs b/src/types/entities/invite.rs index 720203a1..e9c9bd8b 100644 --- a/src/types/entities/invite.rs +++ b/src/types/entities/invite.rs @@ -5,8 +5,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::gateway::Shared; -use crate::types::{Snowflake, WelcomeScreenObject}; +use crate::types::{Snowflake, WelcomeScreenObject, Shared}; use super::guild::GuildScheduledEvent; use super::{Application, Channel, GuildMember, NSFWLevel, User}; diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index d7642437..e03a0784 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize}; -use crate::gateway::Shared; use crate::types::{ + Shared, entities::{ Application, Attachment, Channel, Emoji, GuildMember, PublicUser, RoleSubscriptionData, Sticker, StickerItem, User, diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index 1400d0e5..d5d70e60 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -27,7 +27,9 @@ pub use user_settings::*; pub use voice_state::*; pub use webhook::*; -use crate::gateway::Shared; +use crate::types::Shared; +use std::sync::{Arc, RwLock}; + #[cfg(feature = "client")] use crate::gateway::Updateable; @@ -39,8 +41,6 @@ use async_trait::async_trait; #[cfg(feature = "client")] use std::fmt::Debug; -#[cfg(feature = "client")] -use std::sync::{Arc, RwLock}; mod application; mod attachment; diff --git a/src/types/entities/relationship.rs b/src/types/entities/relationship.rs index a5682566..b5e2004a 100644 --- a/src/types/entities/relationship.rs +++ b/src/types/entities/relationship.rs @@ -6,8 +6,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use crate::gateway::Shared; -use crate::types::Snowflake; +use crate::types::{Shared, Snowflake}; use super::PublicUser; diff --git a/src/types/entities/sticker.rs b/src/types/entities/sticker.rs index 8b95bc4e..7048f826 100644 --- a/src/types/entities/sticker.rs +++ b/src/types/entities/sticker.rs @@ -4,8 +4,7 @@ use serde::{Deserialize, Serialize}; -use crate::gateway::Shared; -use crate::types::{entities::User, utils::Snowflake}; +use crate::types::{entities::User, utils::Snowflake, Shared}; #[derive(Debug, Serialize, Deserialize, Clone, Default)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] diff --git a/src/types/entities/team.rs b/src/types/entities/team.rs index 98bd23eb..8fed8190 100644 --- a/src/types/entities/team.rs +++ b/src/types/entities/team.rs @@ -4,9 +4,9 @@ use serde::{Deserialize, Serialize}; -use crate::gateway::Shared; use crate::types::entities::User; use crate::types::Snowflake; +use crate::types::Shared; #[derive(Debug, Deserialize, Serialize, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] diff --git a/src/types/entities/template.rs b/src/types/entities/template.rs index f34fbd7e..e82ec172 100644 --- a/src/types/entities/template.rs +++ b/src/types/entities/template.rs @@ -5,8 +5,8 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::gateway::Shared; use crate::types::{ + Shared, entities::{Guild, User}, utils::Snowflake, }; diff --git a/src/types/entities/user_settings.rs b/src/types/entities/user_settings.rs index 6c072a88..db13efc9 100644 --- a/src/types/entities/user_settings.rs +++ b/src/types/entities/user_settings.rs @@ -7,7 +7,7 @@ use std::sync::{Arc, RwLock}; use chrono::{serde::ts_milliseconds_option, Utc}; use serde::{Deserialize, Serialize}; -use crate::gateway::Shared; +use crate::types::Shared; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] diff --git a/src/types/entities/voice_state.rs b/src/types/entities/voice_state.rs index 304b7240..7297456b 100644 --- a/src/types/entities/voice_state.rs +++ b/src/types/entities/voice_state.rs @@ -5,7 +5,8 @@ #[cfg(feature = "client")] use chorus_macros::Composite; -use crate::gateway::Shared; +use crate::types::Shared; + #[cfg(feature = "client")] use crate::types::Composite; @@ -51,6 +52,7 @@ pub struct VoiceState { pub id: Option, // Only exists on Spacebar } +#[cfg(feature = "client")] impl Updateable for VoiceState { #[cfg(not(tarpaulin_include))] fn id(&self) -> Snowflake { diff --git a/src/types/entities/webhook.rs b/src/types/entities/webhook.rs index f973956f..3fcc43bd 100644 --- a/src/types/entities/webhook.rs +++ b/src/types/entities/webhook.rs @@ -6,7 +6,8 @@ use std::fmt::Debug; use serde::{Deserialize, Serialize}; -use crate::gateway::Shared; +use crate::types::Shared; + #[cfg(feature = "client")] use crate::gateway::Updateable; diff --git a/src/types/events/channel.rs b/src/types/events/channel.rs index 28a96e54..911f2491 100644 --- a/src/types/events/channel.rs +++ b/src/types/events/channel.rs @@ -3,7 +3,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use crate::types::events::WebSocketEvent; -use crate::types::IntoShared; use crate::types::{entities::Channel, JsonField, Snowflake, SourceUrlField}; use chorus_macros::{JsonField, SourceUrlField}; use chrono::{DateTime, Utc}; @@ -13,7 +12,10 @@ use serde::{Deserialize, Serialize}; use super::UpdateMessage; #[cfg(feature = "client")] -use crate::gateway::Shared; +use crate::types::Shared; + +#[cfg(feature = "client")] +use crate::types::IntoShared; #[cfg(feature = "client")] use crate::types::Guild; diff --git a/src/types/events/guild.rs b/src/types/events/guild.rs index 7271d6ae..362b9847 100644 --- a/src/types/events/guild.rs +++ b/src/types/events/guild.rs @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; use crate::types::entities::{Guild, PublicUser, UnavailableGuild}; use crate::types::events::WebSocketEvent; use crate::types::{ - AuditLogEntry, Emoji, GuildMember, GuildScheduledEvent, IntoShared, JsonField, RoleObject, + AuditLogEntry, Emoji, GuildMember, GuildScheduledEvent, JsonField, RoleObject, Snowflake, SourceUrlField, Sticker, }; @@ -18,7 +18,9 @@ use super::PresenceUpdate; #[cfg(feature = "client")] use super::UpdateMessage; #[cfg(feature = "client")] -use crate::gateway::Shared; +use crate::types::Shared; +#[cfg(feature = "client")] +use crate::types::IntoShared; #[derive(Debug, Deserialize, Serialize, Default, Clone, SourceUrlField, JsonField, WebSocketEvent)] /// See ; diff --git a/src/types/events/mod.rs b/src/types/events/mod.rs index 38414715..280ebb80 100644 --- a/src/types/events/mod.rs +++ b/src/types/events/mod.rs @@ -48,7 +48,7 @@ use serde_json::{from_str, from_value, to_value, Value}; use std::collections::HashMap; #[cfg(feature = "client")] -use crate::gateway::Shared; +use crate::types::Shared; use std::fmt::Debug; #[cfg(feature = "client")] diff --git a/src/types/mod.rs b/src/types/mod.rs index 8eee13ac..c4cc1907 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -4,6 +4,8 @@ //! All the types, entities, events and interfaces of the Spacebar API. +use std::sync::{Arc, RwLock}; + pub use config::*; pub use entities::*; pub use errors::*; @@ -19,3 +21,11 @@ mod events; mod interfaces; mod schema; mod utils; + +/// A type alias for [`Arc>`], used to make the public facing API concerned with +/// Composite structs more ergonomic. +/// ## Note +/// +/// While `T` does not have to implement `Composite` to be used with `Shared`, +/// the primary use of `Shared` is with types that implement `Composite`. +pub type Shared = Arc>; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index f24c7e62..a98667c8 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -2,13 +2,13 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use chorus::gateway::{Gateway, Shared}; +use chorus::gateway::Gateway; use chorus::types::IntoShared; use chorus::{ instance::{ChorusUser, Instance}, types::{ Channel, ChannelCreateSchema, Guild, GuildCreateSchema, RegisterSchema, - RoleCreateModifySchema, RoleObject, + RoleCreateModifySchema, RoleObject, Shared }, UrlBundle, }; From aac31726ec6721112b128fd4aecd71df925abd0b Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:17:47 +0200 Subject: [PATCH 004/162] Reuse gateway backends, don't duplicate them for voice gateway (#493) --- src/errors.rs | 4 +- src/gateway/backends/tungstenite.rs | 18 +++--- src/gateway/backends/wasm.rs | 10 +--- src/gateway/gateway.rs | 9 ++- src/voice/gateway/backends/mod.rs | 17 ------ src/voice/gateway/backends/tungstenite.rs | 68 ++--------------------- src/voice/gateway/backends/wasm.rs | 29 +--------- src/voice/gateway/gateway.rs | 20 ++++--- src/voice/gateway/handle.rs | 13 +++-- src/voice/gateway/heartbeat.rs | 4 +- 10 files changed, 50 insertions(+), 142 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 722921a9..0d130dd0 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -93,7 +93,7 @@ custom_error! { DisallowedIntents = "You sent a disallowed intent. You may have tried to specify an intent that you have not enabled or are not approved for", // Errors when initiating a gateway connection - CannotConnect{error: String} = "Cannot connect due to a tungstenite error: {error}", + CannotConnect{error: String} = "Cannot connect due to a websocket error: {error}", NonHelloOnInitiate{opcode: u8} = "Received non hello on initial gateway connection ({opcode}), something is definitely wrong", // Other misc errors @@ -124,7 +124,7 @@ custom_error! { UnknownEncryptionMode = "Server failed to decrypt data", // Errors when initiating a gateway connection - CannotConnect{error: String} = "Cannot connect due to a tungstenite error: {error}", + CannotConnect{error: String} = "Cannot connect due to a websocket error: {error}", NonHelloOnInitiate{opcode: u8} = "Received non hello on initial gateway connection ({opcode}), something is definitely wrong", // Other misc errors diff --git a/src/gateway/backends/tungstenite.rs b/src/gateway/backends/tungstenite.rs index a9f9f64f..6c7ac391 100644 --- a/src/gateway/backends/tungstenite.rs +++ b/src/gateway/backends/tungstenite.rs @@ -2,6 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use custom_error::custom_error; use futures_util::{ stream::{SplitSink, SplitStream}, StreamExt, @@ -11,7 +12,6 @@ use tokio_tungstenite::{ connect_async_tls_with_config, tungstenite, Connector, MaybeTlsStream, WebSocketStream, }; -use crate::errors::GatewayError; use crate::gateway::GatewayMessage; #[derive(Debug, Clone)] @@ -22,18 +22,22 @@ pub type TungsteniteSink = SplitSink>, tungstenite::Message>; pub type TungsteniteStream = SplitStream>>; +custom_error! { + pub TungsteniteBackendError + FailedToLoadCerts{error: std::io::Error} = "failed to load platform native certs: {error}", + TungsteniteError{error: tungstenite::error::Error} = "encountered a tungstenite error: {error}", +} + impl TungsteniteBackend { pub async fn connect( websocket_url: &str, - ) -> Result<(TungsteniteSink, TungsteniteStream), crate::errors::GatewayError> { + ) -> Result<(TungsteniteSink, TungsteniteStream), TungsteniteBackendError> { let mut roots = rustls::RootCertStore::empty(); let certs = rustls_native_certs::load_native_certs(); if let Err(e) = certs { log::error!("Failed to load platform native certs! {:?}", e); - return Err(GatewayError::CannotConnect { - error: format!("{:?}", e), - }); + return Err(TungsteniteBackendError::FailedToLoadCerts { error: e }); } for cert in certs.unwrap() { @@ -55,8 +59,8 @@ impl TungsteniteBackend { { Ok(websocket_stream) => websocket_stream, Err(e) => { - return Err(GatewayError::CannotConnect { - error: e.to_string(), + return Err(TungsteniteBackendError::TungsteniteError { + error: e, }) } }; diff --git a/src/gateway/backends/wasm.rs b/src/gateway/backends/wasm.rs index 83f4b37b..a40321da 100644 --- a/src/gateway/backends/wasm.rs +++ b/src/gateway/backends/wasm.rs @@ -9,7 +9,6 @@ use futures_util::{ use ws_stream_wasm::*; -use crate::errors::GatewayError; use crate::gateway::GatewayMessage; #[derive(Debug, Clone)] @@ -22,13 +21,8 @@ pub type WasmStream = SplitStream; impl WasmBackend { pub async fn connect( websocket_url: &str, - ) -> Result<(WasmSink, WasmStream), crate::errors::GatewayError> { - let (_, websocket_stream) = match WsMeta::connect(websocket_url, None).await { - Ok(stream) => Ok(stream), - Err(e) => Err(GatewayError::CannotConnect { - error: e.to_string(), - }), - }?; + ) -> Result<(WasmSink, WasmStream), ws_stream_wasm::WsErr> { + let (_, websocket_stream) = WsMeta::connect(websocket_url, None).await?; Ok(websocket_stream.split()) } diff --git a/src/gateway/gateway.rs b/src/gateway/gateway.rs index dabfeb67..34808c93 100644 --- a/src/gateway/gateway.rs +++ b/src/gateway/gateway.rs @@ -35,7 +35,14 @@ impl Gateway { #[allow(clippy::new_ret_no_self)] pub async fn spawn(websocket_url: String) -> Result { let (websocket_send, mut websocket_receive) = - WebSocketBackend::connect(&websocket_url).await?; + match WebSocketBackend::connect(&websocket_url).await { + Ok(streams) => streams, + Err(e) => { + return Err(GatewayError::CannotConnect { + error: format!("{:?}", e), + }) + } + }; let shared_websocket_send = Arc::new(Mutex::new(websocket_send)); diff --git a/src/voice/gateway/backends/mod.rs b/src/voice/gateway/backends/mod.rs index 7f3f3ddd..23f2767d 100644 --- a/src/voice/gateway/backends/mod.rs +++ b/src/voice/gateway/backends/mod.rs @@ -4,24 +4,7 @@ #[cfg(all(not(target_arch = "wasm32"), feature = "voice_gateway"))] pub mod tungstenite; -#[cfg(all(not(target_arch = "wasm32"), feature = "voice_gateway"))] -pub use tungstenite::*; #[cfg(all(target_arch = "wasm32", feature = "voice_gateway"))] pub mod wasm; -#[cfg(all(target_arch = "wasm32", feature = "voice_gateway"))] -pub use wasm::*; -#[cfg(all(not(target_arch = "wasm32"), feature = "voice_gateway"))] -pub type Sink = tungstenite::TungsteniteSink; -#[cfg(all(not(target_arch = "wasm32"), feature = "voice_gateway"))] -pub type Stream = tungstenite::TungsteniteStream; -#[cfg(all(not(target_arch = "wasm32"), feature = "voice_gateway"))] -pub type WebSocketBackend = tungstenite::TungsteniteBackend; - -#[cfg(all(target_arch = "wasm32", feature = "voice_gateway"))] -pub type Sink = wasm::WasmSink; -#[cfg(all(target_arch = "wasm32", feature = "voice_gateway"))] -pub type Stream = wasm::WasmStream; -#[cfg(all(target_arch = "wasm32", feature = "voice_gateway"))] -pub type WebSocketBackend = wasm::WasmBackend; diff --git a/src/voice/gateway/backends/tungstenite.rs b/src/voice/gateway/backends/tungstenite.rs index 26cc0fe4..599274d1 100644 --- a/src/voice/gateway/backends/tungstenite.rs +++ b/src/voice/gateway/backends/tungstenite.rs @@ -2,76 +2,16 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use futures_util::{ - stream::{SplitSink, SplitStream}, - StreamExt, -}; -use tokio::net::TcpStream; -use tokio_tungstenite::{ - connect_async_tls_with_config, tungstenite, Connector, MaybeTlsStream, WebSocketStream, -}; +use crate::voice::gateway::VoiceGatewayMessage; -use crate::{errors::VoiceGatewayError, voice::gateway::VoiceGatewayMessage}; - -#[derive(Debug, Clone)] -pub struct TungsteniteBackend; - -// These could be made into inherent associated types when that's stabilized -pub type TungsteniteSink = - SplitSink>, tungstenite::Message>; -pub type TungsteniteStream = SplitStream>>; - -impl TungsteniteBackend { - pub async fn connect( - websocket_url: &str, - ) -> Result<(TungsteniteSink, TungsteniteStream), crate::errors::VoiceGatewayError> { - let mut roots = rustls::RootCertStore::empty(); - let certs = rustls_native_certs::load_native_certs(); - - if let Err(e) = certs { - log::error!("Failed to load platform native certs! {:?}", e); - return Err(VoiceGatewayError::CannotConnect { - error: format!("{:?}", e), - }); - } - - for cert in certs.unwrap() { - roots.add(&rustls::Certificate(cert.0)).unwrap(); - } - let (websocket_stream, _) = match connect_async_tls_with_config( - websocket_url, - None, - false, - Some(Connector::Rustls( - rustls::ClientConfig::builder() - .with_safe_defaults() - .with_root_certificates(roots) - .with_no_client_auth() - .into(), - )), - ) - .await - { - Ok(websocket_stream) => websocket_stream, - Err(e) => { - return Err(VoiceGatewayError::CannotConnect { - error: e.to_string(), - }) - } - }; - - Ok(websocket_stream.split()) - } -} - -impl From for tungstenite::Message { +impl From for tokio_tungstenite::tungstenite::Message { fn from(message: VoiceGatewayMessage) -> Self { Self::Text(message.0) } } -impl From for VoiceGatewayMessage { - fn from(value: tungstenite::Message) -> Self { +impl From for VoiceGatewayMessage { + fn from(value: tokio_tungstenite::tungstenite::Message) -> Self { Self(value.to_string()) } } diff --git a/src/voice/gateway/backends/wasm.rs b/src/voice/gateway/backends/wasm.rs index a39723e8..611b2027 100644 --- a/src/voice/gateway/backends/wasm.rs +++ b/src/voice/gateway/backends/wasm.rs @@ -2,36 +2,9 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use futures_util::{ - stream::{SplitSink, SplitStream}, - StreamExt, -}; - -use ws_stream_wasm::*; - -use crate::errors::VoiceGatewayError; +use ws_stream_wasm::WsMessage; use crate::voice::gateway::VoiceGatewayMessage; -#[derive(Debug, Clone)] -pub struct WasmBackend; - -// These could be made into inherent associated types when that's stabilized -pub type WasmSink = SplitSink; -pub type WasmStream = SplitStream; - -impl WasmBackend { - pub async fn connect(websocket_url: &str) -> Result<(WasmSink, WasmStream), VoiceGatewayError> { - let (_, websocket_stream) = match WsMeta::connect(websocket_url, None).await { - Ok(stream) => Ok(stream), - Err(e) => Err(VoiceGatewayError::CannotConnect { - error: e.to_string(), - }), - }?; - - Ok(websocket_stream.split()) - } -} - impl From for WsMessage { fn from(message: VoiceGatewayMessage) -> Self { Self::Text(message.0) diff --git a/src/voice/gateway/gateway.rs b/src/voice/gateway/gateway.rs index 4727ae4d..9a2a60b1 100644 --- a/src/voice/gateway/gateway.rs +++ b/src/voice/gateway/gateway.rs @@ -11,6 +11,9 @@ use tokio::sync::Mutex; use futures_util::SinkExt; use futures_util::StreamExt; +use crate::gateway::Sink; +use crate::gateway::Stream; +use crate::gateway::WebSocketBackend; use crate::{ errors::VoiceGatewayError, gateway::GatewayEvent, @@ -21,14 +24,10 @@ use crate::{ VOICE_READY, VOICE_RESUME, VOICE_SELECT_PROTOCOL, VOICE_SESSION_DESCRIPTION, VOICE_SESSION_UPDATE, VOICE_SPEAKING, VOICE_SSRC_DEFINITION, }, - voice::gateway::{ - heartbeat::VoiceHeartbeatThreadCommunication, VoiceGatewayMessage, WebSocketBackend, - }, + voice::gateway::{heartbeat::VoiceHeartbeatThreadCommunication, VoiceGatewayMessage}, }; -use super::{ - events::VoiceEvents, heartbeat::VoiceHeartbeatHandler, Sink, Stream, VoiceGatewayHandle, -}; +use super::{events::VoiceEvents, heartbeat::VoiceHeartbeatHandler, VoiceGatewayHandle}; #[derive(Debug)] pub struct VoiceGateway { @@ -48,7 +47,14 @@ impl VoiceGateway { trace!("Created voice socket url: {}", processed_url.clone()); let (websocket_send, mut websocket_receive) = - WebSocketBackend::connect(&processed_url).await?; + match WebSocketBackend::connect(&processed_url).await { + Ok(streams) => streams, + Err(e) => { + return Err(VoiceGatewayError::CannotConnect { + error: format!("{:?}", e), + }) + } + }; let shared_websocket_send = Arc::new(Mutex::new(websocket_send)); diff --git a/src/voice/gateway/handle.rs b/src/voice/gateway/handle.rs index b48080a1..8750f12f 100644 --- a/src/voice/gateway/handle.rs +++ b/src/voice/gateway/handle.rs @@ -11,13 +11,16 @@ use futures_util::SinkExt; use serde_json::json; use tokio::sync::Mutex; -use crate::types::{ - SelectProtocol, Speaking, SsrcDefinition, VoiceGatewaySendPayload, VoiceIdentify, - VOICE_BACKEND_VERSION, VOICE_IDENTIFY, VOICE_SELECT_PROTOCOL, VOICE_SPEAKING, - VOICE_SSRC_DEFINITION, +use crate::{ + gateway::Sink, + types::{ + SelectProtocol, Speaking, SsrcDefinition, VoiceGatewaySendPayload, VoiceIdentify, + VOICE_BACKEND_VERSION, VOICE_IDENTIFY, VOICE_SELECT_PROTOCOL, VOICE_SPEAKING, + VOICE_SSRC_DEFINITION, + }, }; -use super::{events::VoiceEvents, Sink, VoiceGatewayMessage}; +use super::{events::VoiceEvents, VoiceGatewayMessage}; /// Represents a handle to a Voice Gateway connection. /// Using this handle you can send Gateway Events directly. diff --git a/src/voice/gateway/heartbeat.rs b/src/voice/gateway/heartbeat.rs index 2b9fde58..945bfbd9 100644 --- a/src/voice/gateway/heartbeat.rs +++ b/src/voice/gateway/heartbeat.rs @@ -26,13 +26,11 @@ use tokio::sync::{ use tokio::task; use crate::{ - gateway::heartbeat::HEARTBEAT_ACK_TIMEOUT, + gateway::{heartbeat::HEARTBEAT_ACK_TIMEOUT, Sink}, types::{VoiceGatewaySendPayload, VOICE_HEARTBEAT, VOICE_HEARTBEAT_ACK}, voice::gateway::VoiceGatewayMessage, }; -use super::Sink; - /// Handles sending heartbeats to the voice gateway in another thread #[allow(dead_code)] // FIXME: Remove this, once all fields of VoiceHeartbeatHandler are used #[derive(Debug)] From 03f1e7d983fe4e33ce54c47396114a74e35fa120 Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Sun, 5 May 2024 14:43:23 +0200 Subject: [PATCH 005/162] Refactor / fix login and register (#495) Change login and register to only use one ChorusUser object, change the api of related methods which were also somewhat ugly --- src/api/auth/login.rs | 31 +++++++++------------ src/api/auth/mod.rs | 31 ++++++++------------- src/api/auth/register.rs | 34 ++++++++++------------- src/api/users/users.rs | 60 ++++++++-------------------------------- 4 files changed, 51 insertions(+), 105 deletions(-) diff --git a/src/api/auth/login.rs b/src/api/auth/login.rs index 7689af75..7c58e0e7 100644 --- a/src/api/auth/login.rs +++ b/src/api/auth/login.rs @@ -11,7 +11,7 @@ use crate::errors::ChorusResult; use crate::gateway::Gateway; use crate::instance::{ChorusUser, Instance}; use crate::ratelimiter::ChorusRequest; -use crate::types::{GatewayIdentifyPayload, LimitType, LoginResult, LoginSchema}; +use crate::types::{GatewayIdentifyPayload, LimitType, LoginResult, LoginSchema, User}; impl Instance { /// Logs into an existing account on the spacebar server. @@ -30,27 +30,22 @@ impl Instance { // We do not have a user yet, and the UserRateLimits will not be affected by a login // request (since login is an instance wide limit), which is why we are just cloning the // instances' limits to pass them on as user_rate_limits later. - let mut shell = + let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None".to_string()).await; + let login_result = chorus_request - .deserialize_response::(&mut shell) + .deserialize_response::(&mut user) .await?; - let object = self.get_user(login_result.token.clone(), None).await?; - if self.limits_information.is_some() { - self.limits_information.as_mut().unwrap().ratelimits = shell.limits.clone().unwrap(); - } + user.set_token(login_result.token); + user.settings = login_result.settings; + + let object = User::get(&mut user, None).await?; + *user.object.write().unwrap() = object; + let mut identify = GatewayIdentifyPayload::common(); - let gateway = Gateway::spawn(self.urls.wss.clone()).await.unwrap(); - identify.token = login_result.token.clone(); - gateway.send_identify(identify).await; - let user = ChorusUser::new( - Arc::new(RwLock::new(self.clone())), - login_result.token, - self.clone_limits_if_some(), - login_result.settings, - Arc::new(RwLock::new(object)), - gateway, - ); + identify.token = user.token(); + user.gateway.send_identify(identify).await; + Ok(user) } } diff --git a/src/api/auth/mod.rs b/src/api/auth/mod.rs index 5bd539f6..498080e8 100644 --- a/src/api/auth/mod.rs +++ b/src/api/auth/mod.rs @@ -23,26 +23,19 @@ 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 { - 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 user = + ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await; + + let object = User::get(&mut user, None).await?; + let settings = User::get_settings(&mut user).await?; + + *user.object.write().unwrap() = object; + *user.settings.write().unwrap() = settings; + let mut identify = GatewayIdentifyPayload::common(); - let gateway = Gateway::spawn(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, - ); + identify.token = user.token(); + user.gateway.send_identify(identify).await; + Ok(user) } } diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs index deece4db..6b94a4d7 100644 --- a/src/api/auth/register.rs +++ b/src/api/auth/register.rs @@ -8,7 +8,7 @@ use reqwest::Client; use serde_json::to_string; use crate::gateway::{Gateway, GatewayHandle}; -use crate::types::GatewayIdentifyPayload; +use crate::types::{GatewayIdentifyPayload, User}; use crate::{ errors::ChorusResult, instance::{ChorusUser, Instance, Token}, @@ -37,29 +37,25 @@ impl Instance { // We do not have a user yet, and the UserRateLimits will not be affected by a login // request (since register is an instance wide limit), which is why we are just cloning // the instances' limits to pass them on as user_rate_limits later. - let mut shell = + let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None".to_string()).await; + let token = chorus_request - .deserialize_response::(&mut shell) + .deserialize_response::(&mut user) .await? .token; - if self.limits_information.is_some() { - self.limits_information.as_mut().unwrap().ratelimits = shell.limits.unwrap(); - } - let user_object = self.get_user(token.clone(), None).await.unwrap(); - let settings = ChorusUser::get_settings(&token, &self.urls.api.clone(), self).await?; + user.set_token(token); + + let object = User::get(&mut user, None).await?; + let settings = User::get_settings(&mut user).await?; + + *user.object.write().unwrap() = object; + *user.settings.write().unwrap() = settings; + let mut identify = GatewayIdentifyPayload::common(); - let gateway: GatewayHandle = Gateway::spawn(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(settings)), - Arc::new(RwLock::new(user_object)), - gateway, - ); + identify.token = user.token(); + user.gateway.send_identify(identify).await; + Ok(user) } } diff --git a/src/api/users/users.rs b/src/api/users/users.rs index b80bc1e2..61017132 100644 --- a/src/api/users/users.rs +++ b/src/api/users/users.rs @@ -30,13 +30,9 @@ impl ChorusUser { /// Gets the user's settings. /// /// # Notes - /// This functions is a wrapper around [`User::get_settings`]. - pub async fn get_settings( - token: &String, - url_api: &String, - instance: &mut Instance, - ) -> ChorusResult { - User::get_settings(token, url_api, instance).await + /// This function is a wrapper around [`User::get_settings`]. + pub async fn get_settings(&mut self) -> ChorusResult { + User::get_settings(self).await } /// Modifies the current user's representation. (See [`User`]) @@ -118,56 +114,22 @@ impl User { /// /// # Reference /// See - pub async fn get_settings( - token: &String, - url_api: &String, - instance: &mut Instance, - ) -> ChorusResult { + pub async fn get_settings(user: &mut ChorusUser) -> ChorusResult { + let url_api = user.belongs_to.read().unwrap().urls.api.clone(); let request: reqwest::RequestBuilder = Client::new() .get(format!("{}/users/@me/settings", url_api)) - .header("Authorization", token); - let mut user = - ChorusUser::shell(Arc::new(RwLock::new(instance.clone())), token.clone()).await; + .header("Authorization", user.token()); let chorus_request = ChorusRequest { request, limit_type: LimitType::Global, }; - let result = match chorus_request.send_request(&mut user).await { - Ok(result) => Ok(serde_json::from_str(&result.text().await.unwrap()).unwrap()), + match chorus_request.send_request(user).await { + Ok(result) => { + let result_text = result.text().await.unwrap(); + Ok(serde_json::from_str(&result_text).unwrap()) + } Err(e) => Err(e), - }; - if instance.limits_information.is_some() { - instance.limits_information.as_mut().unwrap().ratelimits = user - .belongs_to - .read() - .unwrap() - .clone_limits_if_some() - .unwrap(); } - result } } -impl Instance { - /// Gets a user by id, or if the id is None, gets the current user. - /// - /// # Notes - /// This function is a wrapper around [`User::get`]. - /// - /// # Reference - /// See and - /// - pub async fn get_user(&mut self, token: String, id: Option<&String>) -> ChorusResult { - let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await; - let result = User::get(&mut user, id).await; - if self.limits_information.is_some() { - self.limits_information.as_mut().unwrap().ratelimits = user - .belongs_to - .read() - .unwrap() - .clone_limits_if_some() - .unwrap(); - } - result - } -} From c44dd269dd9ce7e061d1e62c8dea8aa1abcfaa5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Szab=C3=B3?= Date: Fri, 10 May 2024 22:12:03 +0300 Subject: [PATCH 006/162] Add the repository field to Cargo.toml --- chorus-macros/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/chorus-macros/Cargo.toml b/chorus-macros/Cargo.toml index 272d99f5..ac97fb19 100644 --- a/chorus-macros/Cargo.toml +++ b/chorus-macros/Cargo.toml @@ -4,6 +4,7 @@ version = "0.2.0" edition = "2021" license = "AGPL-3.0" description = "Macros for the chorus crate." +repository = "https://github.com/polyphony-chat/chorus" [lib] proc-macro = true From d4377c52801e61b0dda6661628ed145e4c53d776 Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Sun, 2 Jun 2024 19:28:02 +0200 Subject: [PATCH 007/162] Ci improvements (#498) * bump wasm-bindgen version to 0.2.92 * change wasm-gecko to using ubuntu-latest, since geckodriver is not supported on macos-latest * check some common non-default feature configurations * add experimental semver checks --- .github/workflows/build_and_test.yml | 26 +++++++++++++++++++++++--- Cargo.lock | 20 ++++++++++---------- semver_release_checks.yml | 18 ++++++++++++++++++ 3 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 semver_release_checks.yml diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 0f680ccd..d0ddba58 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -46,6 +46,26 @@ jobs: cargo build --verbose --all-features cargo test --verbose --all-features fi + - name: Check common non-default feature configurations + run: | + echo "No features:" + cargo check --features="" --no-default-features + echo "Only client:" + cargo check --features="client" --no-default-features + echo "Only backend:" + cargo check --features="backend" --no-default-features + echo "Only voice:" + cargo check --features="voice" --no-default-features + echo "Only voice gateway:" + cargo check --features="voice_gateway" --no-default-features + echo "Backend + client:" + cargo check --features="backend, client" --no-default-features + echo "Backend + voice:" + cargo check --features="backend, voice" --no-default-features + echo "Backend + voice gateway:" + cargo check --features="backend, voice_gateway" --no-default-features + echo "Client + voice gateway:" + cargo check --features="client, voice_gateway" --no-default-features # wasm-safari: # runs-on: macos-latest # steps: @@ -75,7 +95,7 @@ jobs: # cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.88" --force # SAFARIDRIVER=$(which safaridriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt" --no-fail-fast wasm-gecko: - runs-on: macos-latest + runs-on: ubuntu-latest timeout-minutes: 30 steps: - uses: actions/checkout@v4 @@ -101,7 +121,7 @@ jobs: run: | rustup target add wasm32-unknown-unknown curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.88" --force + cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force GECKODRIVER=$(which geckodriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" wasm-chrome: runs-on: macos-latest @@ -130,5 +150,5 @@ jobs: run: | rustup target add wasm32-unknown-unknown curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.88" --force + cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force CHROMEDRIVER=$(which chromedriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" diff --git a/Cargo.lock b/Cargo.lock index 53283ccf..0d0cb0cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2727,9 +2727,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2737,9 +2737,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", @@ -2764,9 +2764,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2774,9 +2774,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", @@ -2787,9 +2787,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-bindgen-test" diff --git a/semver_release_checks.yml b/semver_release_checks.yml new file mode 100644 index 00000000..12dd718f --- /dev/null +++ b/semver_release_checks.yml @@ -0,0 +1,18 @@ +name: Semver release checks + +on: + pull_request: + branches: ["main"] + +env: + CARGO_TERM_COLOR: always + +jobs: + semver-checks: + + runs-on: ubuntu-latest + timeout-minutes: 60 + + steps: + - uses: actions/checkout@v4 + - uses: obi1kenobi/cargo-semver-checks-action@v2 From f876f25a2ca464fae4410829e0a407c771cb1f8e Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Sun, 2 Jun 2024 18:00:07 -0400 Subject: [PATCH 008/162] Update poem dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a31a9da8..936e1499 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ http = "0.2.11" base64 = "0.21.7" bitflags = { version = "2.4.1", features = ["serde"] } lazy_static = "1.4.0" -poem = { version = "1.3.59", optional = true } +poem = { version = "3.0.1", optional = true } thiserror = "1.0.56" jsonwebtoken = "8.3.0" log = "0.4.20" From d1b3a9ad9efc2183c9d16105d094d125fff9d533 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Sun, 2 Jun 2024 18:09:43 -0400 Subject: [PATCH 009/162] Convert timestamp fields to DateTime's --- src/types/entities/channel.rs | 12 +- src/types/entities/guild.rs | 5 +- src/types/entities/guild_member.rs | 8 +- src/types/entities/message.rs | 9 +- src/types/schema/auth.rs | 5 +- src/types/utils/mod.rs | 2 + src/types/utils/serde.rs | 263 +++++++++++++++++++++++++++++ 7 files changed, 292 insertions(+), 12 deletions(-) create mode 100644 src/types/utils/serde.rs diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index fd0c077b..dc1e6ad7 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -11,7 +11,7 @@ use std::fmt::Debug; use crate::types::Shared; use crate::types::{ entities::{GuildMember, User}, - utils::Snowflake, + utils::{Snowflake, serde::*}, }; #[cfg(feature = "client")] @@ -60,6 +60,7 @@ pub struct Channel { pub icon: Option, pub id: Snowflake, pub last_message_id: Option, + #[serde(with = "ts_seconds_option_str")] pub last_pin_timestamp: Option>, pub managed: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] @@ -160,10 +161,12 @@ pub struct PermissionOverwrite { pub struct ThreadMetadata { pub archived: bool, pub auto_archive_duration: i32, - pub archive_timestamp: String, + #[serde(with = "ts_seconds_str")] + pub archive_timestamp: DateTime, pub locked: bool, pub invitable: Option, - pub create_timestamp: Option, + #[serde(with = "ts_seconds_option_str")] + pub create_timestamp: Option>, } #[derive(Default, Debug, Deserialize, Serialize, Clone)] @@ -172,7 +175,8 @@ pub struct ThreadMetadata { pub struct ThreadMember { pub id: Option, pub user_id: Option, - pub join_timestamp: Option, + #[serde(with = "ts_seconds_option_str")] + pub join_timestamp: Option>, pub flags: Option, pub member: Option>, } diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 2b7ae441..b2590564 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -14,7 +14,7 @@ use crate::types::types::guild_configuration::GuildFeaturesList; use crate::types::{ entities::{Channel, Emoji, RoleObject, Sticker, User, VoiceState, Webhook}, interfaces::WelcomeScreenObject, - utils::Snowflake, + utils::{Snowflake, serde::*}, }; use super::PublicUser; @@ -67,7 +67,8 @@ pub struct Guild { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub invites: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub joined_at: Option, + #[serde(with = "ts_seconds_option_str")] + pub joined_at: Option>, pub large: Option, pub max_members: Option, pub max_presences: Option, diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index 5cd5ad13..2a3c184d 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -2,10 +2,12 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::types::Shared; use crate::types::{entities::PublicUser, Snowflake}; +use crate::types::utils::serde::*; #[derive(Debug, Deserialize, Default, Serialize, Clone)] /// Represents a participating user in a guild. @@ -17,12 +19,14 @@ pub struct GuildMember { pub nick: Option, pub avatar: Option, pub roles: Vec, - pub joined_at: String, + #[serde(with = "ts_seconds_str")] + pub joined_at: DateTime, pub premium_since: Option, pub deaf: bool, pub mute: bool, pub flags: Option, pub pending: Option, pub permissions: Option, - pub communication_disabled_until: Option, + #[serde(with = "ts_seconds_option_str")] + pub communication_disabled_until: Option>, } diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index e03a0784..607ccf25 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -2,6 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::types::{ @@ -10,7 +11,7 @@ use crate::types::{ Application, Attachment, Channel, Emoji, GuildMember, PublicUser, RoleSubscriptionData, Sticker, StickerItem, User, }, - utils::Snowflake, + utils::{Snowflake, serde::*}, }; #[derive(Debug, Serialize, Deserialize, Default, Clone)] @@ -25,8 +26,10 @@ pub struct Message { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub author: Option, pub content: Option, - pub timestamp: String, - pub edited_timestamp: Option, + #[serde(with = "ts_seconds_str")] + pub timestamp: DateTime, + #[serde(with = "ts_seconds_option_str")] + pub edited_timestamp: Option>, pub tts: Option, pub mention_everyone: bool, #[cfg_attr(feature = "sqlx", sqlx(skip))] diff --git a/src/types/schema/auth.rs b/src/types/schema/auth.rs index 27968059..c1c1f555 100644 --- a/src/types/schema/auth.rs +++ b/src/types/schema/auth.rs @@ -2,7 +2,9 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; +use crate::types::utils::serde::ts_seconds_option_str; #[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] @@ -13,7 +15,8 @@ pub struct RegisterSchema { pub email: Option, pub fingerprint: Option, pub invite: Option, - pub date_of_birth: Option, + #[serde(with = "ts_seconds_option_str")] + pub date_of_birth: Option>, pub gift_code_sku_id: Option, pub captcha_key: Option, pub promotional_email_opt_in: Option, diff --git a/src/types/utils/mod.rs b/src/types/utils/mod.rs index 88796887..5608fe74 100644 --- a/src/types/utils/mod.rs +++ b/src/types/utils/mod.rs @@ -11,3 +11,5 @@ pub mod jwt; mod regexes; mod rights; mod snowflake; +pub mod serde; + diff --git a/src/types/utils/serde.rs b/src/types/utils/serde.rs new file mode 100644 index 00000000..28d6e606 --- /dev/null +++ b/src/types/utils/serde.rs @@ -0,0 +1,263 @@ +use core::fmt; +use chrono::{LocalResult, NaiveDateTime}; +use serde::de; +use chrono::serde::ts_seconds; + +#[doc(hidden)] +#[derive(Debug)] +pub struct SecondsStringTimestampVisitor; + + +/// Ser/de to/from timestamps in seconds +/// +/// Intended for use with `serde`'s `with` attribute. +/// +/// # Example: +/// +/// ```rust +/// # use chrono::{TimeZone, DateTime, Utc}; +/// # use serde::{Deserialize, Serialize}; +/// use chrono::serde::ts_seconds; +/// #[derive(Deserialize, Serialize)] +/// struct S { +/// #[serde(with = "ts_seconds_str")] +/// time: DateTime +/// } +/// +/// let time = Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap(); +/// let my_s = S { +/// time: time.clone(), +/// }; +/// +/// let as_string = serde_json::to_string(&my_s)?; +/// assert_eq!(as_string, r#"{"time":"1431684000"}"#); +/// let my_s: S = serde_json::from_str(&as_string)?; +/// assert_eq!(my_s.time, time); +/// # Ok::<(), serde_json::Error>(()) +/// ``` + +pub mod ts_seconds_str { + use core::fmt; + use chrono::{DateTime, LocalResult, Utc}; + use super::SecondsStringTimestampVisitor; + use serde::{de, ser}; + use chrono::TimeZone; + use super::serde_from; + + /// Serialize a UTC datetime into an integer number of seconds since the epoch + /// + /// Intended for use with `serde`s `serialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # use chrono::{TimeZone, DateTime, Utc}; + /// # use serde::Serialize; + /// use chrono::serde::ts_seconds::serialize as to_ts; + /// #[derive(Serialize)] + /// struct S { + /// #[serde(serialize_with = "ts_seconds_str")] + /// time: DateTime + /// } + /// + /// let my_s = S { + /// time: Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap(), + /// }; + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); + /// # Ok::<(), serde_json::Error>(()) + /// ``` + pub fn serialize(dt: &DateTime, serializer: S) -> Result + where + S: ser::Serializer, + { + serializer.serialize_str(&format!("{}", dt.timestamp())) + } + + /// Deserialize a `DateTime` from a seconds timestamp + /// + /// Intended for use with `serde`s `deserialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # use chrono::{DateTime, TimeZone, Utc}; + /// # use serde::Deserialize; + /// use chrono::serde::ts_seconds::deserialize as from_ts; + /// #[derive(Debug, PartialEq, Deserialize)] + /// struct S { + /// #[serde(deserialize_with = "ts_seconds_str")] + /// time: DateTime + /// } + /// + /// let my_s: S = serde_json::from_str(r#"{ "time": "1431684000" }"#)?; + /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).unwrap() }); + /// # Ok::<(), serde_json::Error>(()) + /// ``` + pub fn deserialize<'de, D>(d: D) -> Result, D::Error> + where + D: de::Deserializer<'de>, + { + d.deserialize_str(SecondsStringTimestampVisitor) + } + + impl<'de> de::Visitor<'de> for SecondsStringTimestampVisitor { + type Value = DateTime; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a unix timestamp in seconds") + } + + /// Deserialize a timestamp in seconds since the epoch + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + serde_from(Utc.timestamp_opt(value.parse::().map_err(|e| E::custom(e))?, 0), &value) + } + } +} + +/// Ser/de to/from optional timestamps in seconds +/// +/// Intended for use with `serde`'s `with` attribute. +/// +/// # Example: +/// +/// ```rust +/// # use chrono::{TimeZone, DateTime, Utc}; +/// # use serde::{Deserialize, Serialize}; +/// use chrono::serde::ts_seconds_option; +/// #[derive(Deserialize, Serialize)] +/// struct S { +/// #[serde(with = "ts_seconds_option_str")] +/// time: Option> +/// } +/// +/// let time = Some(Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap()); +/// let my_s = S { +/// time: time.clone(), +/// }; +/// +/// let as_string = serde_json::to_string(&my_s)?; +/// assert_eq!(as_string, r#"{"time":"1431684000"}"#); +/// let my_s: S = serde_json::from_str(&as_string)?; +/// assert_eq!(my_s.time, time); +/// # Ok::<(), serde_json::Error>(()) +/// ``` +pub mod ts_seconds_option_str { + use core::fmt; + use chrono::{DateTime, Utc}; + use serde::{de, ser}; + use super::SecondsStringTimestampVisitor; + + /// Serialize a UTC datetime into an integer number of seconds since the epoch or none + /// + /// Intended for use with `serde`s `serialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # use chrono::{TimeZone, DateTime, Utc}; + /// # use serde::Serialize; + /// use chrono::serde::ts_seconds_option::serialize as to_tsopt; + /// #[derive(Serialize)] + /// struct S { + /// #[serde(serialize_with = "ts_seconds_option_str")] + /// time: Option> + /// } + /// + /// let my_s = S { + /// time: Some(Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap()), + /// }; + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); + /// # Ok::<(), serde_json::Error>(()) + /// ``` + pub fn serialize(opt: &Option>, serializer: S) -> Result + where + S: ser::Serializer, + { + match *opt { + Some(ref dt) => serializer.serialize_some(&dt.timestamp().to_string()), + None => serializer.serialize_none(), + } + } + + /// Deserialize a `DateTime` from a seconds timestamp or none + /// + /// Intended for use with `serde`s `deserialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # use chrono::{DateTime, TimeZone, Utc}; + /// # use serde::Deserialize; + /// use chrono::serde::ts_seconds_option::deserialize as from_tsopt; + /// #[derive(Debug, PartialEq, Deserialize)] + /// struct S { + /// #[serde(deserialize_with = "ts_seconds_option_str")] + /// time: Option> + /// } + /// + /// let my_s: S = serde_json::from_str(r#"{ "time": "1431684000" }"#)?; + /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).single() }); + /// # Ok::<(), serde_json::Error>(()) + /// ``` + pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> + where + D: de::Deserializer<'de>, + { + d.deserialize_option(OptionSecondsTimestampVisitor) + } + + struct OptionSecondsTimestampVisitor; + + impl<'de> de::Visitor<'de> for OptionSecondsTimestampVisitor { + type Value = Option>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a unix timestamp in seconds or none") + } + + /// Deserialize a timestamp in seconds since the epoch + fn visit_some(self, d: D) -> Result + where + D: de::Deserializer<'de>, + { + d.deserialize_str(SecondsStringTimestampVisitor).map(Some) + } + + /// Deserialize a timestamp in seconds since the epoch + fn visit_none(self) -> Result + where + E: de::Error, + { + Ok(None) + } + + /// Deserialize a timestamp in seconds since the epoch + fn visit_unit(self) -> Result + where + E: de::Error, + { + Ok(None) + } + } +} + +pub(crate) fn serde_from(me: LocalResult, ts: &V) -> Result + where + E: de::Error, + V: fmt::Display, + T: fmt::Display, +{ + // TODO: Make actual error type + match me { + LocalResult::None => Err(E::custom("value is not a legal timestamp")), + LocalResult::Ambiguous(min, max) => { + Err(E::custom("value is an ambiguous timestamp")) + } + LocalResult::Single(val) => Ok(val), + } +} \ No newline at end of file From c44521320d5ca68d7a43324621624b72d70d3db9 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Sun, 2 Jun 2024 18:10:57 -0400 Subject: [PATCH 010/162] Feature lock different types for UserSettings::status --- src/types/entities/user_settings.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/types/entities/user_settings.rs b/src/types/entities/user_settings.rs index db13efc9..1eef5d2e 100644 --- a/src/types/entities/user_settings.rs +++ b/src/types/entities/user_settings.rs @@ -83,6 +83,9 @@ pub struct UserSettings { #[cfg(not(feature = "sqlx"))] pub restricted_guilds: Vec, pub show_current_game: bool, + #[cfg(feature = "sqlx")] + pub status: UserStatus, + #[cfg(not(feature = "sqlx"))] pub status: Shared, pub stream_notifications_enabled: bool, pub theme: UserTheme, @@ -119,7 +122,7 @@ impl Default for UserSettings { render_reactions: true, restricted_guilds: Default::default(), show_current_game: true, - status: Arc::new(RwLock::new(UserStatus::Online)), + status: Default::default(), stream_notifications_enabled: false, theme: UserTheme::Dark, timezone_offset: 0, From 7b7294433b957e86dd7d0988581f2ed1cfe34c2f Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Sun, 2 Jun 2024 18:11:39 -0400 Subject: [PATCH 011/162] Make config register_configuration use Rights bitflag object --- src/types/config/types/register_configuration.rs | 8 ++++---- src/types/utils/rights.rs | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/types/config/types/register_configuration.rs b/src/types/config/types/register_configuration.rs index a4573bfd..19cedfb6 100644 --- a/src/types/config/types/register_configuration.rs +++ b/src/types/config/types/register_configuration.rs @@ -4,9 +4,9 @@ use serde::{Deserialize, Serialize}; -use crate::types::config::types::subconfigs::register::{ +use crate::types::{config::types::subconfigs::register::{ DateOfBirthConfiguration, PasswordConfiguration, RegistrationEmailConfiguration, -}; +}, Rights}; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -22,7 +22,7 @@ pub struct RegisterConfiguration { pub allow_multiple_accounts: bool, pub block_proxies: bool, pub incrementing_discriminators: bool, - pub default_rights: String, + pub default_rights: Rights, } impl Default for RegisterConfiguration { @@ -39,7 +39,7 @@ impl Default for RegisterConfiguration { allow_multiple_accounts: true, block_proxies: true, incrementing_discriminators: false, - default_rights: String::from("875069521787904"), + default_rights: Rights::from_bits(648540060672).expect("failed to parse default_rights"), } } } diff --git a/src/types/utils/rights.rs b/src/types/utils/rights.rs index 4b1aa138..63bbeb2a 100644 --- a/src/types/utils/rights.rs +++ b/src/types/utils/rights.rs @@ -3,6 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use bitflags::bitflags; +use serde::{Deserialize, Serialize}; bitflags! { /// Rights are instance-wide, per-user permissions for everything you may perform on the instance, @@ -14,6 +15,7 @@ bitflags! { /// /// # Reference /// See + #[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)] pub struct Rights: u64 { /// All rights const OPERATOR = 1 << 0; @@ -151,6 +153,12 @@ impl Rights { } } +impl Default for Rights { + fn default() -> Self { + Self::empty() + } +} + #[allow(dead_code)] // FIXME: Remove this when we use this fn all_rights() -> Rights { Rights::OPERATOR From ab4435a79faa570bb7c69e87688bd33163ae64e9 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Sun, 2 Jun 2024 18:12:52 -0400 Subject: [PATCH 012/162] Update tests to use DateTime's for timestamps --- tests/auth.rs | 8 +++++--- tests/common/mod.rs | 6 ++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/auth.rs b/tests/auth.rs index 35007f1d..6266aa39 100644 --- a/tests/auth.rs +++ b/tests/auth.rs @@ -2,6 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use std::str::FromStr; +use chrono::DateTime; use chorus::types::{LoginSchema, RegisterSchema}; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; @@ -16,7 +18,7 @@ async fn test_registration() { let mut bundle = common::setup().await; let reg = RegisterSchema { username: "Hiiii".into(), - date_of_birth: Some("2000-01-01".to_string()), + date_of_birth: Some(DateTime::from_str("2000-01-01").unwrap()), consent: true, ..Default::default() }; @@ -32,7 +34,7 @@ async fn test_login() { username: "Hiiii".into(), email: Some("testuser1@integrationtesting.xyz".into()), password: Some("Correct-Horse-Battery-Staple1".into()), - date_of_birth: Some("2000-01-01".to_string()), + date_of_birth: Some(DateTime::from_str("2000-01-01").unwrap()), consent: true, ..Default::default() }; @@ -54,7 +56,7 @@ async fn test_wrong_login() { username: "Hiiii".into(), email: Some("testuser2@integrationtesting.xyz".into()), password: Some("Correct-Horse-Battery-Staple1".into()), - date_of_birth: Some("2000-01-01".to_string()), + date_of_birth: Some(DateTime::from_str("2000-01-01").unwrap()), consent: true, ..Default::default() }; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index a98667c8..4abedd5e 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -2,6 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use std::str::FromStr; +use chrono::DateTime; use chorus::gateway::Gateway; use chorus::types::IntoShared; use chorus::{ @@ -30,7 +32,7 @@ impl TestBundle { let register_schema = RegisterSchema { username: username.to_string(), consent: true, - date_of_birth: Some("2000-01-01".to_string()), + date_of_birth: Some(DateTime::from_str("2000-01-01").unwrap()), ..Default::default() }; self.instance @@ -60,7 +62,7 @@ pub(crate) async fn setup() -> TestBundle { let reg = RegisterSchema { username: "integrationtestuser".into(), consent: true, - date_of_birth: Some("2000-01-01".to_string()), + date_of_birth: Some(DateTime::from_str("2000-01-01").unwrap()), ..Default::default() }; let guild_create_schema = GuildCreateSchema { From 08952db0141bff12a247e15db1a50c1b79d9c9dd Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Sun, 2 Jun 2024 19:02:36 -0400 Subject: [PATCH 013/162] Fix tests --- tests/auth.rs | 7 +++---- tests/common/mod.rs | 5 ++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/auth.rs b/tests/auth.rs index 6266aa39..a2f2c3f7 100644 --- a/tests/auth.rs +++ b/tests/auth.rs @@ -2,7 +2,6 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::str::FromStr; use chrono::DateTime; use chorus::types::{LoginSchema, RegisterSchema}; #[cfg(target_arch = "wasm32")] @@ -18,7 +17,7 @@ async fn test_registration() { let mut bundle = common::setup().await; let reg = RegisterSchema { username: "Hiiii".into(), - date_of_birth: Some(DateTime::from_str("2000-01-01").unwrap()), + date_of_birth: Some(DateTime::from_timestamp(978325200, 0).unwrap()), consent: true, ..Default::default() }; @@ -34,7 +33,7 @@ async fn test_login() { username: "Hiiii".into(), email: Some("testuser1@integrationtesting.xyz".into()), password: Some("Correct-Horse-Battery-Staple1".into()), - date_of_birth: Some(DateTime::from_str("2000-01-01").unwrap()), + date_of_birth: Some(DateTime::from_timestamp(978325200, 0).unwrap()), consent: true, ..Default::default() }; @@ -56,7 +55,7 @@ async fn test_wrong_login() { username: "Hiiii".into(), email: Some("testuser2@integrationtesting.xyz".into()), password: Some("Correct-Horse-Battery-Staple1".into()), - date_of_birth: Some(DateTime::from_str("2000-01-01").unwrap()), + date_of_birth: Some(DateTime::from_timestamp(978325200, 0).unwrap()), consent: true, ..Default::default() }; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 4abedd5e..a07e5035 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -2,7 +2,6 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::str::FromStr; use chrono::DateTime; use chorus::gateway::Gateway; use chorus::types::IntoShared; @@ -32,7 +31,7 @@ impl TestBundle { let register_schema = RegisterSchema { username: username.to_string(), consent: true, - date_of_birth: Some(DateTime::from_str("2000-01-01").unwrap()), + date_of_birth: Some(DateTime::from_timestamp(978325200, 0).unwrap()), ..Default::default() }; self.instance @@ -62,7 +61,7 @@ pub(crate) async fn setup() -> TestBundle { let reg = RegisterSchema { username: "integrationtestuser".into(), consent: true, - date_of_birth: Some(DateTime::from_str("2000-01-01").unwrap()), + date_of_birth: Some(DateTime::from_timestamp(978325200, 0).unwrap()), ..Default::default() }; let guild_create_schema = GuildCreateSchema { From 8c5d80d3f1d8992dbe319fc0eadbc16b6fe9b897 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Sun, 2 Jun 2024 19:18:43 -0400 Subject: [PATCH 014/162] Allow joined_at to default if field is not in responses. --- src/types/entities/guild.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index b2590564..af6f1530 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -67,7 +67,7 @@ pub struct Guild { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub invites: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] - #[serde(with = "ts_seconds_option_str")] + #[serde(with = "ts_seconds_option_str", default)] pub joined_at: Option>, pub large: Option, pub max_members: Option, From a75701d9c6483cc3a68a9bc3de3fac694514bdf4 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Sun, 2 Jun 2024 20:06:01 -0400 Subject: [PATCH 015/162] Allow last_pin_timestamp to default if field is not in responses. --- src/types/entities/channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index dc1e6ad7..b5e604de 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -60,7 +60,7 @@ pub struct Channel { pub icon: Option, pub id: Snowflake, pub last_message_id: Option, - #[serde(with = "ts_seconds_option_str")] + #[serde(with = "ts_seconds_option_str", default)] pub last_pin_timestamp: Option>, pub managed: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] From eefdd4aebfccc344f3e006f003759a493a973dd0 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Sun, 2 Jun 2024 20:17:48 -0400 Subject: [PATCH 016/162] Remove serde(with) for message timestamps --- src/types/entities/message.rs | 62 +++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index 607ccf25..4f444e35 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -26,9 +26,9 @@ pub struct Message { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub author: Option, pub content: Option, - #[serde(with = "ts_seconds_str")] + // #[serde(with = "ts_seconds_str")] pub timestamp: DateTime, - #[serde(with = "ts_seconds_option_str")] + // #[serde(with = "ts_seconds_option_str")] pub edited_timestamp: Option>, pub tts: Option, pub mention_everyone: bool, @@ -255,3 +255,61 @@ pub struct MessageActivity { pub activity_type: i64, pub party_id: Option, } + +#[cfg(test)] +mod tests { + #[test] + fn test_deserialize_message() { + let raw = r#"{ + "id":"1246967362553443002", + "channel_id":"1246967361836216935", + "guild_id":"1246967361001550368", + "author":{ + "username":"integrationtestuser", + "discriminator":"3864", + "id":"1246967359860699591", + "public_flags":0, + "avatar":null, + "accent_color":null, + "banner":null, + "bio":"", + "bot":false, + "premium_since":"2024-06-02T23:23:06.124+00:00", + "premium_type":2, + "theme_colors":null, + "pronouns":null + }, + "member":{ + "index":142, + "id":"1246967359860699591", + "guild_id":"1246967361001550368", + "nick":null, + "joined_at":"2024-06-02T23:23:06.526+00:00", + "premium_since":null,"deaf":false,"mute":false,"pending":false, + "last_message_id":null, + "joined_by":null, + "avatar":null, + "banner":null, + "bio":"", + "theme_colors":null, + "pronouns":null, + "communication_disabled_until":null, + "roles":[] + }, + "content":"A Message!", + "timestamp":"2024-06-02T23:23:06.762+00:00", + "edited_timestamp":null, + "tts":false, + "mention_everyone":false, + "mentions":[], + "mention_roles":[], + "attachments":[], + "embeds":[], + "reactions":[], + "pinned":false, + "type":0, + "flags":null + }"#; + let message: super::Message = serde_json::from_str(raw).unwrap(); + } +} \ No newline at end of file From eb087938ed48f348de2ed299f07f464efd865719 Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Mon, 3 Jun 2024 07:32:11 +0200 Subject: [PATCH 017/162] Fix some iso timestamps being strings, not DateTime (#499) * fix: some iso timestamps being strings * fix: register uses dates, not datetimes --- src/types/entities/channel.rs | 6 +++--- src/types/entities/guild.rs | 2 +- src/types/entities/guild_member.rs | 7 ++++--- src/types/entities/message.rs | 5 +++-- src/types/events/channel.rs | 2 +- src/types/schema/auth.rs | 4 +++- tests/auth.rs | 10 +++++++--- tests/common/mod.rs | 8 ++++++-- 8 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index fd0c077b..262897c2 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -160,10 +160,10 @@ pub struct PermissionOverwrite { pub struct ThreadMetadata { pub archived: bool, pub auto_archive_duration: i32, - pub archive_timestamp: String, + pub archive_timestamp: DateTime, pub locked: bool, pub invitable: Option, - pub create_timestamp: Option, + pub create_timestamp: Option>, } #[derive(Default, Debug, Deserialize, Serialize, Clone)] @@ -172,7 +172,7 @@ pub struct ThreadMetadata { pub struct ThreadMember { pub id: Option, pub user_id: Option, - pub join_timestamp: Option, + pub join_timestamp: Option>, pub flags: Option, pub member: Option>, } diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 2b7ae441..8544b0ba 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -67,7 +67,7 @@ pub struct Guild { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub invites: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub joined_at: Option, + pub joined_at: Option>, pub large: Option, pub max_members: Option, pub max_presences: Option, diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index 5cd5ad13..66fad99d 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -2,6 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::types::Shared; @@ -17,12 +18,12 @@ pub struct GuildMember { pub nick: Option, pub avatar: Option, pub roles: Vec, - pub joined_at: String, - pub premium_since: Option, + pub joined_at: DateTime, + pub premium_since: Option>, pub deaf: bool, pub mute: bool, pub flags: Option, pub pending: Option, pub permissions: Option, - pub communication_disabled_until: Option, + pub communication_disabled_until: Option>, } diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index e03a0784..4b57e062 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -2,6 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::types::{ @@ -25,8 +26,8 @@ pub struct Message { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub author: Option, pub content: Option, - pub timestamp: String, - pub edited_timestamp: Option, + pub timestamp: DateTime, + pub edited_timestamp: Option>, pub tts: Option, pub mention_everyone: bool, #[cfg_attr(feature = "sqlx", sqlx(skip))] diff --git a/src/types/events/channel.rs b/src/types/events/channel.rs index 911f2491..dd167542 100644 --- a/src/types/events/channel.rs +++ b/src/types/events/channel.rs @@ -96,7 +96,7 @@ pub struct ChannelUnreadUpdate { pub struct ChannelUnreadUpdateObject { pub id: Snowflake, pub last_message_id: Snowflake, - pub last_pin_timestamp: Option, + pub last_pin_timestamp: Option>, } #[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField, WebSocketEvent)] diff --git a/src/types/schema/auth.rs b/src/types/schema/auth.rs index 27968059..83c88dc0 100644 --- a/src/types/schema/auth.rs +++ b/src/types/schema/auth.rs @@ -2,6 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use chrono::NaiveDate; use serde::{Deserialize, Serialize}; #[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)] @@ -13,7 +14,8 @@ pub struct RegisterSchema { pub email: Option, pub fingerprint: Option, pub invite: Option, - pub date_of_birth: Option, + /// The user's date of birth, serialized as an ISO8601 date + pub date_of_birth: Option, pub gift_code_sku_id: Option, pub captcha_key: Option, pub promotional_email_opt_in: Option, diff --git a/tests/auth.rs b/tests/auth.rs index 35007f1d..705328ae 100644 --- a/tests/auth.rs +++ b/tests/auth.rs @@ -2,12 +2,16 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use std::str::FromStr; + use chorus::types::{LoginSchema, RegisterSchema}; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; #[cfg(target_arch = "wasm32")] wasm_bindgen_test_configure!(run_in_browser); +use chrono::NaiveDate; + mod common; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] @@ -16,7 +20,7 @@ async fn test_registration() { let mut bundle = common::setup().await; let reg = RegisterSchema { username: "Hiiii".into(), - date_of_birth: Some("2000-01-01".to_string()), + date_of_birth: Some(NaiveDate::from_str("2000-01-01").unwrap()), consent: true, ..Default::default() }; @@ -32,7 +36,7 @@ async fn test_login() { username: "Hiiii".into(), email: Some("testuser1@integrationtesting.xyz".into()), password: Some("Correct-Horse-Battery-Staple1".into()), - date_of_birth: Some("2000-01-01".to_string()), + date_of_birth: Some(NaiveDate::from_str("2000-01-01").unwrap()), consent: true, ..Default::default() }; @@ -54,7 +58,7 @@ async fn test_wrong_login() { username: "Hiiii".into(), email: Some("testuser2@integrationtesting.xyz".into()), password: Some("Correct-Horse-Battery-Staple1".into()), - date_of_birth: Some("2000-01-01".to_string()), + date_of_birth: Some(NaiveDate::from_str("2000-01-01").unwrap()), consent: true, ..Default::default() }; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index a98667c8..315db38d 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -2,6 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use std::str::FromStr; + use chorus::gateway::Gateway; use chorus::types::IntoShared; use chorus::{ @@ -13,6 +15,8 @@ use chorus::{ UrlBundle, }; +use chrono::NaiveDate; + #[allow(dead_code)] #[derive(Debug)] pub(crate) struct TestBundle { @@ -30,7 +34,7 @@ impl TestBundle { let register_schema = RegisterSchema { username: username.to_string(), consent: true, - date_of_birth: Some("2000-01-01".to_string()), + date_of_birth: Some(NaiveDate::from_str("2000-01-01").unwrap()), ..Default::default() }; self.instance @@ -60,7 +64,7 @@ pub(crate) async fn setup() -> TestBundle { let reg = RegisterSchema { username: "integrationtestuser".into(), consent: true, - date_of_birth: Some("2000-01-01".to_string()), + date_of_birth: Some(NaiveDate::from_str("2000-01-01").unwrap()), ..Default::default() }; let guild_create_schema = GuildCreateSchema { From 0bc54ce46fa100b5e9655a8e1dd58f9c623f804f Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Mon, 3 Jun 2024 01:41:52 -0400 Subject: [PATCH 018/162] Add sqlx::FromRow derive to GuildMember --- src/types/entities/guild_member.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index 2a3c184d..09e8554c 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -10,6 +10,7 @@ use crate::types::{entities::PublicUser, Snowflake}; use crate::types::utils::serde::*; #[derive(Debug, Deserialize, Default, Serialize, Clone)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] /// Represents a participating user in a guild. /// /// # Reference From d6ad68c0444f722e466eda05a59847b152651577 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Mon, 3 Jun 2024 01:42:31 -0400 Subject: [PATCH 019/162] remove dep: prefix in backend feature list --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 936e1499..6a3b3843 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ rust-version = "1.67.1" [features] default = ["client", "rt-multi-thread"] -backend = ["dep:poem", "dep:sqlx"] +backend = ["poem", "sqlx"] rt-multi-thread = ["tokio/rt-multi-thread"] rt = ["tokio/rt"] client = [] From 85aa85495373c417335c6c447b0ba5b067e9181b Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Mon, 3 Jun 2024 22:58:05 -0400 Subject: [PATCH 020/162] Implement sqlx Encode, Decode, Type for Rights bitflag object. --- src/types/utils/rights.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/types/utils/rights.rs b/src/types/utils/rights.rs index 63bbeb2a..e4fff316 100644 --- a/src/types/utils/rights.rs +++ b/src/types/utils/rights.rs @@ -4,6 +4,10 @@ use bitflags::bitflags; use serde::{Deserialize, Serialize}; +use tokio::io::AsyncWriteExt; + +#[cfg(feature = "sqlx")] +use sqlx::{{Decode, Encode, MySql}, database::{HasArguments, HasValueRef}, encode::IsNull, error::BoxDynError, mysql::MySqlValueRef}; bitflags! { /// Rights are instance-wide, per-user permissions for everything you may perform on the instance, @@ -129,6 +133,33 @@ bitflags! { } } +#[cfg(feature = "sqlx")] +impl sqlx::Type for Rights { + fn type_info() -> ::TypeInfo { + u64::type_info() + } + + fn compatible(ty: &::TypeInfo) -> bool { + u64::compatible(ty) + } +} + +#[cfg(feature = "sqlx")] +impl<'q> Encode<'q, MySql> for Rights { + fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> IsNull { + >::encode_by_ref(&self.0.0, buf) + } +} + +#[cfg(feature = "sqlx")] +impl<'r> Decode<'r, MySql> for Rights { + fn decode(value: >::ValueRef) -> Result { + let raw = >::decode(value)?; + Ok(Rights::from_bits(raw).unwrap()) + } +} + + impl Rights { pub fn any(&self, permission: Rights, check_operator: bool) -> bool { (check_operator && self.contains(Rights::OPERATOR)) || self.contains(permission) From 7d55bbea4b0e2b853d4e508a0354fa65acaf61e0 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Mon, 3 Jun 2024 23:53:15 -0400 Subject: [PATCH 021/162] Use Snowflake in Claims --- src/types/utils/jwt.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/utils/jwt.rs b/src/types/utils/jwt.rs index 6addb4c8..0919a5a9 100644 --- a/src/types/utils/jwt.rs +++ b/src/types/utils/jwt.rs @@ -19,7 +19,7 @@ pub struct Claims { /// When the token was issued pub iat: i64, pub email: String, - pub id: String, + pub id: Snowflake, } impl Claims { @@ -27,7 +27,7 @@ impl Claims { let unix = chrono::Utc::now().timestamp(); Self { exp: unix + (60 * 60 * 24), - id: id.to_string(), + id: *id, iat: unix, email: user.to_string(), } From 179b8d228ae1680bfde3d0d39cf1df8f3189098a Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Mon, 3 Jun 2024 23:54:17 -0400 Subject: [PATCH 022/162] Use ChannelType enum on ChannelModifySchema --- src/types/schema/channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 1502f978..851bfdaa 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -36,7 +36,7 @@ pub struct ChannelCreateSchema { #[serde(rename_all = "snake_case")] pub struct ChannelModifySchema { pub name: Option, - pub channel_type: Option, + pub channel_type: Option, pub topic: Option, pub icon: Option, pub bitrate: Option, From 40bdafd1a3ea1c9ad3e612e2f6437cc68cdbe5eb Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Mon, 3 Jun 2024 23:56:17 -0400 Subject: [PATCH 023/162] Feature lock Shared, so backend feature gets a facade type --- src/types/entities/mod.rs | 1 + src/types/mod.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index d5d70e60..5b498d60 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -134,6 +134,7 @@ pub trait IntoShared { fn into_shared(self) -> Shared; } +#[cfg(feature = "client")] impl IntoShared for T { fn into_shared(self) -> Shared { Arc::new(RwLock::new(self)) diff --git a/src/types/mod.rs b/src/types/mod.rs index c4cc1907..9ff2c09c 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -28,4 +28,7 @@ mod utils; /// /// While `T` does not have to implement `Composite` to be used with `Shared`, /// the primary use of `Shared` is with types that implement `Composite`. +#[cfg(feature = "client")] pub type Shared = Arc>; +#[cfg(not(feature = "client"))] +pub type Shared = T; From 4d75aa89c9ebda2753e787922f6f90eb08282e11 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Mon, 3 Jun 2024 23:59:21 -0400 Subject: [PATCH 024/162] Remove erroneous serde with attributes --- src/types/entities/guild.rs | 3 +-- src/types/entities/guild_member.rs | 3 --- src/types/entities/message.rs | 4 +--- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index af6f1530..8544b0ba 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -14,7 +14,7 @@ use crate::types::types::guild_configuration::GuildFeaturesList; use crate::types::{ entities::{Channel, Emoji, RoleObject, Sticker, User, VoiceState, Webhook}, interfaces::WelcomeScreenObject, - utils::{Snowflake, serde::*}, + utils::Snowflake, }; use super::PublicUser; @@ -67,7 +67,6 @@ pub struct Guild { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub invites: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] - #[serde(with = "ts_seconds_option_str", default)] pub joined_at: Option>, pub large: Option, pub max_members: Option, diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index 09e8554c..83adb0b9 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -7,7 +7,6 @@ use serde::{Deserialize, Serialize}; use crate::types::Shared; use crate::types::{entities::PublicUser, Snowflake}; -use crate::types::utils::serde::*; #[derive(Debug, Deserialize, Default, Serialize, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -20,7 +19,6 @@ pub struct GuildMember { pub nick: Option, pub avatar: Option, pub roles: Vec, - #[serde(with = "ts_seconds_str")] pub joined_at: DateTime, pub premium_since: Option, pub deaf: bool, @@ -28,6 +26,5 @@ pub struct GuildMember { pub flags: Option, pub pending: Option, pub permissions: Option, - #[serde(with = "ts_seconds_option_str")] pub communication_disabled_until: Option>, } diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index c4abb8e1..4b57e062 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -11,7 +11,7 @@ use crate::types::{ Application, Attachment, Channel, Emoji, GuildMember, PublicUser, RoleSubscriptionData, Sticker, StickerItem, User, }, - utils::{Snowflake, serde::*}, + utils::Snowflake, }; #[derive(Debug, Serialize, Deserialize, Default, Clone)] @@ -26,9 +26,7 @@ pub struct Message { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub author: Option, pub content: Option, - // #[serde(with = "ts_seconds_str")] pub timestamp: DateTime, - // #[serde(with = "ts_seconds_option_str")] pub edited_timestamp: Option>, pub tts: Option, pub mention_everyone: bool, From 97f10aaa61d6484a5e36a37b6cccec46f97581ce Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 00:21:38 -0400 Subject: [PATCH 025/162] Add From> impl for GuildFeaturesList --- src/types/config/types/guild_configuration.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/types/config/types/guild_configuration.rs b/src/types/config/types/guild_configuration.rs index af40b30f..d2b3f16c 100644 --- a/src/types/config/types/guild_configuration.rs +++ b/src/types/config/types/guild_configuration.rs @@ -376,6 +376,12 @@ impl FromStr for GuildFeatures { } } +impl From> for GuildFeaturesList { + fn from(features: Vec) -> GuildFeaturesList { + Self(features) + } +} + impl GuildFeatures { pub fn to_str(&self) -> &'static str { match *self { From 2b06742a62c8d0cdf471882608bf19efd1ffcaac Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 00:22:12 -0400 Subject: [PATCH 026/162] Add feature sqlx locks for user, roles on GuildMember --- src/types/entities/guild_member.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index 83adb0b9..bdfd1a9b 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -15,9 +15,11 @@ use crate::types::{entities::PublicUser, Snowflake}; /// # Reference /// See pub struct GuildMember { + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub user: Option>, pub nick: Option, pub avatar: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub roles: Vec, pub joined_at: DateTime, pub premium_since: Option, From f178e517d3f5e69187323e8183161afac063c091 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 00:22:52 -0400 Subject: [PATCH 027/162] Use distinct type for explicit_content_filter --- src/types/entities/guild.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 8544b0ba..66b93357 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -57,7 +57,7 @@ pub struct Guild { #[cfg_attr(feature = "client", observe_vec)] #[serde(default)] pub emojis: Vec>, - pub explicit_content_filter: Option, + pub explicit_content_filter: Option, //#[cfg_attr(feature = "sqlx", sqlx(try_from = "String"))] pub features: Option, pub icon: Option, From 2b4e9fa1491db750153e37b26ed3d450e043dc76 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 00:38:49 -0400 Subject: [PATCH 028/162] Remove unused imports --- src/types/entities/user_settings.rs | 2 -- src/types/utils/rights.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/src/types/entities/user_settings.rs b/src/types/entities/user_settings.rs index 1eef5d2e..2e0d84db 100644 --- a/src/types/entities/user_settings.rs +++ b/src/types/entities/user_settings.rs @@ -2,8 +2,6 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::sync::{Arc, RwLock}; - use chrono::{serde::ts_milliseconds_option, Utc}; use serde::{Deserialize, Serialize}; diff --git a/src/types/utils/rights.rs b/src/types/utils/rights.rs index e4fff316..63978da0 100644 --- a/src/types/utils/rights.rs +++ b/src/types/utils/rights.rs @@ -4,7 +4,6 @@ use bitflags::bitflags; use serde::{Deserialize, Serialize}; -use tokio::io::AsyncWriteExt; #[cfg(feature = "sqlx")] use sqlx::{{Decode, Encode, MySql}, database::{HasArguments, HasValueRef}, encode::IsNull, error::BoxDynError, mysql::MySqlValueRef}; From 119a09ae8880496a8b248c72d258352feaa00d54 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 00:38:59 -0400 Subject: [PATCH 029/162] Revert c4452132 --- src/types/entities/user_settings.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/types/entities/user_settings.rs b/src/types/entities/user_settings.rs index 2e0d84db..0dbce3e5 100644 --- a/src/types/entities/user_settings.rs +++ b/src/types/entities/user_settings.rs @@ -81,9 +81,6 @@ pub struct UserSettings { #[cfg(not(feature = "sqlx"))] pub restricted_guilds: Vec, pub show_current_game: bool, - #[cfg(feature = "sqlx")] - pub status: UserStatus, - #[cfg(not(feature = "sqlx"))] pub status: Shared, pub stream_notifications_enabled: bool, pub theme: UserTheme, From fcda4cc2cab80eda306fe7583ea91bdf88c66741 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 00:41:03 -0400 Subject: [PATCH 030/162] Remove final usages of erroneous serde impl --- src/types/entities/channel.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index b5e604de..262897c2 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -11,7 +11,7 @@ use std::fmt::Debug; use crate::types::Shared; use crate::types::{ entities::{GuildMember, User}, - utils::{Snowflake, serde::*}, + utils::Snowflake, }; #[cfg(feature = "client")] @@ -60,7 +60,6 @@ pub struct Channel { pub icon: Option, pub id: Snowflake, pub last_message_id: Option, - #[serde(with = "ts_seconds_option_str", default)] pub last_pin_timestamp: Option>, pub managed: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] @@ -161,11 +160,9 @@ pub struct PermissionOverwrite { pub struct ThreadMetadata { pub archived: bool, pub auto_archive_duration: i32, - #[serde(with = "ts_seconds_str")] pub archive_timestamp: DateTime, pub locked: bool, pub invitable: Option, - #[serde(with = "ts_seconds_option_str")] pub create_timestamp: Option>, } @@ -175,7 +172,6 @@ pub struct ThreadMetadata { pub struct ThreadMember { pub id: Option, pub user_id: Option, - #[serde(with = "ts_seconds_option_str")] pub join_timestamp: Option>, pub flags: Option, pub member: Option>, From 2db91e8538ee9e059896a3dd6b6fc9b36e70ac37 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 00:51:22 -0400 Subject: [PATCH 031/162] Fix errors in documentation tests --- src/types/utils/serde.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/types/utils/serde.rs b/src/types/utils/serde.rs index 28d6e606..2f273c26 100644 --- a/src/types/utils/serde.rs +++ b/src/types/utils/serde.rs @@ -33,7 +33,7 @@ pub struct SecondsStringTimestampVisitor; /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// // Ok::<(), serde_json::Error>(()) /// ``` pub mod ts_seconds_str { @@ -65,7 +65,7 @@ pub mod ts_seconds_str { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); - /// # Ok::<(), serde_json::Error>(()) + /// // Ok::<(), serde_json::Error>(()) /// ``` pub fn serialize(dt: &DateTime, serializer: S) -> Result where @@ -92,7 +92,7 @@ pub mod ts_seconds_str { /// /// let my_s: S = serde_json::from_str(r#"{ "time": "1431684000" }"#)?; /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).unwrap() }); - /// # Ok::<(), serde_json::Error>(()) + /// // Ok::<(), serde_json::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -143,7 +143,7 @@ pub mod ts_seconds_str { /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// // Ok::<(), serde_json::Error>(()) /// ``` pub mod ts_seconds_option_str { use core::fmt; @@ -172,7 +172,7 @@ pub mod ts_seconds_option_str { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); - /// # Ok::<(), serde_json::Error>(()) + /// // Ok::<(), serde_json::Error>(()) /// ``` pub fn serialize(opt: &Option>, serializer: S) -> Result where @@ -202,7 +202,7 @@ pub mod ts_seconds_option_str { /// /// let my_s: S = serde_json::from_str(r#"{ "time": "1431684000" }"#)?; /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).single() }); - /// # Ok::<(), serde_json::Error>(()) + /// // Ok::<(), serde_json::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where From 50c5c29caee4772b4e61328ac8fd62ba1d69552d Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 00:53:08 -0400 Subject: [PATCH 032/162] update dev-dependencies --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6a3b3843..a3b0b369 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,5 +76,5 @@ wasmtimer = "0.2.0" [dev-dependencies] lazy_static = "1.4.0" -wasm-bindgen-test = "0.3.39" -wasm-bindgen = "0.2.89" +wasm-bindgen-test = "0.3.42" +wasm-bindgen = "0.2.92" From 32677b8cd938abba621f4bef5c03d51cad5a82c9 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 01:02:06 -0400 Subject: [PATCH 033/162] actually fix linux tests --- src/types/utils/serde.rs | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/types/utils/serde.rs b/src/types/utils/serde.rs index 2f273c26..8a1555f2 100644 --- a/src/types/utils/serde.rs +++ b/src/types/utils/serde.rs @@ -1,7 +1,6 @@ use core::fmt; use chrono::{LocalResult, NaiveDateTime}; use serde::de; -use chrono::serde::ts_seconds; #[doc(hidden)] #[derive(Debug)] @@ -17,7 +16,7 @@ pub struct SecondsStringTimestampVisitor; /// ```rust /// # use chrono::{TimeZone, DateTime, Utc}; /// # use serde::{Deserialize, Serialize}; -/// use chrono::serde::ts_seconds; +/// use chorus::types::serde::ts_seconds_str; /// #[derive(Deserialize, Serialize)] /// struct S { /// #[serde(with = "ts_seconds_str")] @@ -33,7 +32,7 @@ pub struct SecondsStringTimestampVisitor; /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// // Ok::<(), serde_json::Error>(()) +/// # Ok::<(), serde_json::Error>(()) /// ``` pub mod ts_seconds_str { @@ -53,10 +52,10 @@ pub mod ts_seconds_str { /// ```rust /// # use chrono::{TimeZone, DateTime, Utc}; /// # use serde::Serialize; - /// use chrono::serde::ts_seconds::serialize as to_ts; + /// use chorus::types::serde::ts_seconds_str::serialize as to_ts; /// #[derive(Serialize)] /// struct S { - /// #[serde(serialize_with = "ts_seconds_str")] + /// #[serde(serialize_with = "to_ts")] /// time: DateTime /// } /// @@ -65,7 +64,7 @@ pub mod ts_seconds_str { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); - /// // Ok::<(), serde_json::Error>(()) + /// # Ok::<(), serde_json::Error>(()) /// ``` pub fn serialize(dt: &DateTime, serializer: S) -> Result where @@ -83,16 +82,16 @@ pub mod ts_seconds_str { /// ```rust /// # use chrono::{DateTime, TimeZone, Utc}; /// # use serde::Deserialize; - /// use chrono::serde::ts_seconds::deserialize as from_ts; + /// use chorus::types::serde::ts_seconds_str::deserialize as from_ts; /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { - /// #[serde(deserialize_with = "ts_seconds_str")] + /// #[serde(deserialize_with = "from_ts")] /// time: DateTime /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": "1431684000" }"#)?; /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).unwrap() }); - /// // Ok::<(), serde_json::Error>(()) + /// # Ok::<(), serde_json::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -127,7 +126,7 @@ pub mod ts_seconds_str { /// ```rust /// # use chrono::{TimeZone, DateTime, Utc}; /// # use serde::{Deserialize, Serialize}; -/// use chrono::serde::ts_seconds_option; +/// use chorus::types::serde::ts_seconds_option_str; /// #[derive(Deserialize, Serialize)] /// struct S { /// #[serde(with = "ts_seconds_option_str")] @@ -143,7 +142,7 @@ pub mod ts_seconds_str { /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// // Ok::<(), serde_json::Error>(()) +/// # Ok::<(), serde_json::Error>(()) /// ``` pub mod ts_seconds_option_str { use core::fmt; @@ -160,10 +159,10 @@ pub mod ts_seconds_option_str { /// ```rust /// # use chrono::{TimeZone, DateTime, Utc}; /// # use serde::Serialize; - /// use chrono::serde::ts_seconds_option::serialize as to_tsopt; + /// use chorus::types::serde::ts_seconds_option_str::serialize as from_tsopt; /// #[derive(Serialize)] /// struct S { - /// #[serde(serialize_with = "ts_seconds_option_str")] + /// #[serde(serialize_with = "from_tsopt")] /// time: Option> /// } /// @@ -172,7 +171,7 @@ pub mod ts_seconds_option_str { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); - /// // Ok::<(), serde_json::Error>(()) + /// # Ok::<(), serde_json::Error>(()) /// ``` pub fn serialize(opt: &Option>, serializer: S) -> Result where @@ -193,16 +192,16 @@ pub mod ts_seconds_option_str { /// ```rust /// # use chrono::{DateTime, TimeZone, Utc}; /// # use serde::Deserialize; - /// use chrono::serde::ts_seconds_option::deserialize as from_tsopt; + /// use chorus::types::serde::ts_seconds_option_str::deserialize as from_tsopt; /// #[derive(Debug, PartialEq, Deserialize)] /// struct S { - /// #[serde(deserialize_with = "ts_seconds_option_str")] + /// #[serde(deserialize_with = "from_tsopt")] /// time: Option> /// } /// /// let my_s: S = serde_json::from_str(r#"{ "time": "1431684000" }"#)?; /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).single() }); - /// // Ok::<(), serde_json::Error>(()) + /// # Ok::<(), serde_json::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where From 0c9e9cf3673c48a02b4074561ce9a3e32238fdce Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 12:57:48 -0400 Subject: [PATCH 034/162] clear warnings --- src/types/entities/mod.rs | 1 + src/types/mod.rs | 1 + src/types/utils/serde.rs | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index 5b498d60..4227e242 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -28,6 +28,7 @@ pub use voice_state::*; pub use webhook::*; use crate::types::Shared; +#[cfg(feature = "client")] use std::sync::{Arc, RwLock}; #[cfg(feature = "client")] diff --git a/src/types/mod.rs b/src/types/mod.rs index 9ff2c09c..e67c203c 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -4,6 +4,7 @@ //! All the types, entities, events and interfaces of the Spacebar API. +#[cfg(feature = "client")] use std::sync::{Arc, RwLock}; pub use config::*; diff --git a/src/types/utils/serde.rs b/src/types/utils/serde.rs index 8a1555f2..85840045 100644 --- a/src/types/utils/serde.rs +++ b/src/types/utils/serde.rs @@ -245,7 +245,7 @@ pub mod ts_seconds_option_str { } } -pub(crate) fn serde_from(me: LocalResult, ts: &V) -> Result +pub(crate) fn serde_from(me: LocalResult, _ts: &V) -> Result where E: de::Error, V: fmt::Display, @@ -254,7 +254,7 @@ pub(crate) fn serde_from(me: LocalResult, ts: &V) -> Result // TODO: Make actual error type match me { LocalResult::None => Err(E::custom("value is not a legal timestamp")), - LocalResult::Ambiguous(min, max) => { + LocalResult::Ambiguous(_min, _max) => { Err(E::custom("value is an ambiguous timestamp")) } LocalResult::Single(val) => Ok(val), From 82c8f570f23582319eec48485ab5a558741853bf Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 13:33:40 -0400 Subject: [PATCH 035/162] Update Cargo.lock --- Cargo.lock | 234 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 178 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53283ccf..61d67fb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,13 +101,19 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "atomic-write-file" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" dependencies = [ - "nix", + "nix 0.27.1", "rand", ] @@ -207,6 +213,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chorus" version = "0.15.0" @@ -222,7 +234,7 @@ dependencies = [ "futures-util", "getrandom", "hostname", - "http", + "http 0.2.11", "jsonwebtoken", "lazy_static", "log", @@ -725,7 +737,26 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.11", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", "indexmap 2.1.0", "slab", "tokio", @@ -760,14 +791,14 @@ dependencies = [ [[package]] name = "headers" -version = "0.3.9" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" dependencies = [ "base64 0.21.7", "bytes", "headers-core", - "http", + "http 1.1.0", "httpdate", "mime", "sha1", @@ -775,11 +806,11 @@ dependencies = [ [[package]] name = "headers-core" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http", + "http 1.1.0", ] [[package]] @@ -852,6 +883,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -859,7 +901,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.11", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http 1.1.0", + "http-body 1.0.0", "pin-project-lite", ] @@ -885,9 +950,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.3.26", + "http 0.2.11", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -899,6 +964,26 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.5", + "http 1.1.0", + "http-body 1.0.0", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -906,12 +991,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper", + "hyper 0.14.28", "native-tls", "tokio", "tokio-native-tls", ] +[[package]] +name = "hyper-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "hyper 1.3.1", + "pin-project-lite", + "tokio", +] + [[package]] name = "iana-time-zone" version = "0.1.59" @@ -1014,9 +1114,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.66" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -1046,9 +1146,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.152" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libm" @@ -1182,6 +1282,18 @@ dependencies = [ "libc", ] +[[package]] +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "no-std-net" version = "0.6.0" @@ -1466,18 +1578,19 @@ dependencies = [ [[package]] name = "poem" -version = "1.3.59" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504774c97b0744c1ee108a37e5a65a9745a4725c4c06277521dabc28eb53a904" +checksum = "e88b6912ed1e8833d7c22c9c986c517f4518d7d37e3c04566d917c789aaea591" dependencies = [ - "async-trait", "bytes", "futures-util", "headers", - "http", - "hyper", + "http 1.1.0", + "http-body-util", + "hyper 1.3.1", + "hyper-util", "mime", - "nix", + "nix 0.28.0", "parking_lot", "percent-encoding", "pin-project-lite", @@ -1488,6 +1601,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", + "sync_wrapper", "thiserror", "tokio", "tokio-util", @@ -1497,9 +1611,9 @@ dependencies = [ [[package]] name = "poem-derive" -version = "1.3.59" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ddcf4680d8d867e1e375116203846acb088483fa2070244f90589f458bbb31" +checksum = "c2b961d58a6c53380c20236394381d9292fda03577f902b158f1638932964dcf" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1532,11 +1646,10 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro-crate" -version = "2.0.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ - "toml_datetime", "toml_edit", ] @@ -1637,10 +1750,10 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", + "h2 0.3.26", + "http 0.2.11", + "http-body 0.4.6", + "hyper 0.14.28", "hyper-tls", "ipnet", "js-sys", @@ -2024,9 +2137,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -2323,6 +2436,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -2511,15 +2633,15 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" [[package]] name = "toml_edit" -version = "0.20.2" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ "indexmap 2.1.0", "toml_datetime", @@ -2579,7 +2701,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.11", "httparse", "log", "rand", @@ -2727,9 +2849,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2737,9 +2859,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", @@ -2752,9 +2874,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.39" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -2764,9 +2886,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2774,9 +2896,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", @@ -2787,15 +2909,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-bindgen-test" -version = "0.3.39" +version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cf9242c0d27999b831eae4767b2a146feb0b27d332d553e605864acd2afd403" +checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" dependencies = [ "console_error_panic_hook", "js-sys", @@ -2807,9 +2929,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.39" +version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794645f5408c9a039fd09f4d113cdfb2e7eba5ff1956b07bcf701cf4b394fe89" +checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" dependencies = [ "proc-macro2", "quote", From cb905d0a834deea6677d6933ef185e67e698e7c5 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 13:34:58 -0400 Subject: [PATCH 036/162] Expand documentation to explain facade type --- src/types/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/types/mod.rs b/src/types/mod.rs index e67c203c..f41a0830 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -29,6 +29,9 @@ mod utils; /// /// While `T` does not have to implement `Composite` to be used with `Shared`, /// the primary use of `Shared` is with types that implement `Composite`. +/// +/// When the `client` feature is disabled, this does nothing (same as just `T`), +/// since `Composite` structures are disabled. #[cfg(feature = "client")] pub type Shared = Arc>; #[cfg(not(feature = "client"))] From 0bf5091f3c95dd0d8d63f964b30aa9f818c946cc Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 13:35:28 -0400 Subject: [PATCH 037/162] Fix oversight for premium_since --- src/types/entities/guild_member.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index bdfd1a9b..df075833 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -22,7 +22,7 @@ pub struct GuildMember { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub roles: Vec, pub joined_at: DateTime, - pub premium_since: Option, + pub premium_since: Option>, pub deaf: bool, pub mute: bool, pub flags: Option, From a5a0459d7061ce2250e43d2718a2417aae9c1f86 Mon Sep 17 00:00:00 2001 From: Quat3rnion <81202811+Quat3rnion@users.noreply.github.com> Date: Tue, 4 Jun 2024 13:41:50 -0400 Subject: [PATCH 038/162] Backend related updates (#501) (by Quat3rnion) Some updates relating to usage with Symfonia: * Using distinct types instead of primitives on some objects * Add sqlx derives and implementations * Make a facade type for Shared to be used in non-client contexts --- Cargo.lock | 214 +++++++++++--- Cargo.toml | 8 +- src/types/config/types/guild_configuration.rs | 6 + .../config/types/register_configuration.rs | 8 +- src/types/entities/guild.rs | 2 +- src/types/entities/guild_member.rs | 3 + src/types/entities/mod.rs | 2 + src/types/entities/user_settings.rs | 4 +- src/types/mod.rs | 7 + src/types/schema/channel.rs | 2 +- src/types/utils/jwt.rs | 4 +- src/types/utils/mod.rs | 2 + src/types/utils/rights.rs | 38 +++ src/types/utils/serde.rs | 262 ++++++++++++++++++ 14 files changed, 501 insertions(+), 61 deletions(-) create mode 100644 src/types/utils/serde.rs diff --git a/Cargo.lock b/Cargo.lock index 0d0cb0cc..61d67fb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,13 +101,19 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "atomic-write-file" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" dependencies = [ - "nix", + "nix 0.27.1", "rand", ] @@ -207,6 +213,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chorus" version = "0.15.0" @@ -222,7 +234,7 @@ dependencies = [ "futures-util", "getrandom", "hostname", - "http", + "http 0.2.11", "jsonwebtoken", "lazy_static", "log", @@ -725,7 +737,26 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.11", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", "indexmap 2.1.0", "slab", "tokio", @@ -760,14 +791,14 @@ dependencies = [ [[package]] name = "headers" -version = "0.3.9" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" dependencies = [ "base64 0.21.7", "bytes", "headers-core", - "http", + "http 1.1.0", "httpdate", "mime", "sha1", @@ -775,11 +806,11 @@ dependencies = [ [[package]] name = "headers-core" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http", + "http 1.1.0", ] [[package]] @@ -852,6 +883,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -859,7 +901,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.11", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http 1.1.0", + "http-body 1.0.0", "pin-project-lite", ] @@ -885,9 +950,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.3.26", + "http 0.2.11", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -899,6 +964,26 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.5", + "http 1.1.0", + "http-body 1.0.0", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -906,12 +991,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper", + "hyper 0.14.28", "native-tls", "tokio", "tokio-native-tls", ] +[[package]] +name = "hyper-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "hyper 1.3.1", + "pin-project-lite", + "tokio", +] + [[package]] name = "iana-time-zone" version = "0.1.59" @@ -1014,9 +1114,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.66" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -1046,9 +1146,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.152" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libm" @@ -1182,6 +1282,18 @@ dependencies = [ "libc", ] +[[package]] +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "no-std-net" version = "0.6.0" @@ -1466,18 +1578,19 @@ dependencies = [ [[package]] name = "poem" -version = "1.3.59" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504774c97b0744c1ee108a37e5a65a9745a4725c4c06277521dabc28eb53a904" +checksum = "e88b6912ed1e8833d7c22c9c986c517f4518d7d37e3c04566d917c789aaea591" dependencies = [ - "async-trait", "bytes", "futures-util", "headers", - "http", - "hyper", + "http 1.1.0", + "http-body-util", + "hyper 1.3.1", + "hyper-util", "mime", - "nix", + "nix 0.28.0", "parking_lot", "percent-encoding", "pin-project-lite", @@ -1488,6 +1601,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", + "sync_wrapper", "thiserror", "tokio", "tokio-util", @@ -1497,9 +1611,9 @@ dependencies = [ [[package]] name = "poem-derive" -version = "1.3.59" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ddcf4680d8d867e1e375116203846acb088483fa2070244f90589f458bbb31" +checksum = "c2b961d58a6c53380c20236394381d9292fda03577f902b158f1638932964dcf" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1532,11 +1646,10 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro-crate" -version = "2.0.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ - "toml_datetime", "toml_edit", ] @@ -1637,10 +1750,10 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", + "h2 0.3.26", + "http 0.2.11", + "http-body 0.4.6", + "hyper 0.14.28", "hyper-tls", "ipnet", "js-sys", @@ -2024,9 +2137,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -2323,6 +2436,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -2511,15 +2633,15 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" [[package]] name = "toml_edit" -version = "0.20.2" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ "indexmap 2.1.0", "toml_datetime", @@ -2579,7 +2701,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.11", "httparse", "log", "rand", @@ -2752,9 +2874,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.39" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -2793,9 +2915,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-bindgen-test" -version = "0.3.39" +version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cf9242c0d27999b831eae4767b2a146feb0b27d332d553e605864acd2afd403" +checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" dependencies = [ "console_error_panic_hook", "js-sys", @@ -2807,9 +2929,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.39" +version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794645f5408c9a039fd09f4d113cdfb2e7eba5ff1956b07bcf701cf4b394fe89" +checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index a31a9da8..a3b0b369 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ rust-version = "1.67.1" [features] default = ["client", "rt-multi-thread"] -backend = ["dep:poem", "dep:sqlx"] +backend = ["poem", "sqlx"] rt-multi-thread = ["tokio/rt-multi-thread"] rt = ["tokio/rt"] client = [] @@ -38,7 +38,7 @@ http = "0.2.11" base64 = "0.21.7" bitflags = { version = "2.4.1", features = ["serde"] } lazy_static = "1.4.0" -poem = { version = "1.3.59", optional = true } +poem = { version = "3.0.1", optional = true } thiserror = "1.0.56" jsonwebtoken = "8.3.0" log = "0.4.20" @@ -76,5 +76,5 @@ wasmtimer = "0.2.0" [dev-dependencies] lazy_static = "1.4.0" -wasm-bindgen-test = "0.3.39" -wasm-bindgen = "0.2.89" +wasm-bindgen-test = "0.3.42" +wasm-bindgen = "0.2.92" diff --git a/src/types/config/types/guild_configuration.rs b/src/types/config/types/guild_configuration.rs index af40b30f..d2b3f16c 100644 --- a/src/types/config/types/guild_configuration.rs +++ b/src/types/config/types/guild_configuration.rs @@ -376,6 +376,12 @@ impl FromStr for GuildFeatures { } } +impl From> for GuildFeaturesList { + fn from(features: Vec) -> GuildFeaturesList { + Self(features) + } +} + impl GuildFeatures { pub fn to_str(&self) -> &'static str { match *self { diff --git a/src/types/config/types/register_configuration.rs b/src/types/config/types/register_configuration.rs index a4573bfd..19cedfb6 100644 --- a/src/types/config/types/register_configuration.rs +++ b/src/types/config/types/register_configuration.rs @@ -4,9 +4,9 @@ use serde::{Deserialize, Serialize}; -use crate::types::config::types::subconfigs::register::{ +use crate::types::{config::types::subconfigs::register::{ DateOfBirthConfiguration, PasswordConfiguration, RegistrationEmailConfiguration, -}; +}, Rights}; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -22,7 +22,7 @@ pub struct RegisterConfiguration { pub allow_multiple_accounts: bool, pub block_proxies: bool, pub incrementing_discriminators: bool, - pub default_rights: String, + pub default_rights: Rights, } impl Default for RegisterConfiguration { @@ -39,7 +39,7 @@ impl Default for RegisterConfiguration { allow_multiple_accounts: true, block_proxies: true, incrementing_discriminators: false, - default_rights: String::from("875069521787904"), + default_rights: Rights::from_bits(648540060672).expect("failed to parse default_rights"), } } } diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 8544b0ba..66b93357 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -57,7 +57,7 @@ pub struct Guild { #[cfg_attr(feature = "client", observe_vec)] #[serde(default)] pub emojis: Vec>, - pub explicit_content_filter: Option, + pub explicit_content_filter: Option, //#[cfg_attr(feature = "sqlx", sqlx(try_from = "String"))] pub features: Option, pub icon: Option, diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index 66fad99d..df075833 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -9,14 +9,17 @@ use crate::types::Shared; use crate::types::{entities::PublicUser, Snowflake}; #[derive(Debug, Deserialize, Default, Serialize, Clone)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] /// Represents a participating user in a guild. /// /// # Reference /// See pub struct GuildMember { + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub user: Option>, pub nick: Option, pub avatar: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub roles: Vec, pub joined_at: DateTime, pub premium_since: Option>, diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index d5d70e60..4227e242 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -28,6 +28,7 @@ pub use voice_state::*; pub use webhook::*; use crate::types::Shared; +#[cfg(feature = "client")] use std::sync::{Arc, RwLock}; #[cfg(feature = "client")] @@ -134,6 +135,7 @@ pub trait IntoShared { fn into_shared(self) -> Shared; } +#[cfg(feature = "client")] impl IntoShared for T { fn into_shared(self) -> Shared { Arc::new(RwLock::new(self)) diff --git a/src/types/entities/user_settings.rs b/src/types/entities/user_settings.rs index db13efc9..0dbce3e5 100644 --- a/src/types/entities/user_settings.rs +++ b/src/types/entities/user_settings.rs @@ -2,8 +2,6 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::sync::{Arc, RwLock}; - use chrono::{serde::ts_milliseconds_option, Utc}; use serde::{Deserialize, Serialize}; @@ -119,7 +117,7 @@ impl Default for UserSettings { render_reactions: true, restricted_guilds: Default::default(), show_current_game: true, - status: Arc::new(RwLock::new(UserStatus::Online)), + status: Default::default(), stream_notifications_enabled: false, theme: UserTheme::Dark, timezone_offset: 0, diff --git a/src/types/mod.rs b/src/types/mod.rs index c4cc1907..f41a0830 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -4,6 +4,7 @@ //! All the types, entities, events and interfaces of the Spacebar API. +#[cfg(feature = "client")] use std::sync::{Arc, RwLock}; pub use config::*; @@ -28,4 +29,10 @@ mod utils; /// /// While `T` does not have to implement `Composite` to be used with `Shared`, /// the primary use of `Shared` is with types that implement `Composite`. +/// +/// When the `client` feature is disabled, this does nothing (same as just `T`), +/// since `Composite` structures are disabled. +#[cfg(feature = "client")] pub type Shared = Arc>; +#[cfg(not(feature = "client"))] +pub type Shared = T; diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 1502f978..851bfdaa 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -36,7 +36,7 @@ pub struct ChannelCreateSchema { #[serde(rename_all = "snake_case")] pub struct ChannelModifySchema { pub name: Option, - pub channel_type: Option, + pub channel_type: Option, pub topic: Option, pub icon: Option, pub bitrate: Option, diff --git a/src/types/utils/jwt.rs b/src/types/utils/jwt.rs index 6addb4c8..0919a5a9 100644 --- a/src/types/utils/jwt.rs +++ b/src/types/utils/jwt.rs @@ -19,7 +19,7 @@ pub struct Claims { /// When the token was issued pub iat: i64, pub email: String, - pub id: String, + pub id: Snowflake, } impl Claims { @@ -27,7 +27,7 @@ impl Claims { let unix = chrono::Utc::now().timestamp(); Self { exp: unix + (60 * 60 * 24), - id: id.to_string(), + id: *id, iat: unix, email: user.to_string(), } diff --git a/src/types/utils/mod.rs b/src/types/utils/mod.rs index 88796887..5608fe74 100644 --- a/src/types/utils/mod.rs +++ b/src/types/utils/mod.rs @@ -11,3 +11,5 @@ pub mod jwt; mod regexes; mod rights; mod snowflake; +pub mod serde; + diff --git a/src/types/utils/rights.rs b/src/types/utils/rights.rs index 4b1aa138..63978da0 100644 --- a/src/types/utils/rights.rs +++ b/src/types/utils/rights.rs @@ -3,6 +3,10 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use bitflags::bitflags; +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "sqlx")] +use sqlx::{{Decode, Encode, MySql}, database::{HasArguments, HasValueRef}, encode::IsNull, error::BoxDynError, mysql::MySqlValueRef}; bitflags! { /// Rights are instance-wide, per-user permissions for everything you may perform on the instance, @@ -14,6 +18,7 @@ bitflags! { /// /// # Reference /// See + #[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)] pub struct Rights: u64 { /// All rights const OPERATOR = 1 << 0; @@ -127,6 +132,33 @@ bitflags! { } } +#[cfg(feature = "sqlx")] +impl sqlx::Type for Rights { + fn type_info() -> ::TypeInfo { + u64::type_info() + } + + fn compatible(ty: &::TypeInfo) -> bool { + u64::compatible(ty) + } +} + +#[cfg(feature = "sqlx")] +impl<'q> Encode<'q, MySql> for Rights { + fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> IsNull { + >::encode_by_ref(&self.0.0, buf) + } +} + +#[cfg(feature = "sqlx")] +impl<'r> Decode<'r, MySql> for Rights { + fn decode(value: >::ValueRef) -> Result { + let raw = >::decode(value)?; + Ok(Rights::from_bits(raw).unwrap()) + } +} + + impl Rights { pub fn any(&self, permission: Rights, check_operator: bool) -> bool { (check_operator && self.contains(Rights::OPERATOR)) || self.contains(permission) @@ -151,6 +183,12 @@ impl Rights { } } +impl Default for Rights { + fn default() -> Self { + Self::empty() + } +} + #[allow(dead_code)] // FIXME: Remove this when we use this fn all_rights() -> Rights { Rights::OPERATOR diff --git a/src/types/utils/serde.rs b/src/types/utils/serde.rs new file mode 100644 index 00000000..85840045 --- /dev/null +++ b/src/types/utils/serde.rs @@ -0,0 +1,262 @@ +use core::fmt; +use chrono::{LocalResult, NaiveDateTime}; +use serde::de; + +#[doc(hidden)] +#[derive(Debug)] +pub struct SecondsStringTimestampVisitor; + + +/// Ser/de to/from timestamps in seconds +/// +/// Intended for use with `serde`'s `with` attribute. +/// +/// # Example: +/// +/// ```rust +/// # use chrono::{TimeZone, DateTime, Utc}; +/// # use serde::{Deserialize, Serialize}; +/// use chorus::types::serde::ts_seconds_str; +/// #[derive(Deserialize, Serialize)] +/// struct S { +/// #[serde(with = "ts_seconds_str")] +/// time: DateTime +/// } +/// +/// let time = Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap(); +/// let my_s = S { +/// time: time.clone(), +/// }; +/// +/// let as_string = serde_json::to_string(&my_s)?; +/// assert_eq!(as_string, r#"{"time":"1431684000"}"#); +/// let my_s: S = serde_json::from_str(&as_string)?; +/// assert_eq!(my_s.time, time); +/// # Ok::<(), serde_json::Error>(()) +/// ``` + +pub mod ts_seconds_str { + use core::fmt; + use chrono::{DateTime, LocalResult, Utc}; + use super::SecondsStringTimestampVisitor; + use serde::{de, ser}; + use chrono::TimeZone; + use super::serde_from; + + /// Serialize a UTC datetime into an integer number of seconds since the epoch + /// + /// Intended for use with `serde`s `serialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # use chrono::{TimeZone, DateTime, Utc}; + /// # use serde::Serialize; + /// use chorus::types::serde::ts_seconds_str::serialize as to_ts; + /// #[derive(Serialize)] + /// struct S { + /// #[serde(serialize_with = "to_ts")] + /// time: DateTime + /// } + /// + /// let my_s = S { + /// time: Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap(), + /// }; + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); + /// # Ok::<(), serde_json::Error>(()) + /// ``` + pub fn serialize(dt: &DateTime, serializer: S) -> Result + where + S: ser::Serializer, + { + serializer.serialize_str(&format!("{}", dt.timestamp())) + } + + /// Deserialize a `DateTime` from a seconds timestamp + /// + /// Intended for use with `serde`s `deserialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # use chrono::{DateTime, TimeZone, Utc}; + /// # use serde::Deserialize; + /// use chorus::types::serde::ts_seconds_str::deserialize as from_ts; + /// #[derive(Debug, PartialEq, Deserialize)] + /// struct S { + /// #[serde(deserialize_with = "from_ts")] + /// time: DateTime + /// } + /// + /// let my_s: S = serde_json::from_str(r#"{ "time": "1431684000" }"#)?; + /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).unwrap() }); + /// # Ok::<(), serde_json::Error>(()) + /// ``` + pub fn deserialize<'de, D>(d: D) -> Result, D::Error> + where + D: de::Deserializer<'de>, + { + d.deserialize_str(SecondsStringTimestampVisitor) + } + + impl<'de> de::Visitor<'de> for SecondsStringTimestampVisitor { + type Value = DateTime; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a unix timestamp in seconds") + } + + /// Deserialize a timestamp in seconds since the epoch + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + serde_from(Utc.timestamp_opt(value.parse::().map_err(|e| E::custom(e))?, 0), &value) + } + } +} + +/// Ser/de to/from optional timestamps in seconds +/// +/// Intended for use with `serde`'s `with` attribute. +/// +/// # Example: +/// +/// ```rust +/// # use chrono::{TimeZone, DateTime, Utc}; +/// # use serde::{Deserialize, Serialize}; +/// use chorus::types::serde::ts_seconds_option_str; +/// #[derive(Deserialize, Serialize)] +/// struct S { +/// #[serde(with = "ts_seconds_option_str")] +/// time: Option> +/// } +/// +/// let time = Some(Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap()); +/// let my_s = S { +/// time: time.clone(), +/// }; +/// +/// let as_string = serde_json::to_string(&my_s)?; +/// assert_eq!(as_string, r#"{"time":"1431684000"}"#); +/// let my_s: S = serde_json::from_str(&as_string)?; +/// assert_eq!(my_s.time, time); +/// # Ok::<(), serde_json::Error>(()) +/// ``` +pub mod ts_seconds_option_str { + use core::fmt; + use chrono::{DateTime, Utc}; + use serde::{de, ser}; + use super::SecondsStringTimestampVisitor; + + /// Serialize a UTC datetime into an integer number of seconds since the epoch or none + /// + /// Intended for use with `serde`s `serialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # use chrono::{TimeZone, DateTime, Utc}; + /// # use serde::Serialize; + /// use chorus::types::serde::ts_seconds_option_str::serialize as from_tsopt; + /// #[derive(Serialize)] + /// struct S { + /// #[serde(serialize_with = "from_tsopt")] + /// time: Option> + /// } + /// + /// let my_s = S { + /// time: Some(Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap()), + /// }; + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); + /// # Ok::<(), serde_json::Error>(()) + /// ``` + pub fn serialize(opt: &Option>, serializer: S) -> Result + where + S: ser::Serializer, + { + match *opt { + Some(ref dt) => serializer.serialize_some(&dt.timestamp().to_string()), + None => serializer.serialize_none(), + } + } + + /// Deserialize a `DateTime` from a seconds timestamp or none + /// + /// Intended for use with `serde`s `deserialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # use chrono::{DateTime, TimeZone, Utc}; + /// # use serde::Deserialize; + /// use chorus::types::serde::ts_seconds_option_str::deserialize as from_tsopt; + /// #[derive(Debug, PartialEq, Deserialize)] + /// struct S { + /// #[serde(deserialize_with = "from_tsopt")] + /// time: Option> + /// } + /// + /// let my_s: S = serde_json::from_str(r#"{ "time": "1431684000" }"#)?; + /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).single() }); + /// # Ok::<(), serde_json::Error>(()) + /// ``` + pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> + where + D: de::Deserializer<'de>, + { + d.deserialize_option(OptionSecondsTimestampVisitor) + } + + struct OptionSecondsTimestampVisitor; + + impl<'de> de::Visitor<'de> for OptionSecondsTimestampVisitor { + type Value = Option>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a unix timestamp in seconds or none") + } + + /// Deserialize a timestamp in seconds since the epoch + fn visit_some(self, d: D) -> Result + where + D: de::Deserializer<'de>, + { + d.deserialize_str(SecondsStringTimestampVisitor).map(Some) + } + + /// Deserialize a timestamp in seconds since the epoch + fn visit_none(self) -> Result + where + E: de::Error, + { + Ok(None) + } + + /// Deserialize a timestamp in seconds since the epoch + fn visit_unit(self) -> Result + where + E: de::Error, + { + Ok(None) + } + } +} + +pub(crate) fn serde_from(me: LocalResult, _ts: &V) -> Result + where + E: de::Error, + V: fmt::Display, + T: fmt::Display, +{ + // TODO: Make actual error type + match me { + LocalResult::None => Err(E::custom("value is not a legal timestamp")), + LocalResult::Ambiguous(_min, _max) => { + Err(E::custom("value is an ambiguous timestamp")) + } + LocalResult::Single(val) => Ok(val), + } +} \ No newline at end of file From c96dcd5c33f7e93b70ba2cca1cf06854073d682e Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 22:19:48 -0400 Subject: [PATCH 039/162] Distinguish InviteType and InviteTargetType --- src/types/schema/channel.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 851bfdaa..91e7d30b 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -109,7 +109,7 @@ pub struct CreateChannelInviteSchema { pub temporary: Option, pub unique: Option, pub validate: Option, - pub target_type: Option, + pub target_type: Option, pub target_user_id: Option, pub target_application_id: Option, } @@ -138,8 +138,21 @@ bitflags! { } #[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] +#[repr(u8)] pub enum InviteType { + #[default] + Guild = 0, + GroupDm = 1, + Friend = 2, +} + +#[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +#[repr(u8)] +pub enum InviteTargetType { #[default] Stream = 1, EmbeddedApplication = 2, From 6c1493f362fc0533b86417b93e5210a2208323a3 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 22:21:48 -0400 Subject: [PATCH 040/162] Add sqlx Type, Encode, Decode impl for InviteFlags bitflag object. --- src/types/schema/channel.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 91e7d30b..d7163991 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -137,6 +137,29 @@ bitflags! { } } +#[cfg(feature = "sqlx")] +impl sqlx::Type for InviteFlags { + fn type_info() -> sqlx::mysql::MySqlTypeInfo { + u64::type_info() + } +} + +#[cfg(feature = "sqlx")] +impl<'q> sqlx::Encode<'q, sqlx::MySql> for InviteFlags { + fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { + u64::encode_by_ref(&self.0.0, buf) + } +} + +#[cfg(feature = "sqlx")] +impl<'r> sqlx::Decode<'r, sqlx::MySql> for InviteFlags { + fn decode(value: >::ValueRef) -> Result { + let raw = u64::decode(value)?; + + Ok(Self::from_bits(raw).unwrap()) + } +} + #[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] From 133b03f1c8acbf073a9c21814ac216468b5e74c2 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 22:22:39 -0400 Subject: [PATCH 041/162] Use distinct type `DefaultReaction` --- src/types/schema/channel.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index d7163991..68abc79a 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -5,7 +5,7 @@ use bitflags::bitflags; use serde::{Deserialize, Serialize}; -use crate::types::ChannelType; +use crate::types::{ChannelType, DefaultReaction}; use crate::types::{entities::PermissionOverwrite, Snowflake}; #[derive(Debug, Deserialize, Serialize, Default, PartialEq, PartialOrd)] @@ -48,7 +48,7 @@ pub struct ChannelModifySchema { pub nsfw: Option, pub rtc_region: Option, pub default_auto_archive_duration: Option, - pub default_reaction_emoji: Option, + pub default_reaction_emoji: Option, pub flags: Option, pub default_thread_rate_limit_per_user: Option, pub video_quality_mode: Option, From 450aa9f4407dd6c26933edf197d08c8f248862dc Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 22:24:03 -0400 Subject: [PATCH 042/162] Update fields for backend/sqlx compatibility. --- src/types/entities/invite.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/types/entities/invite.rs b/src/types/entities/invite.rs index e9c9bd8b..8455f163 100644 --- a/src/types/entities/invite.rs +++ b/src/types/entities/invite.rs @@ -5,7 +5,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::types::{Snowflake, WelcomeScreenObject, Shared}; +use crate::types::{Snowflake, WelcomeScreenObject, Shared, InviteFlags, InviteType, InviteTargetType}; use super::guild::GuildScheduledEvent; use super::{Application, Channel, GuildMember, NSFWLevel, User}; @@ -13,25 +13,35 @@ use super::{Application, Channel, GuildMember, NSFWLevel, User}; /// Represents a code that when used, adds a user to a guild or group DM channel, or creates a relationship between two users. /// See #[derive(Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Invite { pub approximate_member_count: Option, pub approximate_presence_count: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub channel: Option, pub code: String, pub created_at: Option>, pub expires_at: Option>, - pub flags: Option, + pub flags: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub guild: Option, pub guild_id: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub guild_scheduled_event: Option>, #[serde(rename = "type")] - pub invite_type: Option, + #[cfg_attr(feature = "sqlx", sqlx(rename = "type"))] + pub invite_type: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub inviter: Option, - pub max_age: Option, - pub max_uses: Option, + pub max_age: Option, + pub max_uses: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub stage_instance: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub target_application: Option, - pub target_type: Option, + #[cfg_attr(feature = "sqlx", sqlx(rename = "target_user_type"))] + pub target_type: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub target_user: Option, pub temporary: Option, pub uses: Option, From 9f281879a9e0b98a7c81d1b7e5cd8eff6e229dd2 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 22:24:28 -0400 Subject: [PATCH 043/162] Update derive for backend/sqlx compatibility. --- src/types/entities/channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 262897c2..3d6b4cae 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -177,7 +177,7 @@ pub struct ThreadMember { pub member: Option>, } -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd)] /// Specifies the emoji to use as the default way to react to a [ChannelType::GuildForum] or [ChannelType::GuildMedia] channel post. /// /// # Reference From cab4cb1ce63dc79b127ac60540246c50e791da5f Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 23:07:04 -0400 Subject: [PATCH 044/162] Write custom serialize/deserialize impl's for InviteFlags --- src/types/errors.rs | 3 +++ src/types/schema/channel.rs | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/types/errors.rs b/src/types/errors.rs index f0a488ce..f417aef4 100644 --- a/src/types/errors.rs +++ b/src/types/errors.rs @@ -21,6 +21,9 @@ pub enum Error { #[error(transparent)] Guild(#[from] GuildError), + + #[error("Invalid flags value: {0}")] + InvalidFlags(u64) } #[derive(Debug, PartialEq, Eq, thiserror::Error)] diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 68abc79a..da49aec7 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -2,10 +2,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use std::error::Error as StdError; +use std::num::ParseIntError; use bitflags::bitflags; -use serde::{Deserialize, Serialize}; +use bitflags::parser::ParseHex; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde::de::{DeserializeOwned, Visitor}; -use crate::types::{ChannelType, DefaultReaction}; +use crate::types::{ChannelType, DefaultReaction, Error}; use crate::types::{entities::PermissionOverwrite, Snowflake}; #[derive(Debug, Deserialize, Serialize, Default, PartialEq, PartialOrd)] @@ -131,12 +135,39 @@ impl Default for CreateChannelInviteSchema { } bitflags! { - #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)] + #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct InviteFlags: u64 { const GUEST = 1 << 0; } } +impl Serialize for InviteFlags { + fn serialize(&self, serializer: S) -> Result { + self.bits().to_string().serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for InviteFlags { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { + struct FlagsVisitor; + + impl<'de> Visitor<'de> for FlagsVisitor + { + type Value = InviteFlags; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("a raw u64 value of flags") + } + + fn visit_u64(self, v: u64) -> Result where E: serde::de::Error { + InviteFlags::from_bits(v).ok_or(serde::de::Error::custom(Error::InvalidFlags(v))) + } + } + + deserializer.deserialize_u64(FlagsVisitor) + } +} + #[cfg(feature = "sqlx")] impl sqlx::Type for InviteFlags { fn type_info() -> sqlx::mysql::MySqlTypeInfo { From 0f1e693d6041c3b9634b0d1b55a2f7598822e1cc Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 23:45:22 -0400 Subject: [PATCH 045/162] Clear warnings --- src/types/schema/channel.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index da49aec7..7f99394e 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -2,12 +2,9 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::error::Error as StdError; -use std::num::ParseIntError; use bitflags::bitflags; -use bitflags::parser::ParseHex; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use serde::de::{DeserializeOwned, Visitor}; +use serde::de::Visitor; use crate::types::{ChannelType, DefaultReaction, Error}; use crate::types::{entities::PermissionOverwrite, Snowflake}; From c34b1da8d050efaf7d1d6b226b2275754a7bccdf Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 4 Jun 2024 23:53:21 -0400 Subject: [PATCH 046/162] Add InviteFlags::VIEWED --- src/types/schema/channel.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 7f99394e..60caf397 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -6,8 +6,7 @@ use bitflags::bitflags; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::de::Visitor; -use crate::types::{ChannelType, DefaultReaction, Error}; -use crate::types::{entities::PermissionOverwrite, Snowflake}; +use crate::types::{ChannelType, DefaultReaction, Error, entities::PermissionOverwrite, Snowflake}; #[derive(Debug, Deserialize, Serialize, Default, PartialEq, PartialOrd)] #[serde(rename_all = "snake_case")] @@ -135,6 +134,7 @@ bitflags! { #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct InviteFlags: u64 { const GUEST = 1 << 0; + const VIEWED = 1 << 1; } } From 0d01536f5962d83e9047e9d0ae54422dcd5c398f Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Wed, 5 Jun 2024 00:46:29 -0400 Subject: [PATCH 047/162] Remove double bound for E --- src/types/schema/channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 60caf397..260b10e7 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -156,7 +156,7 @@ impl<'de> Deserialize<'de> for InviteFlags { formatter.write_str("a raw u64 value of flags") } - fn visit_u64(self, v: u64) -> Result where E: serde::de::Error { + fn visit_u64(self, v: u64) -> Result { InviteFlags::from_bits(v).ok_or(serde::de::Error::custom(Error::InvalidFlags(v))) } } From c8bde0c9ec26f2fc22d9dae62da73173882b7aa9 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Wed, 5 Jun 2024 14:49:17 -0400 Subject: [PATCH 048/162] Use distinct types in `InviteGuild` object. --- src/types/entities/invite.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/types/entities/invite.rs b/src/types/entities/invite.rs index 8455f163..61318951 100644 --- a/src/types/entities/invite.rs +++ b/src/types/entities/invite.rs @@ -5,7 +5,8 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::types::{Snowflake, WelcomeScreenObject, Shared, InviteFlags, InviteType, InviteTargetType}; +use crate::types::{Snowflake, WelcomeScreenObject, Shared, InviteFlags, InviteType, InviteTargetType, Guild, VerificationLevel}; +use crate::types::types::guild_configuration::GuildFeaturesList; use super::guild::GuildScheduledEvent; use super::{Application, Channel, GuildMember, NSFWLevel, User}; @@ -55,8 +56,8 @@ pub struct InviteGuild { pub name: String, pub icon: Option, pub splash: Option, - pub verification_level: i32, - pub features: Vec, + pub verification_level: VerificationLevel, + pub features: GuildFeaturesList, pub vanity_url_code: Option, pub description: Option, pub banner: Option, From 5110e9bfdb020f2afd114f91db84dcd2c7ebbfdd Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Wed, 5 Jun 2024 14:49:34 -0400 Subject: [PATCH 049/162] Implement `From for InviteGuild` --- src/types/entities/invite.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/types/entities/invite.rs b/src/types/entities/invite.rs index 61318951..0bfce28f 100644 --- a/src/types/entities/invite.rs +++ b/src/types/entities/invite.rs @@ -69,6 +69,26 @@ pub struct InviteGuild { pub welcome_screen: Option, } +impl From for InviteGuild { + fn from(value: Guild) -> Self { + Self { + id: value.id, + name: value.name.unwrap_or_default(), + icon: value.icon, + splash: value.splash, + verification_level: value.verification_level.unwrap_or_default(), + features: value.features.unwrap_or_default(), + vanity_url_code: value.vanity_url_code, + description: value.description, + banner: value.banner, + premium_subscription_count: value.premium_subscription_count, + nsfw_deprecated: None, + nsfw_level: value.nsfw_level.unwrap_or_default(), + welcome_screen: value.welcome_screen.map(|obj| obj.0), + } + } +} + /// See #[derive(Debug, Serialize, Deserialize)] pub struct InviteStageInstance { From eb87bd6ffc70cefe682b8a3cd7930a1f76744c07 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Wed, 5 Jun 2024 14:50:10 -0400 Subject: [PATCH 050/162] Add `GetInvitesSchema` --- src/types/schema/invites.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/types/schema/invites.rs diff --git a/src/types/schema/invites.rs b/src/types/schema/invites.rs new file mode 100644 index 00000000..cecf0733 --- /dev/null +++ b/src/types/schema/invites.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)] +/// Query parameters for routes that list invites. +/// # Reference: +/// Read: +pub struct GetInvitesSchema { + pub with_counts: Option, +} \ No newline at end of file From 556fbb9ded628494bb73a3833086b61d1b388396 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Wed, 5 Jun 2024 14:50:38 -0400 Subject: [PATCH 051/162] Add forgotten import and pub use. --- src/types/schema/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/types/schema/mod.rs b/src/types/schema/mod.rs index d353e09d..ef3233db 100644 --- a/src/types/schema/mod.rs +++ b/src/types/schema/mod.rs @@ -10,6 +10,7 @@ pub use message::*; pub use relationship::*; pub use role::*; pub use user::*; +pub use invites::*; mod apierror; mod auth; @@ -19,3 +20,4 @@ mod message; mod relationship; mod role; mod user; +mod invites; From a0cddbf3ae48ac6ce6793b0c3406f48731afaf7d Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Wed, 5 Jun 2024 21:10:29 -0400 Subject: [PATCH 052/162] Fix compile error --- src/types/entities/invite.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/types/entities/invite.rs b/src/types/entities/invite.rs index 0bfce28f..caec03fc 100644 --- a/src/types/entities/invite.rs +++ b/src/types/entities/invite.rs @@ -84,7 +84,13 @@ impl From for InviteGuild { premium_subscription_count: value.premium_subscription_count, nsfw_deprecated: None, nsfw_level: value.nsfw_level.unwrap_or_default(), - welcome_screen: value.welcome_screen.map(|obj| obj.0), + welcome_screen: value.welcome_screen.map(|obj| { + #[cfg(feature = "sqlx")] + let res = obj.0; + #[cfg(not(feature = "sqlx"))] + let res = obj; + res + }), } } } From 83a8f080b7811de0f9b5d5df1642690498b81152 Mon Sep 17 00:00:00 2001 From: Quat3rnion <81202811+Quat3rnion@users.noreply.github.com> Date: Fri, 7 Jun 2024 00:46:53 -0400 Subject: [PATCH 053/162] Update docs aesthetics Co-authored-by: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> --- src/types/schema/invites.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/types/schema/invites.rs b/src/types/schema/invites.rs index cecf0733..6bf2131a 100644 --- a/src/types/schema/invites.rs +++ b/src/types/schema/invites.rs @@ -1,9 +1,10 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)] -/// Query parameters for routes that list invites. +/// Query parameters for the `Get Invite` route. +/// /// # Reference: -/// Read: +/// Read: pub struct GetInvitesSchema { pub with_counts: Option, } \ No newline at end of file From 0468292ec646d8be99cbb4f97a47b23340c4a6de Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Fri, 7 Jun 2024 02:08:21 -0400 Subject: [PATCH 054/162] Add type locks --- src/types/entities/message.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index 4b57e062..6e493fcc 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -63,13 +63,20 @@ pub struct Message { #[cfg(not(feature = "sqlx"))] pub message_reference: Option, pub flags: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub referenced_message: Option>, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub interaction: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub thread: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub components: Option>, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub sticker_items: Option>, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub stickers: Option>, pub position: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub role_subscription_data: Option, } From ed5365ade4e6a367d5ff8ade79e07382c2d5e6e7 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Fri, 7 Jun 2024 02:08:41 -0400 Subject: [PATCH 055/162] Fix inverted type wrapping --- src/types/entities/message.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index 6e493fcc..9159c586 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -39,7 +39,7 @@ pub struct Message { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub attachments: Option>, #[cfg(feature = "sqlx")] - pub embeds: Vec>, + pub embeds: sqlx::types::Json>, #[cfg(not(feature = "sqlx"))] pub embeds: Option>, #[cfg(feature = "sqlx")] From c2035585ae41de2b3a59fddccaf82dd542c9c1c2 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Fri, 7 Jun 2024 13:02:17 -0400 Subject: [PATCH 056/162] Update Cargo.lock --- chorus-macros/Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chorus-macros/Cargo.lock b/chorus-macros/Cargo.lock index 9f146197..64632bc3 100644 --- a/chorus-macros/Cargo.lock +++ b/chorus-macros/Cargo.lock @@ -15,7 +15,7 @@ dependencies = [ [[package]] name = "chorus-macros" -version = "0.2.1" +version = "0.3.0" dependencies = [ "async-trait", "quote", From 656e5e31c084e53d5a5716d68ddb04bdf71397c9 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Fri, 7 Jun 2024 13:03:44 -0400 Subject: [PATCH 057/162] Add SqlxBitFlags derive macro --- chorus-macros/src/lib.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/chorus-macros/src/lib.rs b/chorus-macros/src/lib.rs index 436fd68c..6034ff81 100644 --- a/chorus-macros/src/lib.rs +++ b/chorus-macros/src/lib.rs @@ -155,3 +155,34 @@ pub fn composite_derive(input: TokenStream) -> TokenStream { _ => panic!("Composite derive macro only supports structs"), } } + +#[proc_macro_derive(SqlxBitFlags)] +pub fn sqlx_bitflag_derive(input: TokenStream) -> TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + + let name = &ast.ident; + + quote!{ + #[cfg(feature = "sqlx")] + impl sqlx::Type for #name { + fn type_info() -> sqlx::mysql::MySqlTypeInfo { + u64::type_info() + } + } + + #[cfg(feature = "sqlx")] + impl<'q> sqlx::Encode<'q, sqlx::MySql> for #name { + fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> IsNull { + u64::encode_by_ref(&self.bits(), buf) + } + } + + #[cfg(feature = "sqlx")] + impl<'q> sqlx::Decode<'q, sqlx::MySql> for #name { + fn decode(value: >::ValueRef) -> Result { + u64::decode(value).map(|d| #name::from_bits(d).unwrap()) + } + } + } + .into() +} \ No newline at end of file From d89975819a08fd4304e9b25b8d7a10c32405531b Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Fri, 7 Jun 2024 13:13:03 -0400 Subject: [PATCH 058/162] Utilize new macros and use distinct Flag types --- src/types/entities/application.rs | 11 +++------ src/types/entities/guild.rs | 3 ++- src/types/entities/guild_member.rs | 4 ++-- src/types/entities/message.rs | 38 +++++++++++++++++++++++++++++- src/types/entities/role.rs | 1 + src/types/entities/user.rs | 4 ++-- src/types/schema/channel.rs | 24 +------------------ src/types/schema/guild.rs | 1 + src/types/schema/message.rs | 4 ++-- 9 files changed, 51 insertions(+), 39 deletions(-) diff --git a/src/types/entities/application.rs b/src/types/entities/application.rs index c7727884..f57a71f8 100644 --- a/src/types/entities/application.rs +++ b/src/types/entities/application.rs @@ -31,7 +31,7 @@ pub struct Application { pub verify_key: String, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub owner: Shared, - pub flags: u64, + pub flags: ApplicationFlags, #[cfg(feature = "sqlx")] pub redirect_uris: Option>>, #[cfg(not(feature = "sqlx"))] @@ -73,7 +73,7 @@ impl Default for Application { bot_require_code_grant: false, verify_key: "".to_string(), owner: Default::default(), - flags: 0, + flags: ApplicationFlags::empty(), redirect_uris: None, rpc_application_state: 0, store_application_state: 1, @@ -93,12 +93,6 @@ impl Default for Application { } } -impl Application { - pub fn flags(&self) -> ApplicationFlags { - ApplicationFlags::from_bits(self.flags.to_owned()).unwrap() - } -} - #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] /// # Reference /// See @@ -109,6 +103,7 @@ pub struct InstallParams { bitflags! { #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)] + #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] /// # Reference /// See pub struct ApplicationFlags: u64 { diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 66b93357..b8fd0a4a 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -99,7 +99,7 @@ pub struct Guild { pub splash: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub stickers: Option>, - pub system_channel_flags: Option, + pub system_channel_flags: Option, pub system_channel_id: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub vanity_url_code: Option, @@ -423,6 +423,7 @@ pub enum PremiumTier { bitflags! { #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)] + #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] /// # Reference /// See pub struct SystemChannelFlags: u64 { diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index df075833..522824ce 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -5,7 +5,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::types::Shared; +use crate::types::{GuildMemberFlags, Shared}; use crate::types::{entities::PublicUser, Snowflake}; #[derive(Debug, Deserialize, Default, Serialize, Clone)] @@ -25,7 +25,7 @@ pub struct GuildMember { pub premium_since: Option>, pub deaf: bool, pub mute: bool, - pub flags: Option, + pub flags: Option, pub pending: Option, pub permissions: Option, pub communication_disabled_until: Option>, diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index 9159c586..a6d91e70 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -2,6 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use bitflags::bitflags; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -62,7 +63,7 @@ pub struct Message { pub message_reference: Option>, #[cfg(not(feature = "sqlx"))] pub message_reference: Option, - pub flags: Option, + pub flags: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub referenced_message: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] @@ -260,3 +261,38 @@ pub struct MessageActivity { pub activity_type: i64, pub party_id: Option, } + +bitflags! { + #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd)] + #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] + /// # Reference + /// See + pub struct MessageFlags: u64 { + /// This message has been published to subscribed channels (via Channel Following) + const CROSSPOSTED = 1 << 0; + /// This message originated from a message in another channel (via Channel Following) + const IS_CROSSPOST = 1 << 1; + /// Embeds will not be included when serializing this message + const SUPPRESS_EMBEDS = 1 << 2; + /// The source message for this crosspost has been deleted (via Channel Following) + const SOURCE_MESSAGE_DELETED = 1 << 3; + /// This message came from the urgent message system + const URGENT = 1 << 4; + /// This message has an associated thread, with the same ID as the message + const HAS_THREAD = 1 << 5; + /// This message is only visible to the user who invoked the interaction + const EPHEMERAL = 1 << 6; + /// This message is an interaction response and the bot is "thinking" + const LOADING = 1 << 7; + /// Some roles were not mentioned and added to the thread + const FAILED_TO_MENTION_SOME_ROLES_IN_THREAD = 1 << 8; + /// This message contains a link that impersonates Discord + const SHOULD_SHOW_LINK_NOT_DISCORD_WARNING = 1 << 10; + /// This message will not trigger push and desktop notifications + const SUPPRESS_NOTIFICATIONS = 1 << 12; + /// This message's audio attachments are rendered as voice messages + const VOICE_MESSAGE = 1 << 13; + /// This message has a forwarded message snapshot attached + const HAS_SNAPSHOT = 1 << 14; + } +} \ No newline at end of file diff --git a/src/types/entities/role.rs b/src/types/entities/role.rs index 1b5e91e3..712c9abf 100644 --- a/src/types/entities/role.rs +++ b/src/types/entities/role.rs @@ -72,6 +72,7 @@ pub struct RoleTags { bitflags! { #[derive(Debug, Default, Clone, Hash, Serialize, Deserialize, PartialEq, Eq)] + #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] /// Permissions limit what users of certain roles can do on a Guild to Guild basis. /// /// # Reference: diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index 66fbab84..1577479b 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -54,7 +54,7 @@ pub struct User { /// So we need to account for that #[serde(default)] #[serde(deserialize_with = "deserialize_option_number_from_string")] - pub flags: Option, + pub flags: Option, pub premium_since: Option>, pub premium_type: Option, pub pronouns: Option, @@ -112,7 +112,7 @@ const CUSTOM_USER_FLAG_OFFSET: u64 = 1 << 32; bitflags::bitflags! { #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)] - #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] + #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] pub struct UserFlags: u64 { const DISCORD_EMPLOYEE = 1 << 0; const PARTNERED_SERVER_OWNER = 1 << 1; diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 260b10e7..fc2eea6e 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -132,6 +132,7 @@ impl Default for CreateChannelInviteSchema { bitflags! { #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] pub struct InviteFlags: u64 { const GUEST = 1 << 0; const VIEWED = 1 << 1; @@ -165,29 +166,6 @@ impl<'de> Deserialize<'de> for InviteFlags { } } -#[cfg(feature = "sqlx")] -impl sqlx::Type for InviteFlags { - fn type_info() -> sqlx::mysql::MySqlTypeInfo { - u64::type_info() - } -} - -#[cfg(feature = "sqlx")] -impl<'q> sqlx::Encode<'q, sqlx::MySql> for InviteFlags { - fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { - u64::encode_by_ref(&self.0.0, buf) - } -} - -#[cfg(feature = "sqlx")] -impl<'r> sqlx::Decode<'r, sqlx::MySql> for InviteFlags { - fn decode(value: >::ValueRef) -> Result { - let raw = u64::decode(value)?; - - Ok(Self::from_bits(raw).unwrap()) - } -} - #[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] diff --git a/src/types/schema/guild.rs b/src/types/schema/guild.rs index 2e29ce02..d820cd84 100644 --- a/src/types/schema/guild.rs +++ b/src/types/schema/guild.rs @@ -132,6 +132,7 @@ pub struct ModifyGuildMemberSchema { bitflags! { #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)] + #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] /// Represents the flags of a Guild Member. /// /// # Reference: diff --git a/src/types/schema/message.rs b/src/types/schema/message.rs index 7551b6be..d6b8cc7f 100644 --- a/src/types/schema/message.rs +++ b/src/types/schema/message.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::types::entities::{ AllowedMention, Component, Embed, MessageReference, PartialDiscordFileAttachment, }; -use crate::types::{Attachment, Snowflake}; +use crate::types::{Attachment, MessageFlags, Snowflake}; #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)] #[serde(rename_all = "snake_case")] @@ -123,7 +123,7 @@ pub struct MessageModifySchema { embed: Option, allowed_mentions: Option, components: Option>, - flags: Option, + flags: Option, files: Option>, payload_json: Option, attachments: Option>, From d3e2ef947ce9f0856c125557d389a619e6bfefc6 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Fri, 7 Jun 2024 13:14:25 -0400 Subject: [PATCH 059/162] Add distinct MessageType enum --- src/types/entities/message.rs | 111 +++++++++++++++++++++++++++++++++- src/types/schema/message.rs | 4 +- 2 files changed, 112 insertions(+), 3 deletions(-) diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index a6d91e70..697be0de 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -5,6 +5,11 @@ use bitflags::bitflags; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; +use sqlx::database::{HasArguments, HasValueRef}; +use sqlx::encode::IsNull; +use sqlx::error::BoxDynError; +use sqlx::{Encode, MySql}; use crate::types::{ Shared, @@ -51,7 +56,7 @@ pub struct Message { pub pinned: bool, pub webhook_id: Option, #[serde(rename = "type")] - pub message_type: i32, + pub message_type: MessageType, #[cfg(feature = "sqlx")] pub activity: Option>, #[cfg(not(feature = "sqlx"))] @@ -235,10 +240,15 @@ pub struct EmbedField { pub struct Reaction { pub count: u32, pub burst_count: u32, + #[serde(default)] pub me: bool, + #[serde(default)] pub burst_me: bool, pub burst_colors: Vec, pub emoji: Emoji, + #[cfg(feature = "sqlx")] + #[serde(skip)] + pub user_ids: Vec } #[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, Eq, PartialOrd, Ord)] @@ -262,6 +272,105 @@ pub struct MessageActivity { pub party_id: Option, } +#[derive(Debug, Default, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr, Eq, PartialOrd, Ord)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +#[repr(u8)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +/// # Reference +/// See +pub enum MessageType { + /// A default message + #[default] + Default = 0, + /// A message sent when a user is added to a group DM or thread + RecipientAdd = 1, + /// A message sent when a user is removed from a group DM or thread + RecipientRemove = 2, + /// A message sent when a user creates a call in a private channel + Call = 3, + /// A message sent when a group DM or thread's name is changed + ChannelNameChange = 4, + /// A message sent when a group DM's icon is changed + ChannelIconChange = 5, + /// A message sent when a message is pinned in a channel + ChannelPinnedMessage = 6, + /// A message sent when a user joins a guild + GuildMemberJoin = 7, + /// A message sent when a user subscribes to (boosts) a guild + UserPremiumGuildSubscription = 8, + /// A message sent when a user subscribes to (boosts) a guild to tier 1 + UserPremiumGuildSubscriptionTier1 = 9, + /// A message sent when a user subscribes to (boosts) a guild to tier 2 + UserPremiumGuildSubscriptionTier2 = 10, + /// A message sent when a user subscribes to (boosts) a guild to tier 3 + UserPremiumGuildSubscriptionTier3 = 11, + /// A message sent when a news channel is followed + ChannelFollowAdd = 12, + /// A message sent when a user starts streaming in a guild (deprecated) + #[deprecated] + GuildStream = 13, + /// A message sent when a guild is disqualified from discovery + GuildDiscoveryDisqualified = 14, + /// A message sent when a guild requalifies for discovery + GuildDiscoveryRequalified = 15, + /// A message sent when a guild has failed discovery requirements for a week + GuildDiscoveryGracePeriodInitial = 16, + /// A message sent when a guild has failed discovery requirements for 3 weeks + GuildDiscoveryGracePeriodFinal = 17, + /// A message sent when a thread is created + ThreadCreated = 18, + /// A message sent when a user replies to a message + Reply = 19, + /// A message sent when a user uses a slash command + #[serde(rename = "CHAT_INPUT_COMMAND")] + ApplicationCommand = 20, + /// A message sent when a thread starter message is added to a thread + ThreadStarterMessage = 21, + /// A message sent to remind users to invite friends to a guild + GuildInviteReminder = 22, + /// A message sent when a user uses a context menu command + ContextMenuCommand = 23, + /// A message sent when auto moderation takes an action + AutoModerationAction = 24, + /// A message sent when a user purchases or renews a role subscription + RoleSubscriptionPurchase = 25, + /// A message sent when a user is upsold to a premium interaction + InteractionPremiumUpsell = 26, + /// A message sent when a stage channel starts + StageStart = 27, + /// A message sent when a stage channel ends + StageEnd = 28, + /// A message sent when a user starts speaking in a stage channel + StageSpeaker = 29, + /// A message sent when a user raises their hand in a stage channel + StageRaiseHand = 30, + /// A message sent when a stage channel's topic is changed + StageTopic = 31, + /// A message sent when a user purchases an application premium subscription + GuildApplicationPremiumSubscription = 32, + /// A message sent when a user adds an application to group DM + PrivateChannelIntegrationAdded = 33, + /// A message sent when a user removed an application from a group DM + PrivateChannelIntegrationRemoved = 34, + /// A message sent when a user gifts a premium (Nitro) referral + PremiumReferral = 35, + /// A message sent when a user enabled lockdown for the guild + GuildIncidentAlertModeEnabled = 36, + /// A message sent when a user disables lockdown for the guild + GuildIncidentAlertModeDisabled = 37, + /// A message sent when a user reports a raid for the guild + GuildIncidentReportRaid = 38, + /// A message sent when a user reports a false alarm for the guild + GuildIncidentReportFalseAlarm = 39, + /// A message sent when no one sends a message in the current channel for 1 hour + GuildDeadchatRevivePrompt = 40, + /// A message sent when a user buys another user a gift + CustomGift = 41, + GuildGamingStatsPrompt = 42, + /// A message sent when a user purchases a guild product + PurchaseNotification = 44 +} + bitflags! { #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd)] #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] diff --git a/src/types/schema/message.rs b/src/types/schema/message.rs index d6b8cc7f..a7c1eebc 100644 --- a/src/types/schema/message.rs +++ b/src/types/schema/message.rs @@ -7,13 +7,13 @@ use serde::{Deserialize, Serialize}; use crate::types::entities::{ AllowedMention, Component, Embed, MessageReference, PartialDiscordFileAttachment, }; -use crate::types::{Attachment, MessageFlags, Snowflake}; +use crate::types::{Attachment, MessageFlags, MessageType, Snowflake}; #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)] #[serde(rename_all = "snake_case")] pub struct MessageSendSchema { #[serde(rename = "type")] - pub message_type: Option, + pub message_type: Option, pub content: Option, pub nonce: Option, pub tts: Option, From 9bd55b9b5f440035ecbdcdc4645ac9374b9ab180 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Fri, 7 Jun 2024 14:08:24 -0400 Subject: [PATCH 060/162] Fix error in macro --- chorus-macros/src/lib.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/chorus-macros/src/lib.rs b/chorus-macros/src/lib.rs index 6034ff81..9f56a53c 100644 --- a/chorus-macros/src/lib.rs +++ b/chorus-macros/src/lib.rs @@ -163,23 +163,20 @@ pub fn sqlx_bitflag_derive(input: TokenStream) -> TokenStream { let name = &ast.ident; quote!{ - #[cfg(feature = "sqlx")] impl sqlx::Type for #name { fn type_info() -> sqlx::mysql::MySqlTypeInfo { u64::type_info() } } - #[cfg(feature = "sqlx")] impl<'q> sqlx::Encode<'q, sqlx::MySql> for #name { - fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> IsNull { + fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { u64::encode_by_ref(&self.bits(), buf) } } - #[cfg(feature = "sqlx")] impl<'q> sqlx::Decode<'q, sqlx::MySql> for #name { - fn decode(value: >::ValueRef) -> Result { + fn decode(value: >::ValueRef) -> Result { u64::decode(value).map(|d| #name::from_bits(d).unwrap()) } } From 590a6d6828b0b31a9a2efc0b6b55b0250280e82c Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Fri, 7 Jun 2024 14:08:47 -0400 Subject: [PATCH 061/162] Make UserFlags deserialize from string --- src/types/entities/user.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index 1577479b..ddbdc22c 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -4,9 +4,11 @@ use crate::types::utils::Snowflake; use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_aux::prelude::deserialize_option_number_from_string; use std::fmt::Debug; +use std::num::ParseIntError; +use std::str::FromStr; #[cfg(feature = "client")] use crate::gateway::Updateable; @@ -111,7 +113,7 @@ impl From for PublicUser { const CUSTOM_USER_FLAG_OFFSET: u64 = 1 << 32; bitflags::bitflags! { - #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] pub struct UserFlags: u64 { const DISCORD_EMPLOYEE = 1 << 0; @@ -137,6 +139,28 @@ bitflags::bitflags! { } } +impl FromStr for UserFlags { + type Err = ParseIntError; + + fn from_str(s: &str) -> Result { + s.parse::().map(UserFlags::from_bits).map(|f| f.unwrap_or(UserFlags::empty())) + } +} + +impl Serialize for UserFlags { + fn serialize(&self, serializer: S) -> Result { + serializer.serialize_str(&self.bits().to_string()) + } +} + +impl<'de> Deserialize<'de> for UserFlags { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { + let s = String::deserialize(deserializer)?.parse::().map_err(serde::de::Error::custom)?; + + Ok(UserFlags::from_bits(s).unwrap()) + } +} + #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct UserProfileMetadata { pub guild_id: Option, From bec0269e70ed124926596e9564d11159abef6bdc Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Mon, 17 Jun 2024 15:22:58 -0400 Subject: [PATCH 062/162] Add partial emoji and custom reaction types, refine SQLx mapping --- .../config/types/register_configuration.rs | 2 + src/types/entities/channel.rs | 4 ++ src/types/entities/emoji.rs | 17 +++++++- src/types/entities/guild.rs | 4 +- src/types/entities/invite.rs | 10 +++-- src/types/entities/message.rs | 35 +++++++++++++++-- src/types/schema/channel.rs | 8 ++-- src/types/schema/message.rs | 28 ++++++++----- src/types/utils/rights.rs | 39 ++++++++----------- src/types/utils/snowflake.rs | 23 ++++++++++- 10 files changed, 122 insertions(+), 48 deletions(-) diff --git a/src/types/config/types/register_configuration.rs b/src/types/config/types/register_configuration.rs index 19cedfb6..4afc40cf 100644 --- a/src/types/config/types/register_configuration.rs +++ b/src/types/config/types/register_configuration.rs @@ -3,6 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use serde::{Deserialize, Serialize}; +use serde_aux::prelude::deserialize_number_from_string; use crate::types::{config::types::subconfigs::register::{ DateOfBirthConfiguration, PasswordConfiguration, RegistrationEmailConfiguration, @@ -22,6 +23,7 @@ pub struct RegisterConfiguration { pub allow_multiple_accounts: bool, pub block_proxies: bool, pub incrementing_discriminators: bool, + #[serde(deserialize_with = "deserialize_number_from_string")] pub default_rights: Rights, } diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 3d6b4cae..782b6a60 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -64,7 +64,9 @@ pub struct Channel { pub managed: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub member: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub member_count: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub message_count: Option, pub name: Option, pub nsfw: Option, @@ -75,6 +77,7 @@ pub struct Channel { #[cfg(not(feature = "sqlx"))] #[cfg_attr(feature = "client", observe_option_vec)] pub permission_overwrites: Option>>, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub permissions: Option, pub position: Option, pub rate_limit_per_user: Option, @@ -85,6 +88,7 @@ pub struct Channel { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub thread_metadata: Option, pub topic: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub total_message_sent: Option, pub user_limit: Option, pub video_quality_mode: Option, diff --git a/src/types/entities/emoji.rs b/src/types/entities/emoji.rs index 1b68f0dc..23956b5d 100644 --- a/src/types/entities/emoji.rs +++ b/src/types/entities/emoji.rs @@ -6,7 +6,7 @@ use std::fmt::Debug; use serde::{Deserialize, Serialize}; -use crate::types::Shared; +use crate::types::{PartialEmoji, Shared}; use crate::types::entities::User; use crate::types::Snowflake; @@ -66,3 +66,18 @@ impl PartialEq for Emoji { || self.available != other.available) } } + +impl From for Emoji { + fn from(value: PartialEmoji) -> Self { + Self { + id: value.id.unwrap_or_default(), // TODO: this should be handled differently + name: Some(value.name), + roles: None, + user: None, + require_colons: Some(value.animated), + managed: None, + animated: Some(value.animated), + available: None, + } + } +} \ No newline at end of file diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index b8fd0a4a..e3c8a7ec 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -59,7 +59,7 @@ pub struct Guild { pub emojis: Vec>, pub explicit_content_filter: Option, //#[cfg_attr(feature = "sqlx", sqlx(try_from = "String"))] - pub features: Option, + pub features: GuildFeaturesList, pub icon: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub icon_hash: Option, @@ -111,7 +111,7 @@ pub struct Guild { #[cfg_attr(feature = "client", observe_option_vec)] pub webhooks: Option>>, #[cfg(feature = "sqlx")] - pub welcome_screen: Option>, + pub welcome_screen: sqlx::types::Json>, #[cfg(not(feature = "sqlx"))] pub welcome_screen: Option, pub widget_channel_id: Option, diff --git a/src/types/entities/invite.rs b/src/types/entities/invite.rs index caec03fc..bb1d4001 100644 --- a/src/types/entities/invite.rs +++ b/src/types/entities/invite.rs @@ -16,7 +16,9 @@ use super::{Application, Channel, GuildMember, NSFWLevel, User}; #[derive(Debug, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Invite { + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub approximate_member_count: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub approximate_presence_count: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub channel: Option, @@ -45,7 +47,7 @@ pub struct Invite { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub target_user: Option, pub temporary: Option, - pub uses: Option, + pub uses: Option, } /// The guild an invite is for. @@ -77,16 +79,16 @@ impl From for InviteGuild { icon: value.icon, splash: value.splash, verification_level: value.verification_level.unwrap_or_default(), - features: value.features.unwrap_or_default(), + features: value.features, vanity_url_code: value.vanity_url_code, description: value.description, banner: value.banner, premium_subscription_count: value.premium_subscription_count, nsfw_deprecated: None, nsfw_level: value.nsfw_level.unwrap_or_default(), - welcome_screen: value.welcome_screen.map(|obj| { + welcome_screen: value.welcome_screen.0.map(|obj| { #[cfg(feature = "sqlx")] - let res = obj.0; + let res = obj; #[cfg(not(feature = "sqlx"))] let res = obj; res diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index 697be0de..e31b7be0 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -75,13 +75,14 @@ pub struct Message { pub interaction: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub thread: Option, - #[cfg_attr(feature = "sqlx", sqlx(skip))] + #[cfg(feature = "sqlx")] + pub components: Option>>, + #[cfg(not(feature = "sqlx"))] pub components: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub sticker_items: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub stickers: Option>, - pub position: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub role_subscription_data: Option, } @@ -116,7 +117,7 @@ impl PartialEq for Message { && self.thread == other.thread && self.components == other.components && self.sticker_items == other.sticker_items - && self.position == other.position + // && self.position == other.position && self.role_subscription_data == other.role_subscription_data } } @@ -125,12 +126,22 @@ impl PartialEq for Message { /// # Reference /// See pub struct MessageReference { + #[serde(rename = "type")] + pub reference_type: MessageReferenceType, pub message_id: Snowflake, pub channel_id: Snowflake, pub guild_id: Option, pub fail_if_not_exists: Option, } +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Eq, Ord, PartialOrd)] +pub enum MessageReferenceType { + /// A standard reference used by replies and system messages + Default = 0, + /// A reference used to point to a message at a point in time + Forward = 1, +} + #[derive(Debug, Clone, Deserialize, Serialize)] pub struct MessageInteraction { pub id: Snowflake, @@ -404,4 +415,22 @@ bitflags! { /// This message has a forwarded message snapshot attached const HAS_SNAPSHOT = 1 << 14; } +} + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +pub struct PartialEmoji { + #[serde(default)] + pub id: Option, + pub name: String, + #[serde(default)] + pub animated: bool +} + +#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, PartialOrd)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[repr(u8)] +pub enum ReactionType { + Normal = 0, + Burst = 1, // The dreaded super reactions } \ No newline at end of file diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index fc2eea6e..bcebe5a1 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -59,7 +59,7 @@ pub struct GetChannelMessagesSchema { /// Between 1 and 100, defaults to 50. pub limit: Option, #[serde(flatten)] - pub anchor: ChannelMessagesAnchor, + pub anchor: Option, } #[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)] @@ -74,21 +74,21 @@ impl GetChannelMessagesSchema { pub fn before(anchor: Snowflake) -> Self { Self { limit: None, - anchor: ChannelMessagesAnchor::Before(anchor), + anchor: Some(ChannelMessagesAnchor::Before(anchor)), } } pub fn around(anchor: Snowflake) -> Self { Self { limit: None, - anchor: ChannelMessagesAnchor::Around(anchor), + anchor: Some(ChannelMessagesAnchor::Around(anchor)), } } pub fn after(anchor: Snowflake) -> Self { Self { limit: None, - anchor: ChannelMessagesAnchor::After(anchor), + anchor: Some(ChannelMessagesAnchor::After(anchor)), } } diff --git a/src/types/schema/message.rs b/src/types/schema/message.rs index a7c1eebc..4a7f2ab8 100644 --- a/src/types/schema/message.rs +++ b/src/types/schema/message.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::types::entities::{ AllowedMention, Component, Embed, MessageReference, PartialDiscordFileAttachment, }; -use crate::types::{Attachment, MessageFlags, MessageType, Snowflake}; +use crate::types::{Attachment, MessageFlags, MessageType, ReactionType, Snowflake}; #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)] #[serde(rename_all = "snake_case")] @@ -118,13 +118,21 @@ pub struct MessageAck { #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd)] pub struct MessageModifySchema { - content: Option, - embeds: Option>, - embed: Option, - allowed_mentions: Option, - components: Option>, - flags: Option, - files: Option>, - payload_json: Option, - attachments: Option>, + pub content: Option, + pub embeds: Option>, + pub embed: Option, + pub allowed_mentions: Option, + pub components: Option>, + pub flags: Option, + pub files: Option>, + pub payload_json: Option, + pub attachments: Option>, } + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd)] +pub struct ReactionQuerySchema { + pub after: Option, + pub limit: Option, + #[serde(rename = "type")] + pub reaction_type: Option +} \ No newline at end of file diff --git a/src/types/utils/rights.rs b/src/types/utils/rights.rs index 63978da0..ec1cd9c9 100644 --- a/src/types/utils/rights.rs +++ b/src/types/utils/rights.rs @@ -2,11 +2,11 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use std::num::ParseIntError; +use std::str::FromStr; use bitflags::bitflags; -use serde::{Deserialize, Serialize}; - -#[cfg(feature = "sqlx")] -use sqlx::{{Decode, Encode, MySql}, database::{HasArguments, HasValueRef}, encode::IsNull, error::BoxDynError, mysql::MySqlValueRef}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use crate::types::UserFlags; bitflags! { /// Rights are instance-wide, per-user permissions for everything you may perform on the instance, @@ -18,7 +18,7 @@ bitflags! { /// /// # Reference /// See - #[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)] + #[derive(Debug, Clone, Copy, Eq, PartialEq, chorus_macros::SqlxBitFlags)] pub struct Rights: u64 { /// All rights const OPERATOR = 1 << 0; @@ -132,33 +132,28 @@ bitflags! { } } -#[cfg(feature = "sqlx")] -impl sqlx::Type for Rights { - fn type_info() -> ::TypeInfo { - u64::type_info() - } +impl FromStr for Rights { + type Err = ParseIntError; - fn compatible(ty: &::TypeInfo) -> bool { - u64::compatible(ty) + fn from_str(s: &str) -> Result { + s.parse::().map(Rights::from_bits).map(|f| f.unwrap_or(Rights::empty())) } } -#[cfg(feature = "sqlx")] -impl<'q> Encode<'q, MySql> for Rights { - fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> IsNull { - >::encode_by_ref(&self.0.0, buf) +impl Serialize for Rights { + fn serialize(&self, serializer: S) -> Result { + serializer.serialize_str(&self.bits().to_string()) } } -#[cfg(feature = "sqlx")] -impl<'r> Decode<'r, MySql> for Rights { - fn decode(value: >::ValueRef) -> Result { - let raw = >::decode(value)?; - Ok(Rights::from_bits(raw).unwrap()) +impl<'de> Deserialize<'de> for Rights { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { + let s = String::deserialize(deserializer)?.parse::().map_err(serde::de::Error::custom)?; + + Ok(Rights::from_bits(s).unwrap()) } } - impl Rights { pub fn any(&self, permission: Rights, check_operator: bool) -> bool { (check_operator && self.contains(Rights::OPERATOR)) || self.contains(permission) diff --git a/src/types/utils/snowflake.rs b/src/types/utils/snowflake.rs index 1582085a..341cc50d 100644 --- a/src/types/utils/snowflake.rs +++ b/src/types/utils/snowflake.rs @@ -8,6 +8,9 @@ use std::{ }; use chrono::{DateTime, TimeZone, Utc}; +use sqlx::{MySql, TypeInfo}; +use sqlx::database::HasArguments; +use sqlx::encode::IsNull; #[cfg(feature = "sqlx")] use sqlx::Type; @@ -19,8 +22,6 @@ const EPOCH: i64 = 1420070400000; /// # Reference /// See #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[cfg_attr(feature = "sqlx", derive(Type))] -#[cfg_attr(feature = "sqlx", sqlx(transparent))] pub struct Snowflake(pub u64); impl Snowflake { @@ -102,6 +103,24 @@ impl<'de> serde::Deserialize<'de> for Snowflake { } } +impl sqlx::Type for Snowflake { + fn type_info() -> ::TypeInfo { + >::type_info() + } +} + +impl<'q> sqlx::Encode<'q, sqlx::MySql> for Snowflake { + fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { + >::encode_by_ref(&self.0.to_string(), buf) + } +} + +impl<'d> sqlx::Decode<'d, sqlx::MySql> for Snowflake { + fn decode(value: >::ValueRef) -> Result { + >::decode(value).map(|s| s.parse::().map(Snowflake).unwrap()) + } +} + #[cfg(test)] mod test { use chrono::{DateTime, Utc}; From d8560093f573adb73204e48f87536a1336dc3eee Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 18 Jun 2024 04:48:50 -0400 Subject: [PATCH 063/162] Use chorus_macros from path, since it's there anyway --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a3b0b369..95262816 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ thiserror = "1.0.56" jsonwebtoken = "8.3.0" log = "0.4.20" async-trait = "0.1.77" -chorus-macros = "0.3.0" +chorus-macros = { path = "./chorus-macros" } sqlx = { version = "0.7.3", features = [ "mysql", "sqlite", From 6261cebfdfd57b9d34491e93c679679caa02fb05 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 18 Jun 2024 05:03:55 -0400 Subject: [PATCH 064/162] Fix test --- tests/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/types.rs b/tests/types.rs index 8895bb48..4c727cb8 100644 --- a/tests/types.rs +++ b/tests/types.rs @@ -920,7 +920,7 @@ mod entities { .clone() ); let flags = ApplicationFlags::from_bits(0).unwrap(); - assert!(application.flags() == flags); + assert!(application == flags); } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] From dfffcf431344f2db3830e3e71753a762862ed9a7 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 18 Jun 2024 05:08:36 -0400 Subject: [PATCH 065/162] Add forgotten feature locks --- src/types/utils/snowflake.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/types/utils/snowflake.rs b/src/types/utils/snowflake.rs index 341cc50d..87a5586e 100644 --- a/src/types/utils/snowflake.rs +++ b/src/types/utils/snowflake.rs @@ -103,18 +103,21 @@ impl<'de> serde::Deserialize<'de> for Snowflake { } } +#[cfg(feature = "sqlx")] impl sqlx::Type for Snowflake { fn type_info() -> ::TypeInfo { >::type_info() } } +#[cfg(feature = "sqlx")] impl<'q> sqlx::Encode<'q, sqlx::MySql> for Snowflake { fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { >::encode_by_ref(&self.0.to_string(), buf) } } +#[cfg(feature = "sqlx")] impl<'d> sqlx::Decode<'d, sqlx::MySql> for Snowflake { fn decode(value: >::ValueRef) -> Result { >::decode(value).map(|s| s.parse::().map(Snowflake).unwrap()) From 3810170400877144eadf55a0b92f40e6f88756c7 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 18 Jun 2024 05:14:28 -0400 Subject: [PATCH 066/162] Remove unused imports, feature locks in macro --- src/types/entities/message.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index e31b7be0..d776337c 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -6,10 +6,6 @@ use bitflags::bitflags; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use sqlx::database::{HasArguments, HasValueRef}; -use sqlx::encode::IsNull; -use sqlx::error::BoxDynError; -use sqlx::{Encode, MySql}; use crate::types::{ Shared, From 06b4dc3abdbc24d21b1738202fc716d0acd17216 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 18 Jun 2024 05:19:51 -0400 Subject: [PATCH 067/162] forgot a file :( --- src/types/utils/snowflake.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/types/utils/snowflake.rs b/src/types/utils/snowflake.rs index 87a5586e..a021f906 100644 --- a/src/types/utils/snowflake.rs +++ b/src/types/utils/snowflake.rs @@ -8,11 +8,6 @@ use std::{ }; use chrono::{DateTime, TimeZone, Utc}; -use sqlx::{MySql, TypeInfo}; -use sqlx::database::HasArguments; -use sqlx::encode::IsNull; -#[cfg(feature = "sqlx")] -use sqlx::Type; /// 2015-01-01 const EPOCH: i64 = 1420070400000; From 77004abcfa55e604dd2274ef65564370923e5778 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 18 Jun 2024 05:24:42 -0400 Subject: [PATCH 068/162] Feature lock the macro --- src/types/utils/rights.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/types/utils/rights.rs b/src/types/utils/rights.rs index ec1cd9c9..e7de4fc0 100644 --- a/src/types/utils/rights.rs +++ b/src/types/utils/rights.rs @@ -18,7 +18,8 @@ bitflags! { /// /// # Reference /// See - #[derive(Debug, Clone, Copy, Eq, PartialEq, chorus_macros::SqlxBitFlags)] + #[derive(Debug, Clone, Copy, Eq, PartialEq)] + #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] pub struct Rights: u64 { /// All rights const OPERATOR = 1 << 0; From abc4608be5be5fd5c213e924e406eb3774b90b36 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 18 Jun 2024 05:32:27 -0400 Subject: [PATCH 069/162] Dirty hack --- src/types/entities/invite.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/types/entities/invite.rs b/src/types/entities/invite.rs index bb1d4001..239bdb22 100644 --- a/src/types/entities/invite.rs +++ b/src/types/entities/invite.rs @@ -86,13 +86,7 @@ impl From for InviteGuild { premium_subscription_count: value.premium_subscription_count, nsfw_deprecated: None, nsfw_level: value.nsfw_level.unwrap_or_default(), - welcome_screen: value.welcome_screen.0.map(|obj| { - #[cfg(feature = "sqlx")] - let res = obj; - #[cfg(not(feature = "sqlx"))] - let res = obj; - res - }), + welcome_screen: (*value.welcome_screen).to_owned(), // Dirty hack to get around feature locks making different types } } } From c27bc8d5758403a55205f82f062b4c8868c06241 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 18 Jun 2024 05:34:03 -0400 Subject: [PATCH 070/162] Fix test I feel silly. --- tests/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/types.rs b/tests/types.rs index 4c727cb8..48b132cd 100644 --- a/tests/types.rs +++ b/tests/types.rs @@ -920,7 +920,7 @@ mod entities { .clone() ); let flags = ApplicationFlags::from_bits(0).unwrap(); - assert!(application == flags); + assert!(application.flags == flags); } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] From d7de1d2fb7edd699a136ba01a9e494ff149e820b Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 18 Jun 2024 05:46:27 -0400 Subject: [PATCH 071/162] Fix compilation for real, no dirty hack --- src/types/entities/invite.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/types/entities/invite.rs b/src/types/entities/invite.rs index 239bdb22..388cc321 100644 --- a/src/types/entities/invite.rs +++ b/src/types/entities/invite.rs @@ -86,7 +86,10 @@ impl From for InviteGuild { premium_subscription_count: value.premium_subscription_count, nsfw_deprecated: None, nsfw_level: value.nsfw_level.unwrap_or_default(), - welcome_screen: (*value.welcome_screen).to_owned(), // Dirty hack to get around feature locks making different types + #[cfg(feature = "sqlx")] + welcome_screen: value.welcome_screen.0, + #[cfg(not(feature = "sqlx"))] + welcome_screen: value.welcome_screen, } } } From c9a36ce7254390542bbe8a1cc62090e03ad48f30 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 18 Jun 2024 08:46:07 -0400 Subject: [PATCH 072/162] Maybe fix tests, make UserFlags able to be deserialized from String or u64 --- src/types/entities/user.rs | 5 +++-- src/types/utils/serde.rs | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index ddbdc22c..d547be38 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -155,8 +155,9 @@ impl Serialize for UserFlags { impl<'de> Deserialize<'de> for UserFlags { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { - let s = String::deserialize(deserializer)?.parse::().map_err(serde::de::Error::custom)?; - + // let s = String::deserialize(deserializer)?.parse::().map_err(serde::de::Error::custom)?; + let s = crate::types::serde::string_or_u64(deserializer)?; + Ok(UserFlags::from_bits(s).unwrap()) } } diff --git a/src/types/utils/serde.rs b/src/types/utils/serde.rs index 85840045..544a3052 100644 --- a/src/types/utils/serde.rs +++ b/src/types/utils/serde.rs @@ -1,6 +1,7 @@ use core::fmt; use chrono::{LocalResult, NaiveDateTime}; -use serde::de; +use serde::{de, Deserialize, Deserializer}; +use serde::de::Error; #[doc(hidden)] #[derive(Debug)] @@ -259,4 +260,19 @@ pub(crate) fn serde_from(me: LocalResult, _ts: &V) -> Result } LocalResult::Single(val) => Ok(val), } +} + +#[derive(serde::Deserialize, serde::Serialize)] +#[serde(untagged)] +enum StringOrU64 { + String(String), + U64(u64), +} + +pub fn string_or_u64<'de, D>(d: D) -> Result +where D: Deserializer<'de> { + match StringOrU64::deserialize(d)? { + StringOrU64::String(s) => s.parse::().map_err(D::Error::custom), + StringOrU64::U64(u) => Ok(u) + } } \ No newline at end of file From e553d10f25d2e9febe8b8427883167fa3fa1b54f Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 18 Jun 2024 10:04:00 -0400 Subject: [PATCH 073/162] Add new SerdeBitFlags derive macro, to help reduce repetitive code --- chorus-macros/src/lib.rs | 37 ++++++++++++++++++++++ src/types/entities/application.rs | 2 +- src/types/entities/guild.rs | 2 +- src/types/entities/message.rs | 2 +- src/types/entities/role.rs | 2 +- src/types/entities/user.rs | 25 +-------------- src/types/events/voice_gateway/speaking.rs | 2 +- src/types/schema/channel.rs | 29 +---------------- src/types/utils/rights.rs | 24 +------------- 9 files changed, 45 insertions(+), 80 deletions(-) diff --git a/chorus-macros/src/lib.rs b/chorus-macros/src/lib.rs index 9f56a53c..4102039a 100644 --- a/chorus-macros/src/lib.rs +++ b/chorus-macros/src/lib.rs @@ -156,6 +156,7 @@ pub fn composite_derive(input: TokenStream) -> TokenStream { } } + #[proc_macro_derive(SqlxBitFlags)] pub fn sqlx_bitflag_derive(input: TokenStream) -> TokenStream { let ast: syn::DeriveInput = syn::parse(input).unwrap(); @@ -163,18 +164,21 @@ pub fn sqlx_bitflag_derive(input: TokenStream) -> TokenStream { let name = &ast.ident; quote!{ + #[cfg(feature = "sqlx")] impl sqlx::Type for #name { fn type_info() -> sqlx::mysql::MySqlTypeInfo { u64::type_info() } } + #[cfg(feature = "sqlx")] impl<'q> sqlx::Encode<'q, sqlx::MySql> for #name { fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { u64::encode_by_ref(&self.bits(), buf) } } + #[cfg(feature = "sqlx")] impl<'q> sqlx::Decode<'q, sqlx::MySql> for #name { fn decode(value: >::ValueRef) -> Result { u64::decode(value).map(|d| #name::from_bits(d).unwrap()) @@ -182,4 +186,37 @@ pub fn sqlx_bitflag_derive(input: TokenStream) -> TokenStream { } } .into() +} + +#[proc_macro_derive(SerdeBitFlags)] +pub fn serde_bitflag_derive(input: TokenStream) -> TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + + let name = &ast.ident; + + quote! { + impl std::str::FromStr for #name { + type Err = std::num::ParseIntError; + + fn from_str(s: &str) -> Result<#name, Self::Err> { + s.parse::().map(#name::from_bits).map(|f| f.unwrap_or(#name::empty())) + } + } + + impl serde::Serialize for #name { + fn serialize(&self, serializer: S) -> Result { + serializer.serialize_str(&self.bits().to_string()) + } + } + + impl<'de> serde::Deserialize<'de> for #name { + fn deserialize(deserializer: D) -> Result<#name, D::Error> where D: serde::de::Deserializer<'de> + Sized { + // let s = String::deserialize(deserializer)?.parse::().map_err(serde::de::Error::custom)?; + let s = crate::types::serde::string_or_u64(deserializer)?; + + Ok(Self::from_bits(s).unwrap()) + } + } + } + .into() } \ No newline at end of file diff --git a/src/types/entities/application.rs b/src/types/entities/application.rs index f57a71f8..ac4cb971 100644 --- a/src/types/entities/application.rs +++ b/src/types/entities/application.rs @@ -102,7 +102,7 @@ pub struct InstallParams { } bitflags! { - #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, chorus_macros::SerdeBitFlags)] #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] /// # Reference /// See diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index e3c8a7ec..db207fca 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -422,7 +422,7 @@ pub enum PremiumTier { } bitflags! { - #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, chorus_macros::SerdeBitFlags)] #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] /// # Reference /// See diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index d776337c..34a7b9bf 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -379,7 +379,7 @@ pub enum MessageType { } bitflags! { - #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, chorus_macros::SerdeBitFlags)] #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] /// # Reference /// See diff --git a/src/types/entities/role.rs b/src/types/entities/role.rs index 712c9abf..8a2c5135 100644 --- a/src/types/entities/role.rs +++ b/src/types/entities/role.rs @@ -71,7 +71,7 @@ pub struct RoleTags { } bitflags! { - #[derive(Debug, Default, Clone, Hash, Serialize, Deserialize, PartialEq, Eq)] + #[derive(Debug, Default, Clone, Hash, PartialEq, Eq, chorus_macros::SerdeBitFlags)] #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] /// Permissions limit what users of certain roles can do on a Guild to Guild basis. /// diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index d547be38..70669d03 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -113,7 +113,7 @@ impl From for PublicUser { const CUSTOM_USER_FLAG_OFFSET: u64 = 1 << 32; bitflags::bitflags! { - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, chorus_macros::SerdeBitFlags)] #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] pub struct UserFlags: u64 { const DISCORD_EMPLOYEE = 1 << 0; @@ -139,29 +139,6 @@ bitflags::bitflags! { } } -impl FromStr for UserFlags { - type Err = ParseIntError; - - fn from_str(s: &str) -> Result { - s.parse::().map(UserFlags::from_bits).map(|f| f.unwrap_or(UserFlags::empty())) - } -} - -impl Serialize for UserFlags { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str(&self.bits().to_string()) - } -} - -impl<'de> Deserialize<'de> for UserFlags { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { - // let s = String::deserialize(deserializer)?.parse::().map_err(serde::de::Error::custom)?; - let s = crate::types::serde::string_or_u64(deserializer)?; - - Ok(UserFlags::from_bits(s).unwrap()) - } -} - #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct UserProfileMetadata { pub guild_id: Option, diff --git a/src/types/events/voice_gateway/speaking.rs b/src/types/events/voice_gateway/speaking.rs index 64cf2e7a..fea29adb 100644 --- a/src/types/events/voice_gateway/speaking.rs +++ b/src/types/events/voice_gateway/speaking.rs @@ -32,7 +32,7 @@ bitflags! { /// Bitflags of speaking types; /// /// See - #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Serialize, Deserialize)] + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, chorus_macros::SerdeBitFlags)] pub struct SpeakingBitflags: u8 { /// Whether we'll be transmitting normal voice audio const MICROPHONE = 1 << 0; diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index bcebe5a1..9ae64c61 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -131,7 +131,7 @@ impl Default for CreateChannelInviteSchema { } bitflags! { - #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, chorus_macros::SerdeBitFlags)] #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] pub struct InviteFlags: u64 { const GUEST = 1 << 0; @@ -139,33 +139,6 @@ bitflags! { } } -impl Serialize for InviteFlags { - fn serialize(&self, serializer: S) -> Result { - self.bits().to_string().serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for InviteFlags { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { - struct FlagsVisitor; - - impl<'de> Visitor<'de> for FlagsVisitor - { - type Value = InviteFlags; - - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("a raw u64 value of flags") - } - - fn visit_u64(self, v: u64) -> Result { - InviteFlags::from_bits(v).ok_or(serde::de::Error::custom(Error::InvalidFlags(v))) - } - } - - deserializer.deserialize_u64(FlagsVisitor) - } -} - #[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] diff --git a/src/types/utils/rights.rs b/src/types/utils/rights.rs index e7de4fc0..598f782c 100644 --- a/src/types/utils/rights.rs +++ b/src/types/utils/rights.rs @@ -18,7 +18,7 @@ bitflags! { /// /// # Reference /// See - #[derive(Debug, Clone, Copy, Eq, PartialEq)] + #[derive(Debug, Clone, Copy, Eq, PartialEq, chorus_macros::SerdeBitFlags)] #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] pub struct Rights: u64 { /// All rights @@ -133,28 +133,6 @@ bitflags! { } } -impl FromStr for Rights { - type Err = ParseIntError; - - fn from_str(s: &str) -> Result { - s.parse::().map(Rights::from_bits).map(|f| f.unwrap_or(Rights::empty())) - } -} - -impl Serialize for Rights { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str(&self.bits().to_string()) - } -} - -impl<'de> Deserialize<'de> for Rights { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { - let s = String::deserialize(deserializer)?.parse::().map_err(serde::de::Error::custom)?; - - Ok(Rights::from_bits(s).unwrap()) - } -} - impl Rights { pub fn any(&self, permission: Rights, check_operator: bool) -> bool { (check_operator && self.contains(Rights::OPERATOR)) || self.contains(permission) From a8b7d9dfb33d1955481497d70ace39ace68c3a76 Mon Sep 17 00:00:00 2001 From: Quat3rnion Date: Tue, 18 Jun 2024 10:07:56 -0400 Subject: [PATCH 074/162] u8 -> u64 --- src/types/events/voice_gateway/speaking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/events/voice_gateway/speaking.rs b/src/types/events/voice_gateway/speaking.rs index fea29adb..7a505fde 100644 --- a/src/types/events/voice_gateway/speaking.rs +++ b/src/types/events/voice_gateway/speaking.rs @@ -33,7 +33,7 @@ bitflags! { /// /// See #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, chorus_macros::SerdeBitFlags)] - pub struct SpeakingBitflags: u8 { + pub struct SpeakingBitflags: u64 { /// Whether we'll be transmitting normal voice audio const MICROPHONE = 1 << 0; /// Whether we'll be transmitting context audio for video, no speaking indicator From 4430a7c4e6dfd4d7154d318c10d061ef97d6a116 Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Tue, 18 Jun 2024 17:18:20 +0200 Subject: [PATCH 075/162] Fix deserialization error w/ guild features list --- src/types/entities/guild.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index db207fca..866b1729 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -59,6 +59,7 @@ pub struct Guild { pub emojis: Vec>, pub explicit_content_filter: Option, //#[cfg_attr(feature = "sqlx", sqlx(try_from = "String"))] + #[serde(default)] pub features: GuildFeaturesList, pub icon: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] From 8d56259eac0ba0f01c515b9ae4d1ee05eecbb860 Mon Sep 17 00:00:00 2001 From: kozabrada123 Date: Tue, 18 Jun 2024 17:35:39 +0200 Subject: [PATCH 076/162] chorus macros 0.4.0 --- Cargo.lock | 4 +--- Cargo.toml | 2 +- chorus-macros/Cargo.lock | 2 +- chorus-macros/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 61d67fb7..01b7ef93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -264,9 +264,7 @@ dependencies = [ [[package]] name = "chorus-macros" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de4221700bc486c6e6bc261fdea478936d33067a06325895f5d2a8cde5917272" +version = "0.4.0" dependencies = [ "async-trait", "quote", diff --git a/Cargo.toml b/Cargo.toml index 95262816..71cfad9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ thiserror = "1.0.56" jsonwebtoken = "8.3.0" log = "0.4.20" async-trait = "0.1.77" -chorus-macros = { path = "./chorus-macros" } +chorus-macros = { path = "./chorus-macros", version = "0.4.0" } # Note: version here is used when releasing. Make sure to update and republish when code in macros is changed! sqlx = { version = "0.7.3", features = [ "mysql", "sqlite", diff --git a/chorus-macros/Cargo.lock b/chorus-macros/Cargo.lock index 64632bc3..a3eedd4a 100644 --- a/chorus-macros/Cargo.lock +++ b/chorus-macros/Cargo.lock @@ -15,7 +15,7 @@ dependencies = [ [[package]] name = "chorus-macros" -version = "0.3.0" +version = "0.4.0" dependencies = [ "async-trait", "quote", diff --git a/chorus-macros/Cargo.toml b/chorus-macros/Cargo.toml index df5bc7f6..c81cc90d 100644 --- a/chorus-macros/Cargo.toml +++ b/chorus-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chorus-macros" -version = "0.3.0" +version = "0.4.0" edition = "2021" license = "MPL-2.0" description = "Macros for the chorus crate." From b3e62b2c3379272ac0e417038ce86f27306cf7d4 Mon Sep 17 00:00:00 2001 From: kozabrada123 Date: Tue, 18 Jun 2024 17:48:57 +0200 Subject: [PATCH 077/162] always update to latest release of macros --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 71cfad9d..81acc51c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ thiserror = "1.0.56" jsonwebtoken = "8.3.0" log = "0.4.20" async-trait = "0.1.77" -chorus-macros = { path = "./chorus-macros", version = "0.4.0" } # Note: version here is used when releasing. Make sure to update and republish when code in macros is changed! +chorus-macros = { path = "./chorus-macros", version = "0" } # Note: version here is used when releasing. This will use the latest release. Make sure to republish the crate when code in macros is changed! sqlx = { version = "0.7.3", features = [ "mysql", "sqlite", From b4a8082f29c3b054bd8f4302a336db59fc1c810a Mon Sep 17 00:00:00 2001 From: Quat3rnion <81202811+Quat3rnion@users.noreply.github.com> Date: Wed, 19 Jun 2024 13:59:39 -0400 Subject: [PATCH 078/162] Update and add some types in support of the backend (#507) --- src/types/entities/channel.rs | 29 ++++++++++++++++++++++------- src/types/entities/role.rs | 2 +- src/types/entities/webhook.rs | 16 +++++++++++++--- src/types/schema/channel.rs | 12 ++++++++++++ tests/channels.rs | 14 ++++---------- 5 files changed, 52 insertions(+), 21 deletions(-) diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 782b6a60..c1219ad1 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -8,8 +8,8 @@ use serde_aux::prelude::deserialize_string_from_number; use serde_repr::{Deserialize_repr, Serialize_repr}; use std::fmt::Debug; -use crate::types::Shared; use crate::types::{ + PermissionFlags, Shared, entities::{GuildMember, User}, utils::Snowflake, }; @@ -148,14 +148,20 @@ pub struct Tag { pub struct PermissionOverwrite { pub id: Snowflake, #[serde(rename = "type")] - #[serde(deserialize_with = "deserialize_string_from_number")] - pub overwrite_type: String, + pub overwrite_type: PermissionOverwriteType, #[serde(default)] - #[serde(deserialize_with = "deserialize_string_from_number")] - pub allow: String, + pub allow: PermissionFlags, #[serde(default)] - #[serde(deserialize_with = "deserialize_string_from_number")] - pub deny: String, + pub deny: PermissionFlags, +} + + +#[derive(Debug, Serialize_repr, Deserialize_repr, Clone, PartialEq, Eq, PartialOrd)] +#[repr(u8)] +/// # Reference +pub enum PermissionOverwriteType { + Role = 0, + Member = 1, } #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] @@ -260,3 +266,12 @@ pub enum ChannelType { // TODO: Couldn't find reference Unhandled = 255, } + + +/// # Reference +/// See +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct FollowedChannel { + pub channel_id: Snowflake, + pub webhook_id: Snowflake +} \ No newline at end of file diff --git a/src/types/entities/role.rs b/src/types/entities/role.rs index 8a2c5135..7e804f5f 100644 --- a/src/types/entities/role.rs +++ b/src/types/entities/role.rs @@ -71,7 +71,7 @@ pub struct RoleTags { } bitflags! { - #[derive(Debug, Default, Clone, Hash, PartialEq, Eq, chorus_macros::SerdeBitFlags)] + #[derive(Debug, Default, Clone, Hash, PartialEq, Eq, PartialOrd, chorus_macros::SerdeBitFlags)] #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] /// Permissions limit what users of certain roles can do on a Guild to Guild basis. /// diff --git a/src/types/entities/webhook.rs b/src/types/entities/webhook.rs index 3fcc43bd..aea9f412 100644 --- a/src/types/entities/webhook.rs +++ b/src/types/entities/webhook.rs @@ -32,13 +32,13 @@ use crate::types::{ pub struct Webhook { pub id: Snowflake, #[serde(rename = "type")] - pub webhook_type: i32, + pub webhook_type: WebhookType, pub name: String, pub avatar: String, pub token: String, - pub guild_id: Snowflake, + pub guild_id: Snowflake, pub channel_id: Snowflake, - pub application_id: Snowflake, + pub application_id: Option, #[serde(skip_serializing_if = "Option::is_none")] #[cfg_attr(feature = "sqlx", sqlx(skip))] pub user: Option>, @@ -48,3 +48,13 @@ pub struct Webhook { #[serde(skip_serializing_if = "Option::is_none")] pub url: Option, } + +#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy)] +#[repr(u8)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +pub enum WebhookType { + #[default] + Incoming = 1, + ChannelFollower = 2, + Application = 3, +} \ No newline at end of file diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 9ae64c61..33df3ffd 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -177,3 +177,15 @@ pub struct ModifyChannelPositionsSchema { pub lock_permissions: Option, pub parent_id: Option, } + +/// See +#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq)] +pub struct AddFollowingChannelSchema { + pub webhook_channel_id: Snowflake, +} + +#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq)] +pub struct CreateWebhookSchema { + pub name: String, + pub avatar: Option, +} \ No newline at end of file diff --git a/tests/channels.rs b/tests/channels.rs index 14359d2c..e00744a4 100644 --- a/tests/channels.rs +++ b/tests/channels.rs @@ -2,10 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use chorus::types::{ - self, Channel, GetChannelMessagesSchema, MessageSendSchema, PermissionFlags, - PermissionOverwrite, PrivateChannelCreateSchema, RelationshipType, Snowflake, -}; +use chorus::types::{self, Channel, GetChannelMessagesSchema, MessageSendSchema, PermissionFlags, PermissionOverwrite, PermissionOverwriteType, PrivateChannelCreateSchema, RelationshipType, Snowflake}; mod common; @@ -69,16 +66,13 @@ async fn modify_channel() { .unwrap(); assert_eq!(modified_channel.name, Some(CHANNEL_NAME.to_string())); - let permission_override = PermissionFlags::from_vec(Vec::from([ - PermissionFlags::MANAGE_CHANNELS, - PermissionFlags::MANAGE_MESSAGES, - ])); + let permission_override = PermissionFlags::MANAGE_CHANNELS | PermissionFlags::MANAGE_MESSAGES; let user_id: types::Snowflake = bundle.user.object.read().unwrap().id; let permission_override = PermissionOverwrite { id: user_id, - overwrite_type: "1".to_string(), + overwrite_type: PermissionOverwriteType::Member, allow: permission_override, - deny: "0".to_string(), + deny: PermissionFlags::empty(), }; let channel_id: Snowflake = bundle.channel.read().unwrap().id; Channel::modify_permissions( From 89333d635398558929dfe60013968117d9745b80 Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Sun, 23 Jun 2024 17:23:13 +0200 Subject: [PATCH 079/162] Implement gateway options, zlib-stream compression (#508) * feat: add GatewayOptions * feat: implement zlib-stream compression This also changes how gateway messages work. Now each gateway backend converts its message into an intermediary RawGatewayMessage, from which we inflate and parse GatewayMessages. Thanks to ByteAlex and their zlib-stream-rs crate, which helped me understand how to parse a compressed websocket stream --- .github/workflows/build_and_test.yml | 2 +- Cargo.lock | 31 +++++++ Cargo.toml | 4 +- examples/gateway_observers.rs | 12 ++- examples/gateway_simple.rs | 12 ++- src/api/users/users.rs | 15 ++-- src/gateway/backends/tungstenite.rs | 21 ++++- src/gateway/backends/wasm.rs | 20 ++++- src/gateway/gateway.rs | 115 +++++++++++++++++++++----- src/gateway/message.rs | 69 +++++++++++++++- src/gateway/mod.rs | 2 + src/gateway/options.rs | 118 +++++++++++++++++++++++++++ src/instance.rs | 16 +++- src/types/entities/channel.rs | 3 +- src/types/entities/message.rs | 2 +- src/types/entities/user.rs | 4 +- src/types/events/presence.rs | 2 + src/types/events/ready.rs | 42 ++++++---- src/types/schema/channel.rs | 7 +- src/types/schema/user.rs | 77 +++++++++++++++-- src/voice/gateway/backends/wasm.rs | 1 + src/voice/gateway/gateway.rs | 2 +- tests/common/mod.rs | 10 ++- tests/gateway.rs | 6 +- 24 files changed, 521 insertions(+), 72 deletions(-) create mode 100644 src/gateway/options.rs diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index d0ddba58..d37491ae 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -124,7 +124,7 @@ jobs: cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force GECKODRIVER=$(which geckodriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" wasm-chrome: - runs-on: macos-latest + runs-on: ubuntu-latest timeout-minutes: 30 steps: - uses: actions/checkout@v4 diff --git a/Cargo.lock b/Cargo.lock index 01b7ef93..bb74a326 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -231,6 +231,7 @@ dependencies = [ "crypto_secretbox", "custom_error", "discortp", + "flate2", "futures-util", "getrandom", "hostname", @@ -250,6 +251,7 @@ dependencies = [ "serde_json", "serde_repr", "serde_with", + "simple_logger", "sqlx", "thiserror", "tokio", @@ -353,6 +355,15 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-queue" version = "0.3.11" @@ -553,6 +564,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "flume" version = "0.11.0" @@ -2124,6 +2145,16 @@ dependencies = [ "time", ] +[[package]] +name = "simple_logger" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c5dfa5e08767553704aa0ffd9d9794d527103c736aba9854773851fd7497eb" +dependencies = [ + "log", + "windows-sys 0.48.0", +] + [[package]] name = "slab" version = "0.4.9" diff --git a/Cargo.toml b/Cargo.toml index 81acc51c..a1ab80df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ default = ["client", "rt-multi-thread"] backend = ["poem", "sqlx"] rt-multi-thread = ["tokio/rt-multi-thread"] rt = ["tokio/rt"] -client = [] +client = ["flate2"] voice = ["voice_udp", "voice_gateway"] voice_udp = ["dep:discortp", "dep:crypto_secretbox"] voice_gateway = [] @@ -56,6 +56,7 @@ sqlx = { version = "0.7.3", features = [ discortp = { version = "0.5.0", optional = true, features = ["rtp", "discord", "demux"] } crypto_secretbox = { version = "0.1.1", optional = true } rand = "0.8.5" +flate2 = { version = "1.0.30", optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] rustls = "0.21.10" @@ -78,3 +79,4 @@ wasmtimer = "0.2.0" lazy_static = "1.4.0" wasm-bindgen-test = "0.3.42" wasm-bindgen = "0.2.92" +simple_logger = { version = "5.0.0", default-features=false } diff --git a/examples/gateway_observers.rs b/examples/gateway_observers.rs index 0f15759b..17390b6d 100644 --- a/examples/gateway_observers.rs +++ b/examples/gateway_observers.rs @@ -3,6 +3,8 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. // This example showcase how to properly use gateway observers. +// (This assumes you have a manually created gateway, if you created +// a ChorusUser by e.g. logging in, you can access the gateway with user.gateway) // // To properly run it, you will need to change the token below. @@ -12,7 +14,7 @@ const TOKEN: &str = ""; const GATEWAY_URL: &str = "wss://gateway.old.server.spacebar.chat/"; use async_trait::async_trait; -use chorus::gateway::Gateway; +use chorus::gateway::{Gateway, GatewayOptions}; use chorus::{ self, gateway::Observer, @@ -47,8 +49,14 @@ impl Observer for ExampleObserver { async fn main() { let gateway_websocket_url = GATEWAY_URL.to_string(); + // These options specify the encoding format, compression, etc + // + // For most cases the defaults should work, though some implementations + // might only support some formats or not support compression + let options = GatewayOptions::default(); + // Initiate the gateway connection - let gateway = Gateway::spawn(gateway_websocket_url).await.unwrap(); + let gateway = Gateway::spawn(gateway_websocket_url, options).await.unwrap(); // Create an instance of our observer let observer = ExampleObserver {}; diff --git a/examples/gateway_simple.rs b/examples/gateway_simple.rs index e8ff59a0..7f662874 100644 --- a/examples/gateway_simple.rs +++ b/examples/gateway_simple.rs @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. // This example showcases how to initiate a gateway connection manually -// (e. g. not through ChorusUser) +// (e. g. not through ChorusUser or Instance) // // To properly run it, you will need to modify the token below. @@ -14,7 +14,7 @@ const GATEWAY_URL: &str = "wss://gateway.old.server.spacebar.chat/"; use std::time::Duration; -use chorus::gateway::Gateway; +use chorus::gateway::{Gateway, GatewayOptions}; use chorus::{self, types::GatewayIdentifyPayload}; #[cfg(not(target_arch = "wasm32"))] @@ -26,9 +26,15 @@ use wasmtimer::tokio::sleep; #[tokio::main(flavor = "current_thread")] async fn main() { let gateway_websocket_url = GATEWAY_URL.to_string(); + + // These options specify the encoding format, compression, etc + // + // For most cases the defaults should work, though some implementations + // might only support some formats or not support compression + let options = GatewayOptions::default(); // Initiate the gateway connection, starting a listener in one thread and a heartbeat handler in another - let gateway = Gateway::spawn(gateway_websocket_url).await.unwrap(); + let gateway = Gateway::spawn(gateway_websocket_url, options).await.unwrap(); // At this point, we are connected to the server and are sending heartbeats, however we still haven't authenticated diff --git a/src/api/users/users.rs b/src/api/users/users.rs index 61017132..4f6ef579 100644 --- a/src/api/users/users.rs +++ b/src/api/users/users.rs @@ -32,7 +32,7 @@ impl ChorusUser { /// # Notes /// This function is a wrapper around [`User::get_settings`]. pub async fn get_settings(&mut self) -> ChorusResult { - User::get_settings(self).await + User::get_settings(self).await } /// Modifies the current user's representation. (See [`User`]) @@ -40,12 +40,18 @@ impl ChorusUser { /// # Reference /// See pub async fn modify(&mut self, modify_schema: UserModifySchema) -> ChorusResult { - if modify_schema.new_password.is_some() + + // See , note 1 + let requires_current_password = modify_schema.username.is_some() + || modify_schema.discriminator.is_some() || modify_schema.email.is_some() - || modify_schema.code.is_some() - { + || modify_schema.date_of_birth.is_some() + || modify_schema.new_password.is_some(); + + if requires_current_password && modify_schema.current_password.is_none() { return Err(ChorusError::PasswordRequired); } + let request = Client::new() .patch(format!( "{}/users/@me", @@ -132,4 +138,3 @@ impl User { } } } - diff --git a/src/gateway/backends/tungstenite.rs b/src/gateway/backends/tungstenite.rs index 6c7ac391..f4425cda 100644 --- a/src/gateway/backends/tungstenite.rs +++ b/src/gateway/backends/tungstenite.rs @@ -12,7 +12,7 @@ use tokio_tungstenite::{ connect_async_tls_with_config, tungstenite, Connector, MaybeTlsStream, WebSocketStream, }; -use crate::gateway::GatewayMessage; +use crate::gateway::{GatewayMessage, RawGatewayMessage}; #[derive(Debug, Clone)] pub struct TungsteniteBackend; @@ -80,3 +80,22 @@ impl From for GatewayMessage { Self(value.to_string()) } } + +impl From for tungstenite::Message { + fn from(message: RawGatewayMessage) -> Self { + match message { + RawGatewayMessage::Text(text) => tungstenite::Message::Text(text), + RawGatewayMessage::Bytes(bytes) => tungstenite::Message::Binary(bytes), + } + } +} + +impl From for RawGatewayMessage { + fn from(value: tungstenite::Message) -> Self { + match value { + tungstenite::Message::Binary(bytes) => RawGatewayMessage::Bytes(bytes), + tungstenite::Message::Text(text) => RawGatewayMessage::Text(text), + _ => RawGatewayMessage::Text(value.to_string()), + } + } +} diff --git a/src/gateway/backends/wasm.rs b/src/gateway/backends/wasm.rs index a40321da..e0fd9c68 100644 --- a/src/gateway/backends/wasm.rs +++ b/src/gateway/backends/wasm.rs @@ -9,7 +9,7 @@ use futures_util::{ use ws_stream_wasm::*; -use crate::gateway::GatewayMessage; +use crate::gateway::{GatewayMessage, RawGatewayMessage}; #[derive(Debug, Clone)] pub struct WasmBackend; @@ -46,3 +46,21 @@ impl From for GatewayMessage { } } } + +impl From for WsMessage { + fn from(message: RawGatewayMessage) -> Self { + match message { + RawGatewayMessage::Text(text) => WsMessage::Text(text), + RawGatewayMessage::Bytes(bytes) => WsMessage::Binary(bytes), + } + } +} + +impl From for RawGatewayMessage { + fn from(value: WsMessage) -> Self { + match value { + WsMessage::Binary(bytes) => RawGatewayMessage::Bytes(bytes), + WsMessage::Text(text) => RawGatewayMessage::Text(text), + } + } +} diff --git a/src/gateway/gateway.rs b/src/gateway/gateway.rs index 34808c93..ec42b300 100644 --- a/src/gateway/gateway.rs +++ b/src/gateway/gateway.rs @@ -4,6 +4,7 @@ use std::time::Duration; +use flate2::Decompress; use futures_util::{SinkExt, StreamExt}; use log::*; #[cfg(not(target_arch = "wasm32"))] @@ -19,6 +20,9 @@ use crate::types::{ WebSocketEvent, }; +/// Tells us we have received enough of the buffer to decompress it +const ZLIB_SUFFIX: [u8; 4] = [0, 0, 255, 255]; + #[derive(Debug)] pub struct Gateway { events: Arc>, @@ -28,21 +32,36 @@ pub struct Gateway { kill_send: tokio::sync::broadcast::Sender<()>, kill_receive: tokio::sync::broadcast::Receiver<()>, store: Arc>>>>, + /// Url which was used to initialize the gateway url: String, + /// Options which were used to initialize the gateway + options: GatewayOptions, + zlib_inflate: Option, + zlib_buffer: Option>, } impl Gateway { #[allow(clippy::new_ret_no_self)] - pub async fn spawn(websocket_url: String) -> Result { - let (websocket_send, mut websocket_receive) = - match WebSocketBackend::connect(&websocket_url).await { - Ok(streams) => streams, - Err(e) => { - return Err(GatewayError::CannotConnect { - error: format!("{:?}", e), - }) - } - }; + /// Creates / opens a new gateway connection. + /// + /// # Note + /// The websocket url should begin with the prefix wss:// or ws:// (for unsecure connections) + pub async fn spawn( + websocket_url: String, + options: GatewayOptions, + ) -> Result { + let url = options.add_to_url(websocket_url); + + debug!("GW: Connecting to {}", url); + + let (websocket_send, mut websocket_receive) = match WebSocketBackend::connect(&url).await { + Ok(streams) => streams, + Err(e) => { + return Err(GatewayError::CannotConnect { + error: format!("{:?}", e), + }); + } + }; let shared_websocket_send = Arc::new(Mutex::new(websocket_send)); @@ -52,10 +71,32 @@ impl Gateway { // Wait for the first hello and then spawn both tasks so we avoid nested tasks // This automatically spawns the heartbeat task, but from the main thread #[cfg(not(target_arch = "wasm32"))] - let msg: GatewayMessage = websocket_receive.next().await.unwrap().unwrap().into(); + let received: RawGatewayMessage = websocket_receive.next().await.unwrap().unwrap().into(); #[cfg(target_arch = "wasm32")] - let msg: GatewayMessage = websocket_receive.next().await.unwrap().into(); - let gateway_payload: types::GatewayReceivePayload = serde_json::from_str(&msg.0).unwrap(); + let received: RawGatewayMessage = websocket_receive.next().await.unwrap().into(); + + let message: GatewayMessage; + + let zlib_buffer; + let zlib_inflate; + + match options.transport_compression { + GatewayTransportCompression::None => { + zlib_buffer = None; + zlib_inflate = None; + message = GatewayMessage::from_raw_json_message(received).unwrap(); + } + GatewayTransportCompression::ZLibStream => { + zlib_buffer = Some(Vec::new()); + let mut inflate = Decompress::new(true); + + message = GatewayMessage::from_zlib_stream_json_message(received, &mut inflate).unwrap(); + + zlib_inflate = Some(inflate); + } + } + + let gateway_payload: types::GatewayReceivePayload = serde_json::from_str(&message.0).unwrap(); if gateway_payload.op_code != GATEWAY_HELLO { return Err(GatewayError::NonHelloOnInitiate { @@ -85,7 +126,10 @@ impl Gateway { kill_send: kill_send.clone(), kill_receive: kill_send.subscribe(), store: store.clone(), - url: websocket_url.clone(), + url: url.clone(), + options, + zlib_inflate, + zlib_buffer, }; // Now we can continuously check for messages in a different task, since we aren't going to receive another hello @@ -99,7 +143,7 @@ impl Gateway { }); Ok(GatewayHandle { - url: websocket_url.clone(), + url: url.clone(), events: shared_events, websocket_send: shared_websocket_send.clone(), kill_send: kill_send.clone(), @@ -108,7 +152,7 @@ impl Gateway { } /// The main gateway listener task; - pub async fn gateway_listen_task(&mut self) { + async fn gateway_listen_task(&mut self) { loop { let msg; @@ -125,12 +169,12 @@ impl Gateway { // PRETTYFYME: Remove inline conditional compiling #[cfg(not(target_arch = "wasm32"))] if let Some(Ok(message)) = msg { - self.handle_message(message.into()).await; + self.handle_raw_message(message.into()).await; continue; } #[cfg(target_arch = "wasm32")] if let Some(message) = msg { - self.handle_message(message.into()).await; + self.handle_raw_message(message.into()).await; continue; } @@ -163,8 +207,41 @@ impl Gateway { Ok(()) } + /// Takes a [RawGatewayMessage], converts it to [GatewayMessage] based + /// of connection options and calls handle_message + async fn handle_raw_message(&mut self, raw_message: RawGatewayMessage) { + let message; + + match self.options.transport_compression { + GatewayTransportCompression::None => { + message = GatewayMessage::from_raw_json_message(raw_message).unwrap() + } + GatewayTransportCompression::ZLibStream => { + let message_bytes = raw_message.into_bytes(); + + let can_decompress = message_bytes.len() > 4 + && message_bytes[message_bytes.len() - 4..] == ZLIB_SUFFIX; + + let zlib_buffer = self.zlib_buffer.as_mut().unwrap(); + zlib_buffer.extend(message_bytes.clone()); + + if !can_decompress { + return; + } + + let zlib_buffer = self.zlib_buffer.as_ref().unwrap(); + let inflate = self.zlib_inflate.as_mut().unwrap(); + + message = GatewayMessage::from_zlib_stream_json_bytes(zlib_buffer, inflate).unwrap(); + self.zlib_buffer = Some(Vec::new()); + } + }; + + self.handle_message(message).await; + } + /// This handles a message as a websocket event and updates its events along with the events' observers - pub async fn handle_message(&mut self, msg: GatewayMessage) { + async fn handle_message(&mut self, msg: GatewayMessage) { if msg.0.is_empty() { return; } diff --git a/src/gateway/message.rs b/src/gateway/message.rs index 44d912ef..7f581e5b 100644 --- a/src/gateway/message.rs +++ b/src/gateway/message.rs @@ -2,11 +2,41 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use std::string::FromUtf8Error; + use crate::types; use super::*; -/// Represents a message received from the gateway. This will be either a [types::GatewayReceivePayload], containing events, or a [GatewayError]. +/// Defines a raw gateway message, being either string json or bytes +/// +/// This is used as an intermediary type between types from different websocket implementations +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) enum RawGatewayMessage { + Text(String), + Bytes(Vec), +} + +impl RawGatewayMessage { + /// Attempt to consume the message into a String, will try to convert binary to utf8 + pub fn into_text(self) -> Result { + match self { + RawGatewayMessage::Text(text) => Ok(text), + RawGatewayMessage::Bytes(bytes) => String::from_utf8(bytes), + } + } + + /// Consume the message into bytes, will convert text to binary + pub fn into_bytes(self) -> Vec { + match self { + RawGatewayMessage::Text(text) => text.as_bytes().to_vec(), + RawGatewayMessage::Bytes(bytes) => bytes, + } + } +} + +/// Represents a json message received from the gateway. +/// This will be either a [types::GatewayReceivePayload], containing events, or a [GatewayError]. /// This struct is used internally when handling messages. #[derive(Clone, Debug)] pub struct GatewayMessage(pub String); @@ -44,4 +74,41 @@ impl GatewayMessage { pub fn payload(&self) -> Result { serde_json::from_str(&self.0) } + + /// Create self from an uncompressed json [RawGatewayMessage] + pub(crate) fn from_raw_json_message( + message: RawGatewayMessage, + ) -> Result { + let text = message.into_text()?; + Ok(GatewayMessage(text)) + } + + /// Attempt to create self by decompressing zlib-stream bytes + // Thanks to , their + // code helped a lot with the stream implementation + pub(crate) fn from_zlib_stream_json_bytes( + bytes: &[u8], + inflate: &mut flate2::Decompress, + ) -> Result { + + // Note: is there a better way to handle the size of this output buffer? + // + // This used to be 10, I measured it at 11.5, so a safe bet feels like 20 + let mut output = Vec::with_capacity(bytes.len() * 20); + let _status = inflate.decompress_vec(bytes, &mut output, flate2::FlushDecompress::Sync)?; + + output.shrink_to_fit(); + + let string = String::from_utf8(output).unwrap(); + + Ok(GatewayMessage(string)) + } + + /// Attempt to create self by decompressing a zlib-stream bytes raw message + pub(crate) fn from_zlib_stream_json_message( + message: RawGatewayMessage, + inflate: &mut flate2::Decompress, + ) -> Result { + Self::from_zlib_stream_json_bytes(&message.into_bytes(), inflate) + } } diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index b48786e9..3e96af07 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -10,12 +10,14 @@ pub mod gateway; pub mod handle; pub mod heartbeat; pub mod message; +pub mod options; pub use backends::*; pub use gateway::*; pub use handle::*; use heartbeat::*; pub use message::*; +pub use options::*; use crate::errors::GatewayError; use crate::types::{Snowflake, WebSocketEvent}; diff --git a/src/gateway/options.rs b/src/gateway/options.rs new file mode 100644 index 00000000..e5c0314e --- /dev/null +++ b/src/gateway/options.rs @@ -0,0 +1,118 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Debug, Default)] +/// Options passed when initializing the gateway connection. +/// +/// E.g. compression +/// +/// # Note +/// +/// Discord allows specifying the api version (v10, v9, ...) as well, but chorus is built upon one +/// main version (v9). +/// +/// Similarly, discord also supports etf encoding, while chorus does not (yet). +/// We are looking into supporting it as an option, since it is faster and more lightweight. +/// +/// See +pub struct GatewayOptions { + pub encoding: GatewayEncoding, + pub transport_compression: GatewayTransportCompression, +} + +impl GatewayOptions { + /// Adds the options to an existing gateway url + /// + /// Returns the new url + pub(crate) fn add_to_url(&self, url: String) -> String { + + let mut url = url; + + let mut parameters = Vec::with_capacity(2); + + let encoding = self.encoding.to_url_parameter(); + parameters.push(encoding); + + let compression = self.transport_compression.to_url_parameter(); + if let Some(some_compression) = compression { + parameters.push(some_compression); + } + + let mut has_parameters = url.contains('?') && url.contains('='); + + if !has_parameters { + // Insure it ends in a /, so we don't get a 400 error + if !url.ends_with('/') { + url.push('/'); + } + + // Lets hope that if it already has parameters the person knew to add '/' + } + + for parameter in parameters { + if !has_parameters { + url = format!("{}?{}", url, parameter); + has_parameters = true; + } + else { + url = format!("{}&{}", url, parameter); + } + } + + url + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Debug, Default)] +/// Possible transport compression options for the gateway. +/// +/// See +pub enum GatewayTransportCompression { + /// Do not transport compress packets + None, + /// Transport compress using zlib stream + #[default] + ZLibStream, +} + +impl GatewayTransportCompression { + /// Returns the option as a url parameter. + /// + /// If set to [GatewayTransportCompression::None] returns [None]. + /// + /// If set to anything else, returns a string like "compress=zlib-stream" + pub(crate) fn to_url_parameter(self) -> Option { + match self { + Self::None => None, + Self::ZLibStream => Some(String::from("compress=zlib-stream")) + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Debug, Default)] +/// See +pub enum GatewayEncoding { + /// Javascript object notation, a standard for websocket connections, + /// but contains a lot of overhead + #[default] + Json, + /// A binary format originating from Erlang + /// + /// Should be lighter and faster than json. + /// + /// !! Chorus does not implement ETF yet !! + ETF +} + +impl GatewayEncoding { + /// Returns the option as a url parameter. + /// + /// Returns a string like "encoding=json" + pub(crate) fn to_url_parameter(self) -> String { + match self { + Self::Json => String::from("encoding=json"), + Self::ETF => String::from("encoding=etf") + } + } +} diff --git a/src/instance.rs b/src/instance.rs index d23a5678..e6ba5c8a 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -13,7 +13,7 @@ use reqwest::Client; use serde::{Deserialize, Serialize}; use crate::errors::ChorusResult; -use crate::gateway::{Gateway, GatewayHandle}; +use crate::gateway::{Gateway, GatewayHandle, GatewayOptions}; use crate::ratelimiter::ChorusRequest; use crate::types::types::subconfigs::limits::rates::RateLimits; use crate::types::{ @@ -31,6 +31,8 @@ pub struct Instance { pub limits_information: Option, #[serde(skip)] pub client: Client, + #[serde(skip)] + pub gateway_options: GatewayOptions, } impl PartialEq for Instance { @@ -104,6 +106,7 @@ impl Instance { instance_info: GeneralConfiguration::default(), limits_information: limit_information, client: Client::new(), + gateway_options: GatewayOptions::default(), }; instance.instance_info = match instance.general_configuration_schema().await { Ok(schema) => schema, @@ -139,6 +142,13 @@ impl Instance { Err(_) => Ok(None), } } + + /// Sets the [`GatewayOptions`] the instance will use when spawning new connections. + /// + /// These options are used on the gateways created when logging in and registering. + pub fn set_gateway_options(&mut self, options: GatewayOptions) { + self.gateway_options = options; + } } #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -215,7 +225,9 @@ impl ChorusUser { let object = Arc::new(RwLock::new(User::default())); let wss_url = instance.read().unwrap().urls.wss.clone(); // Dummy gateway object - let gateway = Gateway::spawn(wss_url).await.unwrap(); + let gateway = Gateway::spawn(wss_url, GatewayOptions::default()) + .await + .unwrap(); ChorusUser { token, belongs_to: instance.clone(), diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index c1219ad1..044c1e2d 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -4,7 +4,6 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use serde_aux::prelude::deserialize_string_from_number; use serde_repr::{Deserialize_repr, Serialize_repr}; use std::fmt::Debug; @@ -274,4 +273,4 @@ pub enum ChannelType { pub struct FollowedChannel { pub channel_id: Snowflake, pub webhook_id: Snowflake -} \ No newline at end of file +} diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index 34a7b9bf..fe7ff7b5 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -429,4 +429,4 @@ pub struct PartialEmoji { pub enum ReactionType { Normal = 0, Burst = 1, // The dreaded super reactions -} \ No newline at end of file +} diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index 70669d03..c7e60b30 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -4,11 +4,9 @@ use crate::types::utils::Snowflake; use chrono::{DateTime, Utc}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde::{Deserialize, Serialize}; use serde_aux::prelude::deserialize_option_number_from_string; use std::fmt::Debug; -use std::num::ParseIntError; -use std::str::FromStr; #[cfg(feature = "client")] use crate::gateway::Updateable; diff --git a/src/types/events/presence.rs b/src/types/events/presence.rs index 9fe7c1eb..09d07390 100644 --- a/src/types/events/presence.rs +++ b/src/types/events/presence.rs @@ -20,7 +20,9 @@ pub struct UpdatePresence { #[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, WebSocketEvent)] /// Received to tell the client that a user updated their presence / status +/// /// See +/// (Same structure as ) pub struct PresenceUpdate { pub user: PublicUser, #[serde(default)] diff --git a/src/types/events/ready.rs b/src/types/events/ready.rs index 4faa95dd..ffba526a 100644 --- a/src/types/events/ready.rs +++ b/src/types/events/ready.rs @@ -6,13 +6,14 @@ use serde::{Deserialize, Serialize}; use crate::types::entities::{Guild, User}; use crate::types::events::{Session, WebSocketEvent}; -use crate::types::interfaces::ClientStatusObject; -use crate::types::{Activity, GuildMember, PresenceUpdate, VoiceState}; +use crate::types::{Activity, Channel, ClientStatusObject, GuildMember, PresenceUpdate, Snowflake, VoiceState}; #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] -/// 1/2 half documented; +/// 1/2 officially documented; /// Received after identifying, provides initial user info; -/// See +/// +/// See and +// TODO: There are a LOT of fields missing here pub struct GatewayReady { pub analytics_token: Option, pub auth_session_id_hash: Option, @@ -32,36 +33,47 @@ pub struct GatewayReady { #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// Officially Undocumented; -/// Sent after the READY event when a client is a user, seems to somehow add onto the ready event; +/// Sent after the READY event when a client is a user, +/// seems to somehow add onto the ready event; +/// +/// See pub struct GatewayReadySupplemental { + /// The presences of the user's relationships and guild presences sent at startup pub merged_presences: MergedPresences, pub merged_members: Vec>, - // ? - pub lazy_private_channels: Vec, + pub lazy_private_channels: Vec, pub guilds: Vec, - // ? pomelo + // "Upcoming changes that the client should disclose to the user" (discord.sex) pub disclose: Vec, } #[derive(Debug, Deserialize, Serialize, Default, Clone)] +/// See pub struct MergedPresences { - pub guilds: Vec>, + /// "Presences of the user's guilds in the same order as the guilds array in ready" + /// (discord.sex) + pub guilds: Vec>, + /// "Presences of the user's friends and implicit relationships" (discord.sex) pub friends: Vec, } #[derive(Debug, Deserialize, Serialize, Default, Clone)] +/// Not documented even unofficially pub struct MergedPresenceFriend { - pub user_id: String, + pub user_id: Snowflake, pub status: String, - /// Looks like ms?? - pub last_modified: u128, + // Looks like ms?? + // + // Not always sent + pub last_modified: Option, pub client_status: ClientStatusObject, pub activities: Vec, } #[derive(Debug, Deserialize, Serialize, Default, Clone)] +/// Not documented even unofficially pub struct MergedPresenceGuild { - pub user_id: String, + pub user_id: Snowflake, pub status: String, // ? pub game: Option, @@ -70,8 +82,10 @@ pub struct MergedPresenceGuild { } #[derive(Debug, Deserialize, Serialize, Default, Clone)] +/// See pub struct SupplementalGuild { + pub id: Snowflake, pub voice_states: Option>, - pub id: String, + /// Field not documented even unofficially pub embedded_activities: Vec, } diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 33df3ffd..c3c02f49 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -3,10 +3,9 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use bitflags::bitflags; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use serde::de::Visitor; +use serde::{Deserialize, Serialize}; -use crate::types::{ChannelType, DefaultReaction, Error, entities::PermissionOverwrite, Snowflake}; +use crate::types::{ChannelType, DefaultReaction, entities::PermissionOverwrite, Snowflake}; #[derive(Debug, Deserialize, Serialize, Default, PartialEq, PartialOrd)] #[serde(rename_all = "snake_case")] @@ -188,4 +187,4 @@ pub struct AddFollowingChannelSchema { pub struct CreateWebhookSchema { pub name: String, pub avatar: Option, -} \ No newline at end of file +} diff --git a/src/types/schema/user.rs b/src/types/schema/user.rs index 7d217544..e2600a49 100644 --- a/src/types/schema/user.rs +++ b/src/types/schema/user.rs @@ -4,24 +4,91 @@ use std::collections::HashMap; +use chrono::NaiveDate; use serde::{Deserialize, Serialize}; use crate::types::Snowflake; -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] #[serde(rename_all = "snake_case")] /// A schema used to modify a user. +/// +/// See pub struct UserModifySchema { + /// The user's new username (2-32 characters) + /// + /// Requires that `current_password` is set. pub username: Option, + // TODO: Maybe add a special discriminator type? + /// Requires that `current_password` is set. + pub discriminator: Option, + /// The user's display name (1-32 characters) + /// + /// # Note + /// + /// This is not yet implemented on Spacebar + pub global_name: Option, + // TODO: Add a CDN data type pub avatar: Option, + /// Note: This is not yet implemented on Spacebar + pub avatar_decoration_id: Option, + /// Note: This is not yet implemented on Spacebar + pub avatar_decoration_sku_id: Option, + /// The user's email address; if changing from a verified email, email_token must be provided + /// + /// Requires that `current_password` is set. + // TODO: Is ^ up to date? One would think this may not be the case, since email_token exists + pub email: Option, + /// The user's email token from their previous email, required if a new email is set. + /// + /// See and + /// for changing the user's email. + /// + /// # Note + /// + /// This is not yet implemented on Spacebar + pub email_token: Option, + /// The user's pronouns (max 40 characters) + /// + /// # Note + /// + /// This is not yet implemented on Spacebar + pub pronouns: Option, + /// The user's banner. + /// + /// Can only be changed for premium users + pub banner: Option, + /// The user's bio (max 190 characters) pub bio: Option, + /// The user's accent color, as a hex integer pub accent_color: Option, - pub banner: Option, + /// The user's [UserFlags]. + /// + /// Only [UserFlags::PREMIUM_PROMO_DISMISSED], [UserFlags::HAS_UNREAD_URGENT_MESSAGES] + /// and DISABLE_PREMIUM can be set. + /// + /// # Note + /// + /// This is not yet implemented on Spacebar + pub flags: Option, + /// The user's date of birth, can only be set once + /// + /// Requires that `current_password` is set. + pub date_of_birth: Option, + /// The user's current password (if the account does not have a password, this sets it) + /// + /// Required for updating `username`, `discriminator`, `email`, `date_of_birth` and + /// `new_password` + #[serde(rename = "password")] pub current_password: Option, + /// The user's new password (8-72 characters) + /// + /// Requires that `current_password` is set. + /// + /// Regenerates the user's token pub new_password: Option, + /// Spacebar only field, potentially same as `email_token` pub code: Option, - pub email: Option, - pub discriminator: Option, } /// A schema used to create a private channel. @@ -33,7 +100,7 @@ pub struct UserModifySchema { /// /// # Reference: /// Read: -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] pub struct PrivateChannelCreateSchema { pub recipients: Option>, pub access_tokens: Option>, diff --git a/src/voice/gateway/backends/wasm.rs b/src/voice/gateway/backends/wasm.rs index 611b2027..7b069c60 100644 --- a/src/voice/gateway/backends/wasm.rs +++ b/src/voice/gateway/backends/wasm.rs @@ -23,3 +23,4 @@ impl From for VoiceGatewayMessage { } } } + diff --git a/src/voice/gateway/gateway.rs b/src/voice/gateway/gateway.rs index 9a2a60b1..6ff2a379 100644 --- a/src/voice/gateway/gateway.rs +++ b/src/voice/gateway/gateway.rs @@ -44,7 +44,7 @@ impl VoiceGateway { pub async fn spawn(websocket_url: String) -> Result { // Append the needed things to the websocket url let processed_url = format!("wss://{}/?v=7", websocket_url); - trace!("Created voice socket url: {}", processed_url.clone()); + trace!("VGW: Connecting to {}", processed_url.clone()); let (websocket_send, mut websocket_receive) = match WebSocketBackend::connect(&processed_url).await { diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 315db38d..863e91f7 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -4,7 +4,7 @@ use std::str::FromStr; -use chorus::gateway::Gateway; +use chorus::gateway::{Gateway, GatewayOptions}; use chorus::types::IntoShared; use chorus::{ instance::{ChorusUser, Instance}, @@ -50,7 +50,7 @@ impl TestBundle { limits: self.user.limits.clone(), settings: self.user.settings.clone(), object: self.user.object.clone(), - gateway: Gateway::spawn(self.instance.urls.wss.clone()) + gateway: Gateway::spawn(self.instance.urls.wss.clone(), GatewayOptions::default()) .await .unwrap(), } @@ -59,6 +59,10 @@ impl TestBundle { // Set up a test by creating an Instance and a User. Reduces Test boilerplate. pub(crate) async fn setup() -> TestBundle { + + // So we can get logs when tests fail + let _ = simple_logger::SimpleLogger::with_level(simple_logger::SimpleLogger::new(), log::LevelFilter::Debug).init(); + let instance = Instance::new("http://localhost:3001/api").await.unwrap(); // Requires the existence of the below user. let reg = RegisterSchema { @@ -119,7 +123,7 @@ pub(crate) async fn setup() -> TestBundle { let urls = UrlBundle::new( "http://localhost:3001/api".to_string(), "http://localhost:3001/api".to_string(), - "ws://localhost:3001".to_string(), + "ws://localhost:3001/".to_string(), "http://localhost:3001".to_string(), ); TestBundle { diff --git a/tests/gateway.rs b/tests/gateway.rs index 9f72a640..12626a6d 100644 --- a/tests/gateway.rs +++ b/tests/gateway.rs @@ -30,7 +30,7 @@ use wasmtimer::tokio::sleep; async fn test_gateway_establish() { let bundle = common::setup().await; - let _: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone()).await.unwrap(); + let _: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone(), GatewayOptions::default()).await.unwrap(); common::teardown(bundle).await } @@ -52,7 +52,7 @@ impl Observer for GatewayReadyObserver { async fn test_gateway_authenticate() { let bundle = common::setup().await; - let gateway: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone()).await.unwrap(); + let gateway: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone(), GatewayOptions::default()).await.unwrap(); let (ready_send, mut ready_receive) = tokio::sync::mpsc::channel(1); @@ -79,7 +79,7 @@ async fn test_gateway_authenticate() { println!("Timed out waiting for event, failing.."); assert!(false); } - // Sucess, we have received it + // Success, we have received it Some(_) = ready_receive.recv() => {} }; From 39e7f89c785310daa2a089c5f72c9b579a346ff8 Mon Sep 17 00:00:00 2001 From: Quat3rnion <81202811+Quat3rnion@users.noreply.github.com> Date: Thu, 27 Jun 2024 02:45:51 -0400 Subject: [PATCH 080/162] Backend/guilds (#509) * Fix SQL encode/decode for GuildFeatures * Use distinct PermissionFlags type * Add Emoji schema types, modify GuildBan with feature lock * Add Schemas for pruning guild members * Add schemas for interfacing with stickers backend routes * Add schemas for interfacing with vanity-url backend routes * Add schema for interfacing with guilds/id/welcome-screen route * Make all Option types Vec types with #[serde(default)] * Add various types to support guilds/* api routes * Add missing enums and structs for searching messages * Use proper distinct types * Add EmbedType enum * Use distinct PermissionFlags type * Changes supporting backend for VoiceState * Changes supporting backend for AuditLog's --- Cargo.lock | 19 ++ Cargo.toml | 2 +- src/types/config/types/guild_configuration.rs | 35 +-- src/types/entities/audit_log.rs | 177 +++++++++++++- src/types/entities/guild.rs | 32 ++- src/types/entities/guild_member.rs | 5 +- src/types/entities/integration.rs | 14 +- src/types/entities/invite.rs | 2 +- src/types/entities/message.rs | 24 +- src/types/entities/role.rs | 5 +- src/types/entities/sticker.rs | 79 ++++++- src/types/entities/voice_state.rs | 2 + src/types/events/channel.rs | 12 +- src/types/events/guild.rs | 12 +- src/types/schema/audit_log.rs | 23 ++ src/types/schema/guild.rs | 219 +++++++++++++++++- src/types/schema/invites.rs | 16 ++ src/types/schema/message.rs | 81 ++++++- src/types/schema/mod.rs | 10 + src/types/schema/role.rs | 7 +- src/types/schema/voice_state.rs | 15 ++ tests/common/mod.rs | 4 +- tests/gateway.rs | 18 +- tests/roles.rs | 3 +- 24 files changed, 712 insertions(+), 104 deletions(-) create mode 100644 src/types/schema/audit_log.rs create mode 100644 src/types/schema/voice_state.rs diff --git a/Cargo.lock b/Cargo.lock index bb74a326..f967a21f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1272,6 +1272,24 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "multer" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http 1.1.0", + "httparse", + "memchr", + "mime", + "spin 0.9.8", + "tokio", + "version_check", +] + [[package]] name = "native-tls" version = "0.2.11" @@ -1609,6 +1627,7 @@ dependencies = [ "hyper 1.3.1", "hyper-util", "mime", + "multer", "nix 0.28.0", "parking_lot", "percent-encoding", diff --git a/Cargo.toml b/Cargo.toml index a1ab80df..f2e5f12f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ http = "0.2.11" base64 = "0.21.7" bitflags = { version = "2.4.1", features = ["serde"] } lazy_static = "1.4.0" -poem = { version = "3.0.1", optional = true } +poem = { version = "3.0.1", features = ["multipart"], optional = true } thiserror = "1.0.56" jsonwebtoken = "8.3.0" log = "0.4.20" diff --git a/src/types/config/types/guild_configuration.rs b/src/types/config/types/guild_configuration.rs index d2b3f16c..53a2d452 100644 --- a/src/types/config/types/guild_configuration.rs +++ b/src/types/config/types/guild_configuration.rs @@ -3,19 +3,10 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use std::fmt::{Display, Formatter}; -#[cfg(feature = "sqlx")] -use std::io::Write; use std::ops::{Deref, DerefMut}; use std::str::FromStr; use serde::{Deserialize, Serialize}; -#[cfg(feature = "sqlx")] -use sqlx::{ - database::{HasArguments, HasValueRef}, - encode::IsNull, - error::BoxDynError, - Decode, MySql, -}; use crate::types::config::types::subconfigs::guild::{ autojoin::AutoJoinConfiguration, discovery::DiscoverConfiguration, @@ -172,8 +163,8 @@ impl Display for GuildFeaturesList { #[cfg(feature = "sqlx")] impl<'r> sqlx::Decode<'r, sqlx::MySql> for GuildFeaturesList { - fn decode(value: >::ValueRef) -> Result { - let v = <&str as Decode>::decode(value)?; + fn decode(value: >::ValueRef) -> Result { + let v = >::decode(value)?; Ok(Self( v.split(',') .filter(|f| !f.is_empty()) @@ -185,9 +176,9 @@ impl<'r> sqlx::Decode<'r, sqlx::MySql> for GuildFeaturesList { #[cfg(feature = "sqlx")] impl<'q> sqlx::Encode<'q, sqlx::MySql> for GuildFeaturesList { - fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> IsNull { + fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { if self.is_empty() { - return IsNull::Yes; + return sqlx::encode::IsNull::Yes; } let features = self .iter() @@ -195,30 +186,18 @@ impl<'q> sqlx::Encode<'q, sqlx::MySql> for GuildFeaturesList { .collect::>() .join(","); - let _ = buf.write(features.as_bytes()); - IsNull::No + >::encode_by_ref(&features, buf) } } #[cfg(feature = "sqlx")] impl sqlx::Type for GuildFeaturesList { fn type_info() -> sqlx::mysql::MySqlTypeInfo { - <&str as sqlx::Type>::type_info() + >::type_info() } fn compatible(ty: &sqlx::mysql::MySqlTypeInfo) -> bool { - <&str as sqlx::Type>::compatible(ty) - } -} - -#[cfg(feature = "sqlx")] -impl sqlx::TypeInfo for GuildFeaturesList { - fn is_null(&self) -> bool { - false - } - - fn name(&self) -> &str { - "TEXT" + >::compatible(ty) } } diff --git a/src/types/entities/audit_log.rs b/src/types/entities/audit_log.rs index 566b2231..48dc9d49 100644 --- a/src/types/entities/audit_log.rs +++ b/src/types/entities/audit_log.rs @@ -3,21 +3,27 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; -use crate::types::Shared; +use crate::types::{AutoModerationRuleTriggerType, IntegrationType, PermissionOverwriteType, Shared}; use crate::types::utils::Snowflake; #[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] /// See pub struct AuditLogEntry { pub target_id: Option, + #[cfg(feature = "sqlx")] + pub changes: sqlx::types::Json>>>, + #[cfg(not(feature = "sqlx"))] pub changes: Option>>, pub user_id: Option, pub id: Snowflake, - // to:do implement an enum for these types - pub action_type: u8, - // to:do add better options type - pub options: Option, + pub action_type: AuditLogActionType, + #[cfg(feature = "sqlx")] + pub options: Option>, + #[cfg(not(feature = "sqlx"))] + pub options: Option, pub reason: Option, } @@ -28,3 +34,164 @@ pub struct AuditLogChange { pub old_value: Option, pub key: String, } + + +#[derive(Default, Serialize_repr, Deserialize_repr, Debug, Clone, Copy)] +#[repr(u8)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +/// # Reference: +/// See +pub enum AuditLogActionType { + #[default] + /// Guild settings were updated + GuildUpdate = 1, + /// Channel was created + ChannelCreate = 10, + /// Channel settings were updated + ChannelUpdate = 11, + /// Channel was deleted + ChannelDelete = 12, + /// Permission overwrite was added to a channel + ChannelOverwriteCreate = 13, + /// Permission overwrite was updated for a channel + ChannelOverwriteUpdate = 14, + /// Permission overwrite was deleted from a channel + ChannelOverwriteDelete = 15, + /// Member was removed from guild + MemberKick = 20, + /// Members were pruned from guild + MemberPrune = 21, + /// Member was banned from guild + MemberBanAdd = 22, + /// Member was unbanned from guild + MemberBanRemove = 23, + /// Member was updated in guild + MemberUpdate = 24, + /// Member was added or removed from a role + MemberRoleUpdate = 25, + /// Member was moved to a different voice channel + MemberMove = 26, + /// Member was disconnected from a voice channel + MemberDisconnect = 27, + /// Bot user was added to guild + BotAdd = 28, + /// Role was created + RoleCreate = 30, + /// Role was edited + RoleUpdate = 31, + /// Role was deleted + RoleDelete = 32, + /// Guild invite was created + InviteCreate = 40, + /// Guild invite was updated + InviteUpdate = 41, + /// Guild invite was deleted + InviteDelete = 42, + /// Webhook was created + WebhookCreate = 50, + /// Webhook properties or channel were updated + WebhookUpdate = 51, + /// Webhook was deleted + WebhookDelete = 52, + /// Emoji was created + EmojiCreate = 60, + /// Emoji name was updated + EmojiUpdate = 61, + /// Emoji was deleted + EmojiDelete = 62, + /// Single message was deleted + MessageDelete = 72, + /// Multiple messages were deleted + MessageBulkDelete = 73, + /// Message was pinned to a channel + MessagePin = 74, + /// Message was unpinned from a channel + MessageUnpin = 75, + /// Interaction was added to guild + IntegrationCreate = 80, + /// Integration was updated (e.g. its scopes were updated) + IntegrationUpdate = 81, + /// Integration was removed from guild + IntegrationDelete = 82, + /// Stage instance was created (stage channel becomes live) + StageInstanceCreate = 83, + /// Stage instance details were updated + StageInstanceUpdate = 84, + /// Stage instance was deleted (stage channel no longer live) + StageInstanceDelete = 85, + /// Sticker was created + StickerCreate = 90, + /// Sticker details were updated + StickerUpdate = 91, + /// Sticker was deleted + StickerDelete = 92, + /// Event was created + GuildScheduledEventCreate = 100, + /// Event was updated + GuildScheduledEventUpdate = 101, + /// Event was cancelled + GuildScheduledEventDelete = 102, + /// Thread was created in a channel + ThreadCreate = 110, + /// Thread was updated + ThreadUpdate = 111, + /// Thread was deleted + ThreadDelete = 112, + /// Permissions were updated for a command + ApplicationCommandPermissionUpdate = 121, + /// AutoMod rule created + AutoModerationRuleCreate = 140, + /// AutoMod rule was updated + AutoModerationRuleUpdate = 141, + /// AutoMod rule was deleted + AutoModerationRuleDelete = 142, + /// Message was blocked by AutoMod + AutoModerationBlockMessage = 143, + /// Message was flagged by AutoMod + AutoModerationFlagToChannel = 144, + /// Member was timed out by AutoMod + AutoModerationUserCommunicationDisabled = 145, + /// Member was quarantined by AutoMod + AutoModerationQuarantineUser = 146, + /// Creator monetization request was created + CreatorMonetizationRequestCreated = 150, + /// Creator monetization terms were accepted + CreatorMonetizationTermsAccepted = 151, + /// Onboarding prompt was created + OnboardingPromptCreate = 163, + /// Onboarding prompt was updated + OnboardingPromptUpdate = 164, + /// Onboarding prompt was deleted + OnboardingPromptDelete = 165, + /// Onboarding was created + OnboardingCreate = 166, + /// Onboarding was updated + OnboardingUpdate = 167, + /// Voice channel status was updated + VoiceChannelStatusUpdate = 192, + /// Voice channel status was deleted + VoiceChannelStatusDelete = 193 +} + +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct AuditEntryInfo { + pub application_id: Option, + pub auto_moderation_rule_name: Option, + pub auto_moderation_rule_trigger_type: Option, + pub channel_id: Option, + // #[serde(option_string)] + pub count: Option, + // #[serde(option_string)] + pub delete_member_days: Option, + /// The ID of the overwritten entity + pub id: Option, + pub integration_type: Option, + // #[serde(option_string)] + pub members_removed: Option, + // #[serde(option_string)] + pub message_id: Option, + pub role_name: Option, + #[serde(rename = "type")] + pub overwrite_type: Option, + pub status: Option +} \ No newline at end of file diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 866b1729..72e6a7eb 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -23,7 +23,7 @@ use super::PublicUser; use crate::gateway::Updateable; #[cfg(feature = "client")] -use chorus_macros::{observe_option_vec, observe_vec, Composite, Updateable}; +use chorus_macros::{observe_vec, Composite, Updateable}; #[cfg(feature = "client")] use crate::types::Composite; @@ -46,10 +46,12 @@ pub struct Guild { pub approximate_presence_count: Option, pub banner: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub bans: Option>, + #[serde(default)] + pub bans: Vec, #[cfg_attr(feature = "sqlx", sqlx(skip))] - #[cfg_attr(feature = "client", observe_option_vec)] - pub channels: Option>>, + #[cfg_attr(feature = "client", observe_vec)] + #[serde(default)] + pub channels: Vec>, pub default_message_notifications: Option, pub description: Option, pub discovery_splash: Option, @@ -66,7 +68,8 @@ pub struct Guild { pub icon_hash: Option, pub id: Snowflake, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub invites: Option>, + #[serde(default)] + pub invites: Vec, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub joined_at: Option>, pub large: Option, @@ -92,25 +95,29 @@ pub struct Guild { pub public_updates_channel_id: Option, pub region: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - #[cfg_attr(feature = "client", observe_option_vec)] - pub roles: Option>>, + #[cfg_attr(feature = "client", observe_vec)] + #[serde(default)] + pub roles: Vec>, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub rules_channel: Option, pub rules_channel_id: Option, pub splash: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub stickers: Option>, + #[serde(default)] + pub stickers: Vec, pub system_channel_flags: Option, pub system_channel_id: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub vanity_url_code: Option, pub verification_level: Option, + #[serde(default)] #[cfg_attr(feature = "sqlx", sqlx(skip))] - #[cfg_attr(feature = "client", observe_option_vec)] - pub voice_states: Option>>, + #[cfg_attr(feature = "client", observe_vec)] + pub voice_states: Vec>, + #[serde(default)] #[cfg_attr(feature = "sqlx", sqlx(skip))] - #[cfg_attr(feature = "client", observe_option_vec)] - pub webhooks: Option>>, + #[cfg_attr(feature = "client", observe_vec)] + pub webhooks: Vec>, #[cfg(feature = "sqlx")] pub welcome_screen: sqlx::types::Json>, #[cfg(not(feature = "sqlx"))] @@ -226,6 +233,7 @@ impl std::cmp::PartialEq for Guild { #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct GuildBan { + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub user: PublicUser, pub reason: Option, } diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index 522824ce..5b1308d4 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -5,7 +5,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::types::{GuildMemberFlags, Shared}; +use crate::types::{GuildMemberFlags, PermissionFlags, Shared}; use crate::types::{entities::PublicUser, Snowflake}; #[derive(Debug, Deserialize, Default, Serialize, Clone)] @@ -27,6 +27,7 @@ pub struct GuildMember { pub mute: bool, pub flags: Option, pub pending: Option, - pub permissions: Option, + #[serde(default)] + pub permissions: PermissionFlags, pub communication_disabled_until: Option>, } diff --git a/src/types/entities/integration.rs b/src/types/entities/integration.rs index db4fecf2..4b42f463 100644 --- a/src/types/entities/integration.rs +++ b/src/types/entities/integration.rs @@ -18,7 +18,7 @@ pub struct Integration { pub id: Snowflake, pub name: String, #[serde(rename = "type")] - pub integration_type: String, + pub integration_type: IntegrationType, pub enabled: bool, pub syncing: Option, pub role_id: Option, @@ -43,3 +43,15 @@ pub struct IntegrationAccount { pub id: String, pub name: String, } + +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[cfg_attr(feature = "sqlx", sqlx(rename_all = "snake_case"))] +pub enum IntegrationType { + #[default] + Twitch, + Youtube, + Discord, + GuildSubscription, +} \ No newline at end of file diff --git a/src/types/entities/invite.rs b/src/types/entities/invite.rs index 388cc321..0160ac9e 100644 --- a/src/types/entities/invite.rs +++ b/src/types/entities/invite.rs @@ -13,7 +13,7 @@ use super::{Application, Channel, GuildMember, NSFWLevel, User}; /// Represents a code that when used, adds a user to a guild or group DM channel, or creates a relationship between two users. /// See -#[derive(Debug, Serialize, Deserialize)] +#[derive(Default, Debug, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Invite { #[cfg_attr(feature = "sqlx", sqlx(skip))] diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index fe7ff7b5..0a8169b5 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -177,7 +177,7 @@ pub struct ChannelMention { pub struct Embed { title: Option, #[serde(rename = "type")] - embed_type: Option, + embed_type: Option, description: Option, url: Option, timestamp: Option, @@ -191,6 +191,24 @@ pub struct Embed { fields: Option>, } +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +#[serde(rename_all = "snake_case")] +pub enum EmbedType { + #[deprecated] + ApplicationNews, + Article, + AutoModerationMessage, + AutoModerationNotification, + Gift, + #[serde(rename = "gifv")] + GifVideo, + Image, + Link, + PostPreview, + Rich, + Video +} + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub struct EmbedFooter { text: String, @@ -291,7 +309,7 @@ pub enum MessageType { Default = 0, /// A message sent when a user is added to a group DM or thread RecipientAdd = 1, - /// A message sent when a user is removed from a group DM or thread + /// A message sent when a user is removed from a group DM or thread RecipientRemove = 2, /// A message sent when a user creates a call in a private channel Call = 3, @@ -335,7 +353,7 @@ pub enum MessageType { ThreadStarterMessage = 21, /// A message sent to remind users to invite friends to a guild GuildInviteReminder = 22, - /// A message sent when a user uses a context menu command + /// A message sent when a user uses a context menu command ContextMenuCommand = 23, /// A message sent when auto moderation takes an action AutoModerationAction = 24, diff --git a/src/types/entities/role.rs b/src/types/entities/role.rs index 7e804f5f..8c00b41c 100644 --- a/src/types/entities/role.rs +++ b/src/types/entities/role.rs @@ -4,7 +4,7 @@ use bitflags::bitflags; 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; use std::fmt::Debug; use crate::types::utils::Snowflake; @@ -34,8 +34,7 @@ pub struct RoleObject { pub unicode_emoji: Option, pub position: u16, #[serde(default)] - #[serde(deserialize_with = "deserialize_string_from_number")] - pub permissions: String, + pub permissions: PermissionFlags, pub managed: bool, pub mentionable: bool, #[cfg(feature = "sqlx")] diff --git a/src/types/entities/sticker.rs b/src/types/entities/sticker.rs index 7048f826..22affcbb 100644 --- a/src/types/entities/sticker.rs +++ b/src/types/entities/sticker.rs @@ -3,6 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; use crate::types::{entities::User, utils::Snowflake, Shared}; @@ -18,15 +19,17 @@ pub struct Sticker { pub pack_id: Option, pub name: String, pub description: Option, - pub tags: String, + pub tags: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub asset: Option, #[serde(rename = "type")] - pub sticker_type: u8, - pub format_type: u8, + pub sticker_type: StickerType, + pub format_type: StickerFormatType, pub available: Option, pub guild_id: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub user: Option>, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub sort_value: Option, } @@ -108,6 +111,18 @@ impl PartialOrd for Sticker { } } +impl Sticker { + pub fn tags(&self) -> Vec { + self.tags + .as_ref() + .map_or(vec![], |s| + s.split(',') + .map(|tag| tag.trim().to_string()) + .collect() + ) + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] /// A partial sticker object. /// @@ -118,5 +133,61 @@ impl PartialOrd for Sticker { pub struct StickerItem { pub id: Snowflake, pub name: String, - pub format_type: u8, + pub format_type: StickerFormatType, +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Serialize_repr, Deserialize_repr)] +#[repr(u8)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[serde(rename = "SCREAMING_SNAKE_CASE")] +/// # Reference +/// See +pub enum StickerType { + /// An official sticker in a current or legacy purchasable pack + Standard = 1, + #[default] + /// A sticker uploaded to a guild for the guild's members + Guild = 2, +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Serialize_repr, Deserialize_repr)] +#[repr(u8)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +/// # Reference +/// See +pub enum StickerFormatType { + #[default] + /// A PNG image + PNG = 1, + /// An animated PNG image, using the APNG format - uses CDN + APNG = 2, + /// A lottie animation; requires the VERIFIED and/or PARTNERED guild feature - uses CDN + LOTTIE = 3, + /// An animated GIF image - does not use CDN + GIF = 4, +} + +impl StickerFormatType { + pub fn is_animated(&self) -> bool { + matches!(self, StickerFormatType::APNG | StickerFormatType::LOTTIE | StickerFormatType::GIF) + } + + pub const fn to_mime(&self) -> &'static str { + match self { + StickerFormatType::PNG => "image/png", + StickerFormatType::APNG => "image/apng", + StickerFormatType::LOTTIE => "application/json", + StickerFormatType::GIF => "image/gif", + } + } + + pub fn from_mime(mime: &str) -> Option { + match mime { + "image/png" => Some(StickerFormatType::PNG), + "image/apng" => Some(StickerFormatType::APNG), + "application/json" => Some(StickerFormatType::LOTTIE), + "image/gif" => Some(StickerFormatType::GIF), + _ => None, + } + } } diff --git a/src/types/entities/voice_state.rs b/src/types/entities/voice_state.rs index 7297456b..9953b7bf 100644 --- a/src/types/entities/voice_state.rs +++ b/src/types/entities/voice_state.rs @@ -34,9 +34,11 @@ use crate::types::{ #[cfg_attr(feature = "client", derive(Composite))] pub struct VoiceState { pub guild_id: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub guild: Option, pub channel_id: Option, pub user_id: Snowflake, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub member: Option>, /// Includes alphanumeric characters, not a snowflake pub session_id: String, diff --git a/src/types/events/channel.rs b/src/types/events/channel.rs index dd167542..73d89f61 100644 --- a/src/types/events/channel.rs +++ b/src/types/events/channel.rs @@ -49,11 +49,7 @@ impl UpdateMessage for ChannelCreate { fn update(&mut self, object_to_update: Shared) { let mut write = object_to_update.write().unwrap(); let update = self.channel.clone().into_shared(); - if write.channels.is_some() { - write.channels.as_mut().unwrap().push(update); - } else { - write.channels = Some(Vec::from([update])); - } + write.channels.push(update); } } @@ -122,12 +118,12 @@ impl UpdateMessage for ChannelDelete { return; } let mut write = object_to_update.write().unwrap(); - if write.channels.is_none() { + if write.channels.is_empty() { return; } - for (iteration, item) in (0_u32..).zip(write.channels.as_mut().unwrap().iter()) { + for (iteration, item) in (0_u32..).zip(write.channels.iter()) { if item.read().unwrap().id == self.id().unwrap() { - write.channels.as_mut().unwrap().remove(iteration as usize); + write.channels.remove(iteration as usize); return; } } diff --git a/src/types/events/guild.rs b/src/types/events/guild.rs index 362b9847..f2cc009c 100644 --- a/src/types/events/guild.rs +++ b/src/types/events/guild.rs @@ -214,15 +214,9 @@ impl UpdateMessage for GuildRoleCreate { fn update(&mut self, object_to_update: Shared) { let mut object_to_update = object_to_update.write().unwrap(); - if object_to_update.roles.is_some() { - object_to_update - .roles - .as_mut() - .unwrap() - .push(self.role.clone().into_shared()); - } else { - object_to_update.roles = Some(Vec::from([self.role.clone().into_shared()])); - } + object_to_update + .roles + .push(self.role.clone().into_shared()); } } diff --git a/src/types/schema/audit_log.rs b/src/types/schema/audit_log.rs new file mode 100644 index 00000000..ddee8325 --- /dev/null +++ b/src/types/schema/audit_log.rs @@ -0,0 +1,23 @@ +use serde::{Deserialize, Serialize}; +use crate::types::{ApplicationCommand, AuditLogActionType, AuditLogEntry, AutoModerationRule, Channel, GuildScheduledEvent, Integration, Snowflake, User, Webhook}; + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct AuditLogObject { + pub audit_log_entries: Vec, + pub application_commands: Vec, + pub auto_moderation_rules: Vec, + pub guild_scheduled_events: Vec, + pub integrations: Vec, + pub threads: Vec, + pub users: Vec, + pub webhooks: Vec, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct GetAuditLogsQuery { + pub before: Option, + pub after: Option, + pub limit: Option, + pub user_id: Option, + pub action_type: Option +} \ No newline at end of file diff --git a/src/types/schema/guild.rs b/src/types/schema/guild.rs index d820cd84..17c9d616 100644 --- a/src/types/schema/guild.rs +++ b/src/types/schema/guild.rs @@ -2,16 +2,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use std::collections::HashMap; use bitflags::bitflags; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::types::entities::Channel; use crate::types::types::guild_configuration::GuildFeatures; -use crate::types::{ - Emoji, ExplicitContentFilterLevel, MessageNotificationLevel, Snowflake, Sticker, - SystemChannelFlags, VerificationLevel, -}; +use crate::types::{Emoji, ExplicitContentFilterLevel, GenericSearchQueryWithLimit, MessageNotificationLevel, Snowflake, Sticker, StickerFormatType, SystemChannelFlags, VerificationLevel, WelcomeScreenChannel}; #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] #[serde(rename_all = "snake_case")] @@ -32,10 +30,20 @@ pub struct GuildCreateSchema { /// Represents the schema which needs to be sent to create a Guild Ban. /// See: pub struct GuildBanCreateSchema { + /// Deprecated pub delete_message_days: Option, pub delete_message_seconds: Option, } +#[derive(Debug, Deserialize, Serialize, Default, Clone, Eq, PartialEq)] +#[serde(rename_all = "snake_case")] +/// Represents the schema which needs to be sent to create a Guild Ban. +/// See: +pub struct GuildBanBulkCreateSchema { + pub user_ids: Vec, + pub delete_message_seconds: Option, +} + #[derive(Debug, Deserialize, Serialize, Default, Clone, Eq, PartialEq)] #[serde(rename_all = "snake_case")] /// Represents the schema used to modify a guild. @@ -119,6 +127,12 @@ impl Default for GuildMemberSearchSchema { } } +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Eq, Ord)] +pub struct GuildGetMembersQuery { + pub limit: Option, + pub after: Option, +} + #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Eq, Ord)] pub struct ModifyGuildMemberSchema { pub nick: Option, @@ -174,3 +188,200 @@ pub struct GuildBansQuery { pub after: Option, pub limit: Option, } + + +/// Max query length is 32 characters. +/// The limit argument is a number between 1 and 10, defaults to 10. +pub type GuildBansSearchQuery = GenericSearchQueryWithLimit; + +/// Query is partial or full, username or nickname. +/// Limit argument is a number between 1 and 1000, defaults to 1. +pub type GuildMembersSearchQuery = GenericSearchQueryWithLimit; + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +/// A guild's progress on meeting the requirements of joining discovery. +/// +/// Certain guilds, such as those that are verified, are exempt from discovery requirements. These guilds will not have a fully populated discovery requirements object, and are guaranteed to receive only sufficient and sufficient_without_grace_period. +/// +/// # Reference: +/// See +pub struct GuildDiscoveryRequirements { + pub guild_id: Option, + pub safe_environment: Option, + pub healthy: Option, + pub health_score_pending: Option, + pub size: Option, + pub nsfw_properties: Option, + pub protected: Option, + pub sufficient: Option, + pub sufficient_without_grace_period: Option, + pub valid_rules_channel: Option, + pub retention_healthy: Option, + pub engagement_healthy: Option, + pub age: Option, + pub minimum_age: Option, + pub health_score: Option, + pub minimum_size: Option, + pub grace_period_end_date: Option>, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// # Reference: +/// See +pub struct GuildDiscoveryNsfwProperties { + pub channels: Vec, + pub channel_banned_keywords: HashMap>, + pub name: Option, + pub name_banned_keywords: Vec, + pub description: Option, + pub description_banned_keywords: Vec, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +/// Activity metrics are recalculated weekly, as an 8-week rolling average. If they are not yet eligible to be calculated, all fields will be null. +/// +/// # Reference: +/// See +pub struct GuildDiscoveryHealthScore { + pub avg_nonnew_communicators: u64, + pub avg_nonnew_participators: u64, + pub num_intentful_joiners: u64, + pub perc_ret_w1_intentful: f64, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +/// # Reference: +/// See +pub struct EmojiCreateSchema { + pub name: Option, + /// # Reference: + /// See + pub image: String, + #[serde(default)] + pub roles: Vec +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +/// # Reference: +/// See +pub struct EmojiModifySchema { + pub name: Option, + pub roles: Option> +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +/// # Reference: +/// See +pub struct GuildPruneQuerySchema { + pub days: u8, + /// Only used on POST + #[serde(default, skip_serializing_if = "Option::is_none")] + pub compute_prune_count: Option, + #[serde(default)] + pub include_roles: Vec +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +/// # Reference: +/// See +pub struct GuildPruneResult { + /// Null if compute_prune_count is false + pub pruned: Option, +} + +#[derive(Default, Debug, Deserialize, Serialize, Clone, PartialEq)] +/// # Reference: +/// See +pub struct GuildCreateStickerSchema { + pub name: String, + #[serde(default)] + pub description: Option, + #[serde(default)] + pub tags: Option, + pub file_data: Vec, + #[serde(skip)] + pub sticker_format_type: StickerFormatType +} + +impl GuildCreateStickerSchema { + #[cfg(feature = "poem")] + pub async fn from_multipart(mut multipart: poem::web::Multipart) -> Result { + let mut _self = GuildCreateStickerSchema::default(); + while let Some(field) = multipart.next_field().await? { + let name = field.name().ok_or(poem::Error::from_string("All fields must be named", poem::http::StatusCode::BAD_REQUEST))?; + match name { + "name" => { + _self.name = field.text().await?; + } + "description" => { + _self.description = Some(field.text().await?); + } + "tags" => { + _self.tags = Some(field.text().await?); + } + "file_data" => { + if _self.name.is_empty() { + _self.name = field.file_name().map(String::from).ok_or(poem::Error::from_string("File name must be set", poem::http::StatusCode::BAD_REQUEST))?; + } + _self.sticker_format_type = StickerFormatType::from_mime(field.content_type().ok_or(poem::Error::from_string("Content type must be set", poem::http::StatusCode::BAD_REQUEST))?).ok_or(poem::Error::from_string("Unknown sticker format", poem::http::StatusCode::BAD_REQUEST))?; + _self.file_data = field.bytes().await?; + } + _ => {} + } + + } + if _self.name.is_empty() || _self.file_data.is_empty() { + return Err(poem::Error::from_string("At least the name and file_data are required", poem::http::StatusCode::BAD_REQUEST)); + } + + Ok(_self) + } + + // #[cfg(feature = "client")] + pub fn to_multipart(&self) -> reqwest::multipart::Form { + let mut form = reqwest::multipart::Form::new() + .text("name", self.name.clone()) + .part("file_data", reqwest::multipart::Part::bytes(self.file_data.clone()).mime_str(self.sticker_format_type.to_mime()).unwrap()); + + if let Some(description) = &self.description { + form = form.text("description", description.to_owned()); + } + + if let Some(tags) = &self.tags { + form = form.text("tags", tags.to_owned()) + } + form + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +/// # Reference: +/// See +pub struct GuildModifyStickerSchema { + #[serde(default)] + pub name: Option, + #[serde(default)] + pub description: Option, + #[serde(default)] + pub tags: Option +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +/// # Reference: +/// See +pub struct GuildModifyWelcomeScreenSchema { + pub enabled: Option, + pub description: Option, + /// Max of 5 + pub welcome_channels: Option>, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +/// # Reference: +/// See +pub struct GuildTemplateCreateSchema { + /// Name of the template (1-100 characters) + pub name: String, + /// Description of the template (max 120 characters) + pub description: Option +} \ No newline at end of file diff --git a/src/types/schema/invites.rs b/src/types/schema/invites.rs index 6bf2131a..542c990d 100644 --- a/src/types/schema/invites.rs +++ b/src/types/schema/invites.rs @@ -7,4 +7,20 @@ use serde::{Deserialize, Serialize}; /// Read: pub struct GetInvitesSchema { pub with_counts: Option, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Eq, Ord)] +/// # Reference: +/// See +pub struct GuildVanityInviteResponse { + pub code: String, + #[serde(default)] + pub uses: Option +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Eq, Ord)] +/// # Reference: +/// See +pub struct GuildCreateVanitySchema { + pub code: String, } \ No newline at end of file diff --git a/src/types/schema/message.rs b/src/types/schema/message.rs index 4a7f2ab8..4d50b25e 100644 --- a/src/types/schema/message.rs +++ b/src/types/schema/message.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::types::entities::{ AllowedMention, Component, Embed, MessageReference, PartialDiscordFileAttachment, }; -use crate::types::{Attachment, MessageFlags, MessageType, ReactionType, Snowflake}; +use crate::types::{Attachment, EmbedType, Message, MessageFlags, MessageType, ReactionType, Snowflake}; #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)] #[serde(rename_all = "snake_case")] @@ -54,13 +54,13 @@ pub struct MessageSearchQuery { pub attachment_extension: Option>, pub attachment_filename: Option>, pub author_id: Option>, - pub author_type: Option>, + pub author_type: Option>, pub channel_id: Option>, pub command_id: Option>, pub content: Option, pub embed_provider: Option>, - pub embed_type: Option>, - pub has: Option>, + pub embed_type: Option>, + pub has: Option>, pub include_nsfw: Option, pub limit: Option, pub link_hostname: Option>, @@ -70,8 +70,8 @@ pub struct MessageSearchQuery { pub min_id: Option, pub offset: Option, pub pinned: Option, - pub sort_by: Option, - pub sort_order: Option, + pub sort_by: Option, + pub sort_order: Option, } impl std::default::Default for MessageSearchQuery { @@ -102,6 +102,75 @@ impl std::default::Default for MessageSearchQuery { } } +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[serde(rename_all = "snake_case")] +pub enum AuthorType { + User, + #[serde(rename = "-user")] + NotUser, + Bot, + #[serde(rename = "-bot")] + NotBot, + Webhook, + #[serde(rename = "-webhook")] + NotWebhook, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[serde(rename_all = "snake_case")] +pub enum HasType { + Image, + #[serde(rename = "-image")] + NotImage, + Sound, + #[serde(rename = "-sound")] + NotSound, + Video, + #[serde(rename = "-video")] + NotVideo, + File, + #[serde(rename = "-file")] + NotFile, + Sticker, + #[serde(rename = "-sticker")] + NotSticker, + Embed, + #[serde(rename = "-embed")] + NotEmbed, + Link, + #[serde(rename = "-link")] + NotLink, + Poll, + #[serde(rename = "-poll")] + NotPoll, + Snapshot, + #[serde(rename = "-snapshot")] + NotSnapshot, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[serde(rename_all = "snake_case")] +pub enum SortType { + #[default] + Timestamp, + Relevance +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum SortOrder { + #[default] + #[serde(rename = "desc")] + Descending, + #[serde(rename = "asc")] + Ascending, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)] +pub struct MessageSearchResponse { + pub messages: Vec, + pub total_results: u64, +} + #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct CreateGreetMessage { pub sticker_ids: Vec, diff --git a/src/types/schema/mod.rs b/src/types/schema/mod.rs index ef3233db..09e542e4 100644 --- a/src/types/schema/mod.rs +++ b/src/types/schema/mod.rs @@ -3,6 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. pub use apierror::*; +pub use audit_log::*; pub use auth::*; pub use channel::*; pub use guild::*; @@ -11,8 +12,10 @@ pub use relationship::*; pub use role::*; pub use user::*; pub use invites::*; +pub use voice_state::*; mod apierror; +mod audit_log; mod auth; mod channel; mod guild; @@ -21,3 +24,10 @@ mod relationship; mod role; mod user; mod invites; +mod voice_state; + +#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq, PartialOrd, Eq, Ord)] +pub struct GenericSearchQueryWithLimit { + pub query: String, + pub limit: Option, +} \ No newline at end of file diff --git a/src/types/schema/role.rs b/src/types/schema/role.rs index 168d9992..5dce8773 100644 --- a/src/types/schema/role.rs +++ b/src/types/schema/role.rs @@ -3,6 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use serde::{Deserialize, Serialize}; +use crate::types::{PermissionFlags, Snowflake}; #[derive(Debug, Deserialize, Serialize, Clone)] #[serde(rename_all = "snake_case")] @@ -10,8 +11,8 @@ use serde::{Deserialize, Serialize}; /// See: [https://docs.spacebar.chat/routes/#cmp--schemas-rolemodifyschema](https://docs.spacebar.chat/routes/#cmp--schemas-rolemodifyschema) pub struct RoleCreateModifySchema { pub name: Option, - pub permissions: Option, - pub color: Option, + pub permissions: Option, + pub color: Option, pub hoist: Option, pub icon: Option>, pub unicode_emoji: Option, @@ -24,6 +25,6 @@ pub struct RoleCreateModifySchema { /// Represents the schema which needs to be sent to update a roles' position. /// See: [https://docs.spacebar.chat/routes/#cmp--schemas-rolepositionupdateschema](https://docs.spacebar.chat/routes/#cmp--schemas-rolepositionupdateschema) pub struct RolePositionUpdateSchema { - pub id: String, + pub id: Snowflake, pub position: u16, } diff --git a/src/types/schema/voice_state.rs b/src/types/schema/voice_state.rs new file mode 100644 index 00000000..d5576ad2 --- /dev/null +++ b/src/types/schema/voice_state.rs @@ -0,0 +1,15 @@ +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use crate::types::Snowflake; + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd)] +/// # Reference: +/// See +pub struct VoiceStateUpdateSchema { + /// The ID of the channel the user is currently in + pub channel_id: Option, + /// Whether to suppress the user + pub suppress: Option, + /// The time at which the user requested to speak + pub request_to_speak_timestamp: Option>, +} \ No newline at end of file diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 863e91f7..f2f0663e 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -5,7 +5,7 @@ use std::str::FromStr; use chorus::gateway::{Gateway, GatewayOptions}; -use chorus::types::IntoShared; +use chorus::types::{IntoShared, PermissionFlags}; use chorus::{ instance::{ChorusUser, Instance}, types::{ @@ -108,7 +108,7 @@ pub(crate) async fn setup() -> TestBundle { let role_create_schema: chorus::types::RoleCreateModifySchema = RoleCreateModifySchema { name: Some("Bundle role".to_string()), - permissions: Some("8".to_string()), // Administrator permissions + permissions: PermissionFlags::from_bits(8), // Administrator permissions hoist: Some(true), icon: None, unicode_emoji: Some("".to_string()), diff --git a/tests/gateway.rs b/tests/gateway.rs index 12626a6d..99911245 100644 --- a/tests/gateway.rs +++ b/tests/gateway.rs @@ -81,7 +81,7 @@ async fn test_gateway_authenticate() { } // Success, we have received it Some(_) = ready_receive.recv() => {} - }; + } common::teardown(bundle).await } @@ -125,7 +125,7 @@ async fn test_self_updating_structs() { .gateway .observe_and_into_inner(bundle.guild.clone()) .await; - assert!(guild.channels.is_none()); + assert!(guild.channels.is_empty()); Channel::create( &mut bundle.user, @@ -145,8 +145,8 @@ async fn test_self_updating_structs() { .gateway .observe_and_into_inner(guild.into_shared()) .await; - assert!(guild.channels.is_some()); - assert!(guild.channels.as_ref().unwrap().len() == 1); + assert!(!guild.channels.is_empty()); + assert_eq!(guild.channels.len(), 1); common::teardown(bundle).await } @@ -160,13 +160,12 @@ async fn test_recursive_self_updating_structs() { // Observe Guild, make sure it has no channels let guild = bundle.user.gateway.observe(guild.clone()).await; let inner_guild = guild.read().unwrap().clone(); - assert!(inner_guild.roles.is_none()); + assert!(inner_guild.roles.is_empty()); // Create Role let permissions = types::PermissionFlags::CONNECT | types::PermissionFlags::MANAGE_EVENTS; - let permissions = Some(permissions.to_string()); let mut role_create_schema: types::RoleCreateModifySchema = RoleCreateModifySchema { name: Some("cool person".to_string()), - permissions, + permissions: Some(permissions), hoist: Some(true), icon: None, unicode_emoji: Some("".to_string()), @@ -186,7 +185,7 @@ async fn test_recursive_self_updating_structs() { .await; // Update Guild and check for Guild let inner_guild = guild.read().unwrap().clone(); - assert!(inner_guild.roles.is_some()); + assert!(!inner_guild.roles.is_empty()); // Update the Role role_create_schema.name = Some("yippieee".to_string()); RoleObject::modify(&mut bundle.user, guild_id, role.id, role_create_schema) @@ -202,8 +201,7 @@ async fn test_recursive_self_updating_structs() { let guild = bundle.user.gateway.observe(bundle.guild.clone()).await; let inner_guild = guild.read().unwrap().clone(); let guild_roles = inner_guild.roles; - let guild_role = guild_roles.unwrap(); - let guild_role_inner = guild_role.get(0).unwrap().read().unwrap().clone(); + let guild_role_inner = guild_roles.get(0).unwrap().read().unwrap().clone(); assert_eq!(guild_role_inner.name, "yippieee".to_string()); common::teardown(bundle).await; } diff --git a/tests/roles.rs b/tests/roles.rs index 3246140b..faf27196 100644 --- a/tests/roles.rs +++ b/tests/roles.rs @@ -15,10 +15,9 @@ mod common; async fn create_and_get_roles() { let mut bundle = common::setup().await; let permissions = types::PermissionFlags::CONNECT | types::PermissionFlags::MANAGE_EVENTS; - let permissions = Some(permissions.to_string()); let role_create_schema: types::RoleCreateModifySchema = RoleCreateModifySchema { name: Some("cool person".to_string()), - permissions, + permissions: Some(permissions), hoist: Some(true), icon: None, unicode_emoji: Some("".to_string()), From d59161619c98877e4061af6870e1f7bcd655e68a Mon Sep 17 00:00:00 2001 From: Quat3rnion <81202811+Quat3rnion@users.noreply.github.com> Date: Thu, 27 Jun 2024 14:36:39 -0400 Subject: [PATCH 081/162] Add custom deserializer for PermissionOverwriteType (#512) * Add custom deserializer for PermissionOverwriteType --- src/types/entities/channel.rs | 67 +++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 044c1e2d..a42dadf4 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -3,14 +3,16 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use std::fmt::Debug; +use std::fmt::{Debug, Formatter}; +use std::str::FromStr; use crate::types::{ PermissionFlags, Shared, entities::{GuildMember, User}, utils::Snowflake, + serde::string_or_u64 }; #[cfg(feature = "client")] @@ -24,6 +26,8 @@ use crate::gateway::Updateable; #[cfg(feature = "client")] use chorus_macros::{observe_option_vec, Composite, Updateable}; +use serde::de::{Error, Visitor}; + #[derive(Default, Debug, Serialize, Deserialize, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -155,7 +159,7 @@ pub struct PermissionOverwrite { } -#[derive(Debug, Serialize_repr, Deserialize_repr, Clone, PartialEq, Eq, PartialOrd)] +#[derive(Debug, Serialize_repr, Clone, PartialEq, Eq, PartialOrd)] #[repr(u8)] /// # Reference pub enum PermissionOverwriteType { @@ -163,6 +167,63 @@ pub enum PermissionOverwriteType { Member = 1, } +impl From for PermissionOverwriteType { + fn from(v: u8) -> Self { + match v { + 0 => PermissionOverwriteType::Role, + 1 => PermissionOverwriteType::Member, + _ => unreachable!(), + } + } +} + +impl FromStr for PermissionOverwriteType { + type Err = serde::de::value::Error; + + fn from_str(s: &str) -> Result { + match s { + "role" => Ok(PermissionOverwriteType::Role), + "member" => Ok(PermissionOverwriteType::Member), + _ => Err(Self::Err::custom("invalid permission overwrite type")), + } + } +} + +struct PermissionOverwriteTypeVisitor; + +impl<'de> Visitor<'de> for PermissionOverwriteTypeVisitor { + type Value = PermissionOverwriteType; + + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("a valid permission overwrite type") + } + + fn visit_u8(self, v: u8) -> Result where E: Error { + Ok(PermissionOverwriteType::from(v)) + } + + fn visit_u64(self, v: u64) -> Result where E: Error { + self.visit_u8(v as u8) + } + + fn visit_str(self, v: &str) -> Result where E: Error { + PermissionOverwriteType::from_str(v) + .map_err(E::custom) + } + + fn visit_string(self, v: String) -> Result where E: Error { + self.visit_str(v.as_str()) + } +} + +impl<'de> Deserialize<'de> for PermissionOverwriteType { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { + let val = deserializer.deserialize_any(PermissionOverwriteTypeVisitor)?; + + Ok(val) + } +} + #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] /// # Reference /// See From 743f106ec6b0aa40ac7260e3fd5f261d3b7024bb Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Fri, 28 Jun 2024 14:05:59 +0200 Subject: [PATCH 082/162] Miscellaneous fixes (#514) - fix `PATCH /users/@me` - It incorrectly returned a required password error, even if the current password was set - fix `GET /users/@me/guilds` - It incorrectly sent body parameters instead of query ones - don't log debug! for every successful ratelimited request - use trace! so it's less spamy - update the max expected compression ratio (several times) from 20 to 200. let's hope that will be enough - fix deserialization errors relating to guild folders in user settings - fix a panic in `SqlxBitFlags` if there are extra flags. It now truncates them - update `chorus_macros` to 0.4.1 (due to the above fix) - log (trace!) event data if we fail to parse it or it's unrecognised, for debugging purposes - fix a deserialization error in the `MessageACK` event - fix `public_flags` in user objects not being `PublicFlags` bitflags --- Cargo.lock | 2 +- chorus-macros/Cargo.lock | 2 +- chorus-macros/Cargo.toml | 2 +- chorus-macros/src/lib.rs | 6 ++++-- src/api/users/guilds.rs | 12 +++++++++++- src/gateway/gateway.rs | 26 +++++++++++++++----------- src/gateway/message.rs | 9 ++++++++- src/ratelimiter.rs | 4 ++-- src/types/entities/channel.rs | 2 ++ src/types/entities/user.rs | 12 ++++++------ src/types/entities/user_settings.rs | 18 +++++++++++++----- src/types/events/message.rs | 4 ++-- src/types/events/passive_update.rs | 5 ++++- src/types/events/presence.rs | 1 + src/types/schema/guild.rs | 29 +++++++++++++++++++++++++++-- 15 files changed, 98 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f967a21f..4a7d6ea2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -266,7 +266,7 @@ dependencies = [ [[package]] name = "chorus-macros" -version = "0.4.0" +version = "0.4.1" dependencies = [ "async-trait", "quote", diff --git a/chorus-macros/Cargo.lock b/chorus-macros/Cargo.lock index a3eedd4a..e74f64c3 100644 --- a/chorus-macros/Cargo.lock +++ b/chorus-macros/Cargo.lock @@ -15,7 +15,7 @@ dependencies = [ [[package]] name = "chorus-macros" -version = "0.4.0" +version = "0.4.1" dependencies = [ "async-trait", "quote", diff --git a/chorus-macros/Cargo.toml b/chorus-macros/Cargo.toml index c81cc90d..6aa416a1 100644 --- a/chorus-macros/Cargo.toml +++ b/chorus-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chorus-macros" -version = "0.4.0" +version = "0.4.1" edition = "2021" license = "MPL-2.0" description = "Macros for the chorus crate." diff --git a/chorus-macros/src/lib.rs b/chorus-macros/src/lib.rs index 4102039a..aa4f1bc9 100644 --- a/chorus-macros/src/lib.rs +++ b/chorus-macros/src/lib.rs @@ -214,9 +214,11 @@ pub fn serde_bitflag_derive(input: TokenStream) -> TokenStream { // let s = String::deserialize(deserializer)?.parse::().map_err(serde::de::Error::custom)?; let s = crate::types::serde::string_or_u64(deserializer)?; - Ok(Self::from_bits(s).unwrap()) + // Note: while truncating may not be ideal, it's better than a panic if there are + // extra flags + Ok(Self::from_bits_truncate(s)) } } } .into() -} \ No newline at end of file +} diff --git a/src/api/users/guilds.rs b/src/api/users/guilds.rs index aac2f7ad..46a25fb6 100644 --- a/src/api/users/guilds.rs +++ b/src/api/users/guilds.rs @@ -44,6 +44,16 @@ impl ChorusUser { &mut self, query: Option, ) -> ChorusResult> { + + let query_parameters = { + if let Some(query_some) = query { + query_some.to_query() + } + else { + Vec::new() + } + }; + let url = format!( "{}/users/@me/guilds", self.belongs_to.read().unwrap().urls.api, @@ -53,7 +63,7 @@ impl ChorusUser { .get(url) .header("Authorization", self.token()) .header("Content-Type", "application/json") - .body(to_string(&query).unwrap()), + .query(&query_parameters), limit_type: LimitType::Global, }; diff --git a/src/gateway/gateway.rs b/src/gateway/gateway.rs index ec42b300..1312137b 100644 --- a/src/gateway/gateway.rs +++ b/src/gateway/gateway.rs @@ -90,13 +90,15 @@ impl Gateway { zlib_buffer = Some(Vec::new()); let mut inflate = Decompress::new(true); - message = GatewayMessage::from_zlib_stream_json_message(received, &mut inflate).unwrap(); + message = + GatewayMessage::from_zlib_stream_json_message(received, &mut inflate).unwrap(); zlib_inflate = Some(inflate); } } - let gateway_payload: types::GatewayReceivePayload = serde_json::from_str(&message.0).unwrap(); + let gateway_payload: types::GatewayReceivePayload = + serde_json::from_str(&message.0).unwrap(); if gateway_payload.op_code != GATEWAY_HELLO { return Err(GatewayError::NonHelloOnInitiate { @@ -232,7 +234,8 @@ impl Gateway { let zlib_buffer = self.zlib_buffer.as_ref().unwrap(); let inflate = self.zlib_inflate.as_mut().unwrap(); - message = GatewayMessage::from_zlib_stream_json_bytes(zlib_buffer, inflate).unwrap(); + message = + GatewayMessage::from_zlib_stream_json_bytes(zlib_buffer, inflate).unwrap(); self.zlib_buffer = Some(Vec::new()); } }; @@ -278,7 +281,10 @@ impl Gateway { let event = &mut self.events.lock().await.$($path).+; let json = gateway_payload.event_data.unwrap().get(); match serde_json::from_str(json) { - Err(err) => warn!("Failed to parse gateway event {event_name} ({err})"), + Err(err) => { + warn!("Failed to parse gateway event {event_name} ({err})"); + trace!("Event data: {json}"); + }, Ok(message) => { $( let mut message: $message_type = message; @@ -314,15 +320,12 @@ impl Gateway { },)* "RESUMED" => (), "SESSIONS_REPLACE" => { - let result: Result, serde_json::Error> = - serde_json::from_str(gateway_payload.event_data.unwrap().get()); + let json = gateway_payload.event_data.unwrap().get(); + let result: Result, serde_json::Error> = serde_json::from_str(json); match result { Err(err) => { - warn!( - "Failed to parse gateway event {} ({})", - event_name, - err - ); + warn!("Failed to parse gateway event {event_name} ({err})"); + trace!("Event data: {json}"); return; } Ok(sessions) => { @@ -334,6 +337,7 @@ impl Gateway { }, _ => { warn!("Received unrecognized gateway event ({event_name})! Please open an issue on the chorus github so we can implement it"); + trace!("Event data: {}", gateway_payload.event_data.unwrap().get()); } } }; diff --git a/src/gateway/message.rs b/src/gateway/message.rs index 7f581e5b..7d44af6b 100644 --- a/src/gateway/message.rs +++ b/src/gateway/message.rs @@ -94,7 +94,14 @@ impl GatewayMessage { // Note: is there a better way to handle the size of this output buffer? // // This used to be 10, I measured it at 11.5, so a safe bet feels like 20 - let mut output = Vec::with_capacity(bytes.len() * 20); + // + // ^ - This dude is naive. apparently not even 20x is okay. Measured at 47.9x!!!! + // If it is >100x ever, I will literally explode + // + // About an hour later, you ^ will literally explode. + // 133 vs 13994 -- 105.21805x ratio + // Let's hope it doesn't go above 200?? + let mut output = Vec::with_capacity(bytes.len() * 200); let _status = inflate.decompress_vec(bytes, &mut output, flate2::FlushDecompress::Sync)?; output.shrink_to_fit(); diff --git a/src/ratelimiter.rs b/src/ratelimiter.rs index 5e69d950..2b080829 100644 --- a/src/ratelimiter.rs +++ b/src/ratelimiter.rs @@ -88,7 +88,7 @@ impl ChorusRequest { let client = user.belongs_to.read().unwrap().client.clone(); let result = match client.execute(self.request.build().unwrap()).await { Ok(result) => { - debug!("Request successful: {:?}", result); + log::trace!("Request successful: {:?}", result); result } Err(error) => { @@ -494,7 +494,7 @@ impl ChorusRequest { user: &mut ChorusUser, ) -> ChorusResult { let response = self.send_request(user).await?; - debug!("Got response: {:?}", response); + log::trace!("Got response: {:?}", response); let response_text = match response.text().await { Ok(string) => string, Err(e) => { diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index a42dadf4..19bdcef6 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -162,6 +162,8 @@ pub struct PermissionOverwrite { #[derive(Debug, Serialize_repr, Clone, PartialEq, Eq, PartialOrd)] #[repr(u8)] /// # Reference +/// +/// See pub enum PermissionOverwriteType { Role = 0, Member = 1, diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index c7e60b30..81978b05 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -45,7 +45,7 @@ pub struct User { pub bot: Option, pub system: Option, pub mfa_enabled: Option, - pub accent_color: Option, + pub accent_color: Option, #[cfg_attr(feature = "sqlx", sqlx(default))] pub locale: Option, pub verified: Option, @@ -58,10 +58,10 @@ pub struct User { pub premium_since: Option>, pub premium_type: Option, pub pronouns: Option, - pub public_flags: Option, + pub public_flags: Option, pub banner: Option, pub bio: Option, - pub theme_colors: Option>, + pub theme_colors: Option>, pub phone: Option, pub nsfw_allowed: Option, pub premium: Option, @@ -76,15 +76,15 @@ pub struct PublicUser { pub username: Option, pub discriminator: Option, pub avatar: Option, - pub accent_color: Option, + pub accent_color: Option, pub banner: Option, - pub theme_colors: Option>, + pub theme_colors: Option>, pub pronouns: Option, pub bot: Option, pub bio: Option, pub premium_type: Option, pub premium_since: Option>, - pub public_flags: Option, + pub public_flags: Option, } impl From for PublicUser { diff --git a/src/types/entities/user_settings.rs b/src/types/entities/user_settings.rs index 0dbce3e5..fa3433af 100644 --- a/src/types/entities/user_settings.rs +++ b/src/types/entities/user_settings.rs @@ -6,6 +6,7 @@ use chrono::{serde::ts_milliseconds_option, Utc}; use serde::{Deserialize, Serialize}; use crate::types::Shared; +use serde_aux::field_attributes::deserialize_option_number_from_string; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] @@ -37,7 +38,7 @@ pub enum UserTheme { #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct UserSettings { - pub afk_timeout: u16, + pub afk_timeout: Option, pub allow_accessibility_detection: bool, pub animate_emoji: bool, pub animate_stickers: u8, @@ -90,7 +91,7 @@ pub struct UserSettings { impl Default for UserSettings { fn default() -> Self { Self { - afk_timeout: 3600, + afk_timeout: Some(3600), allow_accessibility_detection: true, animate_emoji: true, animate_stickers: 0, @@ -148,10 +149,17 @@ impl Default for FriendSourceFlags { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct GuildFolder { - pub color: u32, + pub color: Option, pub guild_ids: Vec, - pub id: u16, - pub name: String, + // FIXME: What is this thing? + // It's not a snowflake, and it's sometimes a string and sometimes an integer. + // + // Ex: 1249181105 + // + // It can also be negative somehow? Ex: -1176643795 + #[serde(deserialize_with = "deserialize_option_number_from_string")] + pub id: Option, + pub name: Option, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/types/events/message.rs b/src/types/events/message.rs index 8f982e55..62a9d9d9 100644 --- a/src/types/events/message.rs +++ b/src/types/events/message.rs @@ -121,8 +121,8 @@ pub struct MessageReactionRemoveEmoji { /// /// {"t":"MESSAGE_ACK","s":3,"op":0,"d":{"version":52,"message_id":"1107236673638633472","last_viewed":null,"flags":null,"channel_id":"967363950217936897"}} pub struct MessageACK { - /// ? - pub version: u16, + // No ideas. See 206933 + pub version: u32, pub message_id: Snowflake, /// This is an integer??? /// Not even unix, see '3070'??? diff --git a/src/types/events/passive_update.rs b/src/types/events/passive_update.rs index a0f99091..088fb229 100644 --- a/src/types/events/passive_update.rs +++ b/src/types/events/passive_update.rs @@ -12,9 +12,12 @@ use crate::types::{GuildMember, Snowflake, VoiceState}; /// /// Seems to be passively set to update the client on guild details (though, why not just send the update events?) pub struct PassiveUpdateV1 { + #[serde(default)] pub voice_states: Vec, - pub members: Option>, + #[serde(default)] + pub members: Vec, pub guild_id: Snowflake, + #[serde(default)] pub channels: Vec, } diff --git a/src/types/events/presence.rs b/src/types/events/presence.rs index 09d07390..d96d984f 100644 --- a/src/types/events/presence.rs +++ b/src/types/events/presence.rs @@ -28,6 +28,7 @@ pub struct PresenceUpdate { #[serde(default)] pub guild_id: Option, pub status: UserStatus, + #[serde(default)] pub activities: Vec, pub client_status: ClientStatusObject, } diff --git a/src/types/schema/guild.rs b/src/types/schema/guild.rs index 17c9d616..6405d946 100644 --- a/src/types/schema/guild.rs +++ b/src/types/schema/guild.rs @@ -85,6 +85,31 @@ pub struct GetUserGuildSchema { pub with_counts: Option, } +impl GetUserGuildSchema { + /// Converts self to query string parameters + pub fn to_query(self) -> Vec<(&'static str, String)> { + let mut query = Vec::with_capacity(4); + + if let Some(before) = self.before { + query.push(("before", before.to_string())); + } + + if let Some(after) = self.after { + query.push(("after", after.to_string())); + } + + if let Some(limit) = self.limit { + query.push(("limit", limit.to_string())); + } + + if let Some(with_counts) = self.with_counts { + query.push(("with_counts", with_counts.to_string())); + } + + query + } +} + impl std::default::Default for GetUserGuildSchema { fn default() -> Self { Self { @@ -145,7 +170,7 @@ pub struct ModifyGuildMemberSchema { } bitflags! { - #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)] + #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, chorus_macros::SerdeBitFlags)] #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] /// Represents the flags of a Guild Member. /// @@ -384,4 +409,4 @@ pub struct GuildTemplateCreateSchema { pub name: String, /// Description of the template (max 120 characters) pub description: Option -} \ No newline at end of file +} From 484c69229dfe77d16a2afbe11ba9134adb25af46 Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Sat, 13 Jul 2024 08:31:45 +0200 Subject: [PATCH 083/162] No openssl (#522) * Remove openssl from some packages' deps * Add shorthand wasm build script * Eliminate openssl dependency from crate * Build RootCertStore from webpki roots instead of native roots * Expand wasm documentation * Revert reqwest * Lock reqwest at 0.11.23 * Lock reqwest at 0.11.26, latest possible version * Add wasm test script --- Cargo.lock | 866 ++++++++++++---------------- Cargo.toml | 24 +- README.md | 20 +- build-wasm.sh | 6 + src/gateway/backends/tungstenite.rs | 30 +- test-wasm.sh | 6 + 6 files changed, 439 insertions(+), 513 deletions(-) create mode 100755 build-wasm.sh create mode 100755 test-wasm.sh diff --git a/Cargo.lock b/Cargo.lock index 4a7d6ea2..2d4655ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -29,9 +29,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom", @@ -42,18 +42,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "android-tzdata" @@ -72,13 +72,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.70", ] [[package]] @@ -107,27 +107,17 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "atomic-write-file" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" -dependencies = [ - "nix 0.27.1", - "rand", -] - [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -150,6 +140,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64ct" version = "1.6.0" @@ -164,9 +160,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -182,9 +178,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" @@ -194,18 +190,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.83" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8" [[package]] name = "cfg-if" @@ -225,7 +218,7 @@ version = "0.15.0" dependencies = [ "async-trait", "base64 0.21.7", - "bitflags 2.4.1", + "bitflags 2.6.0", "chorus-macros", "chrono", "crypto_secretbox", @@ -235,17 +228,15 @@ dependencies = [ "futures-util", "getrandom", "hostname", - "http 0.2.11", + "http 0.2.12", "jsonwebtoken", "lazy_static", "log", - "native-tls", "poem", "rand", "regex", "reqwest", "rustls", - "rustls-native-certs", "serde", "serde-aux", "serde_json", @@ -261,6 +252,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-bindgen-test", "wasmtimer", + "webpki-roots 0.26.3", "ws_stream_wasm", ] @@ -270,14 +262,14 @@ version = "0.4.1" dependencies = [ "async-trait", "quote", - "syn 2.0.48", + "syn 2.0.70", ] [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -285,7 +277,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -342,9 +334,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.0.1" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" dependencies = [ "crc-catalog", ] @@ -375,9 +367,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-common" @@ -413,9 +405,9 @@ checksum = "4f8a51dd197fa6ba5b4dc98a990a43cc13693c23eb0089ebb0fcc1f04152bca6" [[package]] name = "darling" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -423,40 +415,40 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.48", + "syn 2.0.70", ] [[package]] name = "darling_macro" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.48", + "syn 2.0.70", ] [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "pem-rfc7468", @@ -503,18 +495,18 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "either" -version = "1.9.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" dependencies = [ "serde", ] [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] @@ -527,9 +519,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -554,15 +546,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "finl_unicode" -version = "1.2.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "flate2" @@ -591,21 +577,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -682,7 +653,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.70", ] [[package]] @@ -728,9 +699,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", @@ -741,9 +712,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "h2" @@ -756,8 +727,8 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.11", - "indexmap 2.1.0", + "http 0.2.12", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -776,7 +747,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.1.0", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -791,9 +762,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", @@ -805,7 +776,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -843,9 +814,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -893,9 +864,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -920,7 +891,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http 0.2.11", + "http 0.2.12", "pin-project-lite", ] @@ -936,12 +907,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http 1.1.0", "http-body 1.0.0", "pin-project-lite", @@ -949,9 +920,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -961,16 +932,16 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", "h2 0.3.26", - "http 0.2.11", + "http 0.2.12", "http-body 0.4.6", "httparse", "httpdate", @@ -985,9 +956,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.3.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", @@ -1004,38 +975,39 @@ dependencies = [ ] [[package]] -name = "hyper-tls" -version = "0.5.0" +name = "hyper-rustls" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ - "bytes", - "hyper 0.14.28", - "native-tls", + "futures-util", + "http 0.2.12", + "hyper 0.14.30", + "rustls", "tokio", - "tokio-native-tls", + "tokio-rustls", ] [[package]] name = "hyper-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" +checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" dependencies = [ "bytes", "futures-util", "http 1.1.0", "http-body 1.0.0", - "hyper 1.3.1", + "hyper 1.4.1", "pin-project-lite", "tokio", ] [[package]] name = "iana-time-zone" -version = "0.1.59" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1083,12 +1055,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "serde", ] @@ -1116,20 +1088,11 @@ dependencies = [ "serde", ] -[[package]] -name = "itertools" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" -dependencies = [ - "either", -] - [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" @@ -1156,11 +1119,11 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin 0.5.2", + "spin 0.9.8", ] [[package]] @@ -1188,15 +1151,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1204,9 +1167,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "match_cfg" @@ -1226,9 +1189,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mime" @@ -1238,9 +1201,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", @@ -1254,9 +1217,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] @@ -1290,42 +1253,13 @@ dependencies = [ "version_check", ] -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags 2.4.1", - "cfg-if", - "libc", -] - [[package]] name = "nix" version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "cfg-if", "cfg_aliases", "libc", @@ -1349,11 +1283,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -1375,21 +1308,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -1398,9 +1336,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -1418,9 +1356,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" dependencies = [ "memchr", ] @@ -1433,59 +1371,15 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "openssl" -version = "0.10.62" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" -dependencies = [ - "bitflags 2.4.1", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.98" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1493,22 +1387,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.2", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pem" @@ -1546,9 +1440,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1579,9 +1473,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "pnet_base" @@ -1624,11 +1518,11 @@ dependencies = [ "headers", "http 1.1.0", "http-body-util", - "hyper 1.3.1", + "hyper 1.4.1", "hyper-util", "mime", "multer", - "nix 0.28.0", + "nix", "parking_lot", "percent-encoding", "pin-project-lite", @@ -1639,7 +1533,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "sync_wrapper", + "sync_wrapper 1.0.1", "thiserror", "tokio", "tokio-util", @@ -1656,7 +1550,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.70", ] [[package]] @@ -1693,18 +1587,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.76" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1748,11 +1642,20 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "regex" -version = "1.10.2" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", @@ -1762,9 +1665,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -1773,15 +1676,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" -version = "0.11.23" +version = "0.11.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +checksum = "78bf93c4af7a8bb7d879d51cebe797356ff10ae8516ace542b5182d9dcac10b2" dependencies = [ "base64 0.21.7", "bytes", @@ -1789,38 +1692,41 @@ dependencies = [ "futures-core", "futures-util", "h2 0.3.26", - "http 0.2.11", + "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.28", - "hyper-tls", + "hyper 0.14.30", + "hyper-rustls", "ipnet", "js-sys", "log", "mime", "mime_guess", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", + "rustls", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper 0.1.2", "system-configuration", "tokio", - "tokio-native-tls", + "tokio-rustls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots 0.25.4", "winreg", ] [[package]] name = "rfc7239" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "087317b3cf7eb481f13bd9025d729324b7cd068d6f470e2d76d049e191f5ba47" +checksum = "b106a85eeb5b0336d16d6a20eab857f92861d4fbb1eb9a239866fb98fb6a1063" dependencies = [ "uncased", ] @@ -1842,16 +1748,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1876,9 +1783,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc_version" @@ -1891,11 +1798,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -1904,28 +1811,16 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.11" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring 0.17.7", + "ring 0.17.8", "rustls-webpki", "sct", ] -[[package]] -name = "rustls-native-certs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework", -] - [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -1935,21 +1830,27 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + [[package]] name = "rustls-webpki" version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "salsa20" @@ -1960,15 +1861,6 @@ dependencies = [ "cipher", ] -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "scoped-tls" version = "1.0.1" @@ -1987,38 +1879,15 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "send_wrapper" @@ -2028,18 +1897,18 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.195" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde-aux" -version = "4.3.1" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "184eba62ebddb71658697c8b08822edee89970bf318c5362189f0de27f85b498" +checksum = "0d2e8bfba469d06512e11e3311d4d051a4a387a5b42d010404fecf3200321c95" dependencies = [ "chrono", "serde", @@ -2048,20 +1917,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.70", ] [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", @@ -2070,13 +1939,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.70", ] [[package]] @@ -2093,16 +1962,17 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.4.0" +version = "3.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" +checksum = "e73139bc5ec2d45e6c5fd85be5a46949c1c39a4c18e56915f5eb4c12f975e377" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.1.0", + "indexmap 2.2.6", "serde", + "serde_derive", "serde_json", "serde_with_macros", "time", @@ -2110,14 +1980,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.4.0" +version = "3.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" +checksum = "b80d3d6b56b64335c0180e5ffde23b3c5e08c14c585b51a15bd0e95393f46703" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.70", ] [[package]] @@ -2191,12 +2061,12 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2226,20 +2096,19 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" +checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f" dependencies = [ - "itertools", "nom", "unicode_categories", ] [[package]] name = "sqlx" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" +checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2250,9 +2119,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" +checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" dependencies = [ "ahash", "atoi", @@ -2261,7 +2130,6 @@ dependencies = [ "chrono", "crc", "crossbeam-queue", - "dotenvy", "either", "event-listener", "futures-channel", @@ -2271,14 +2139,15 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.1.0", + "indexmap 2.2.6", "ipnetwork", "log", "memchr", - "native-tls", "once_cell", "paste", "percent-encoding", + "rustls", + "rustls-pemfile", "serde", "serde_json", "sha2", @@ -2289,13 +2158,14 @@ dependencies = [ "tokio-stream", "tracing", "url", + "webpki-roots 0.25.4", ] [[package]] name = "sqlx-macros" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" +checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" dependencies = [ "proc-macro2", "quote", @@ -2306,11 +2176,10 @@ dependencies = [ [[package]] name = "sqlx-macros-core" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841" +checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" dependencies = [ - "atomic-write-file", "dotenvy", "either", "heck", @@ -2333,13 +2202,13 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" +checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" dependencies = [ "atoi", "base64 0.21.7", - "bitflags 2.4.1", + "bitflags 2.6.0", "byteorder", "bytes", "chrono", @@ -2376,13 +2245,13 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" +checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" dependencies = [ "atoi", "base64 0.21.7", - "bitflags 2.4.1", + "bitflags 2.6.0", "byteorder", "chrono", "crc", @@ -2405,7 +2274,6 @@ dependencies = [ "rand", "serde", "serde_json", - "sha1", "sha2", "smallvec", "sqlx-core", @@ -2417,9 +2285,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" +checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" dependencies = [ "atoi", "chrono", @@ -2441,26 +2309,26 @@ dependencies = [ [[package]] name = "stringprep" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" dependencies = [ - "finl_unicode", "unicode-bidi", "unicode-normalization", + "unicode-properties", ] [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -2475,15 +2343,21 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "sync_wrapper" version = "1.0.1" @@ -2516,45 +2390,45 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.9.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", "rustix", "windows-sys 0.52.0", ] [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.70", ] [[package]] name = "time" -version = "0.3.31" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", + "num-conv", "powerfmt", "serde", "time-core", @@ -2569,18 +2443,19 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -2593,9 +2468,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.1" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -2610,23 +2485,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", + "syn 2.0.70", ] [[package]] @@ -2641,9 +2506,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -2659,24 +2524,23 @@ dependencies = [ "futures-util", "log", "rustls", - "rustls-native-certs", "tokio", "tokio-rustls", "tungstenite", + "webpki-roots 0.25.4", ] [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -2691,7 +2555,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.6", "toml_datetime", "winnow", ] @@ -2722,7 +2586,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.70", ] [[package]] @@ -2749,7 +2613,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 0.2.11", + "http 0.2.12", "httparse", "log", "rand", @@ -2768,9 +2632,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "uncased" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b9bc53168a4be7402ab86c3aad243a84dd7381d09be0eddc81280c1da95ca68" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" dependencies = [ "version_check", ] @@ -2786,9 +2650,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -2798,18 +2662,24 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-properties" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" + [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode_categories" @@ -2841,9 +2711,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -2916,7 +2786,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.70", "wasm-bindgen-shared", ] @@ -2950,7 +2820,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.70", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2983,7 +2853,7 @@ checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.70", ] [[package]] @@ -3002,29 +2872,44 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.66" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "webpki-roots" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "whoami" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fec781d48b41f8163426ed18e8fc2864c12937df9ce54c88ede7bd47270893e" +checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" dependencies = [ - "redox_syscall", + "redox_syscall 0.4.1", "wasite", ] [[package]] name = "wildmatch" -version = "2.3.0" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495ec47bf3c1345005f40724f0269362c8556cbc43aed0526ed44cae1d35fceb" +checksum = "3928939971918220fed093266b809d1ee4ec6c1a2d72692ff6876898f3b16c19" [[package]] name = "winapi" @@ -3054,7 +2939,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", ] [[package]] @@ -3072,7 +2957,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", ] [[package]] @@ -3092,17 +2977,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -3113,9 +2999,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -3125,9 +3011,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -3137,9 +3023,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -3149,9 +3041,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -3161,9 +3053,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -3173,9 +3065,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -3185,15 +3077,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.34" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] @@ -3229,26 +3121,26 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.70", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml index f2e5f12f..003de18e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,13 +28,17 @@ serde_json = { version = "1.0.111", features = ["raw_value"] } serde-aux = "4.3.1" serde_with = "3.4.0" serde_repr = "0.1.18" -reqwest = { features = ["multipart", "json"], version = "0.11.23" } +reqwest = { features = [ + "multipart", + "json", + "rustls-tls-webpki-roots", +], version = "=0.11.26", default-features = false } url = "2.5.0" chrono = { version = "0.4.31", features = ["serde"] } regex = "1.10.2" custom_error = "1.9.2" futures-util = "0.3.30" -http = "0.2.11" +http = "0.2.12" base64 = "0.21.7" bitflags = { version = "2.4.1", features = ["serde"] } lazy_static = "1.4.0" @@ -50,22 +54,24 @@ sqlx = { version = "0.7.3", features = [ "json", "chrono", "ipnetwork", - "runtime-tokio-native-tls", + "runtime-tokio-rustls", "any", ], optional = true } -discortp = { version = "0.5.0", optional = true, features = ["rtp", "discord", "demux"] } +discortp = { version = "0.5.0", optional = true, features = [ + "rtp", + "discord", + "demux", +] } crypto_secretbox = { version = "0.1.1", optional = true } rand = "0.8.5" flate2 = { version = "1.0.30", optional = true } +webpki-roots = "0.26.3" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] rustls = "0.21.10" -rustls-native-certs = "0.6.3" tokio-tungstenite = { version = "0.20.1", features = [ - "rustls-tls-native-roots", - "rustls-native-certs", + "rustls-tls-webpki-roots", ] } -native-tls = "0.2.11" hostname = "0.3.1" getrandom = { version = "0.2.12" } @@ -79,4 +85,4 @@ wasmtimer = "0.2.0" lazy_static = "1.4.0" wasm-bindgen-test = "0.3.42" wasm-bindgen = "0.2.92" -simple_logger = { version = "5.0.0", default-features=false } +simple_logger = { version = "5.0.0", default-features = false } diff --git a/README.md b/README.md index dc492304..bde7f652 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,25 @@ All major desktop operating systems (Windows, macOS (aarch64/x86_64), Linux (aar `wasm32-unknown-unknown` is a supported compilation target on versions `0.12.0` and up. This allows you to use Chorus in your browser, or in any other environment that supports WebAssembly. -We recommend checking out the examples directory, as well as the documentation for more information. +To compile for `wasm32-unknown-unknown`, execute the following command: + +```sh +cargo build --target=wasm32-unknown-unknown --no-default-features +``` + +The following features are supported on `wasm32-unknown-unknown`: + +| Feature | WASM Support | +| ----------------- | ------------ | +| `client` | ✅ | +| `rt` | ✅ | +| `rt-multi-thread` | ❌ | +| `backend` | ❌ | +| `voice` | ❌ | +| `voice_udp` | ❌ | +| `voice_gateway` | ✅ | + +We recommend checking out the "examples" directory, as well as the documentation for more information. ## MSRV (Minimum Supported Rust Version) diff --git a/build-wasm.sh b/build-wasm.sh new file mode 100755 index 00000000..85c55c3c --- /dev/null +++ b/build-wasm.sh @@ -0,0 +1,6 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +#!/bin/sh + +cargo build --no-default-features --target=wasm32-unknown-unknown "$@" \ No newline at end of file diff --git a/src/gateway/backends/tungstenite.rs b/src/gateway/backends/tungstenite.rs index f4425cda..7e007719 100644 --- a/src/gateway/backends/tungstenite.rs +++ b/src/gateway/backends/tungstenite.rs @@ -32,17 +32,19 @@ impl TungsteniteBackend { pub async fn connect( websocket_url: &str, ) -> Result<(TungsteniteSink, TungsteniteStream), TungsteniteBackendError> { - let mut roots = rustls::RootCertStore::empty(); - let certs = rustls_native_certs::load_native_certs(); - - if let Err(e) = certs { - log::error!("Failed to load platform native certs! {:?}", e); - return Err(TungsteniteBackendError::FailedToLoadCerts { error: e }); - } - - for cert in certs.unwrap() { - roots.add(&rustls::Certificate(cert.0)).unwrap(); - } + let certs = webpki_roots::TLS_SERVER_ROOTS; + let roots = rustls::RootCertStore { + roots: certs + .iter() + .map(|cert| { + rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( + cert.subject.to_vec(), + cert.subject_public_key_info.to_vec(), + cert.name_constraints.as_ref().map(|der| der.to_vec()), + ) + }) + .collect(), + }; let (websocket_stream, _) = match connect_async_tls_with_config( websocket_url, None, @@ -58,11 +60,7 @@ impl TungsteniteBackend { .await { Ok(websocket_stream) => websocket_stream, - Err(e) => { - return Err(TungsteniteBackendError::TungsteniteError { - error: e, - }) - } + Err(e) => return Err(TungsteniteBackendError::TungsteniteError { error: e }), }; Ok(websocket_stream.split()) diff --git a/test-wasm.sh b/test-wasm.sh new file mode 100755 index 00000000..ca803ef7 --- /dev/null +++ b/test-wasm.sh @@ -0,0 +1,6 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +#!/bin/sh + +wasm-pack test --firefox --headless -- --no-default-features --target=wasm32-unknown-unknown "$@" \ No newline at end of file From 7554f9018705145a0a5202c26d3a15ba8c57c664 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 13 Jul 2024 14:28:22 +0200 Subject: [PATCH 084/162] Replace `Observer` and `GatewayEvent` with `pubserve` crate --- Cargo.lock | 10 +++ Cargo.toml | 1 + examples/gateway_observers.rs | 8 +- src/gateway/events.rs | 154 +++++++++++++++++----------------- src/gateway/gateway.rs | 17 ++-- src/gateway/mod.rs | 53 ------------ src/voice/gateway/events.rs | 22 ++--- src/voice/gateway/gateway.rs | 6 +- src/voice/udp/events.rs | 4 +- src/voice/udp/handler.rs | 4 +- tests/gateway.rs | 11 ++- 11 files changed, 129 insertions(+), 161 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d4655ab..91c5f986 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -233,6 +233,7 @@ dependencies = [ "lazy_static", "log", "poem", + "pubserve", "rand", "regex", "reqwest", @@ -1594,6 +1595,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pubserve" +version = "1.1.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1781b2a51798c98a381e839e61bc5ce6426bd89bb9c3f9142de2086a80591cd" +dependencies = [ + "async-trait", +] + [[package]] name = "quote" version = "1.0.36" diff --git a/Cargo.toml b/Cargo.toml index 003de18e..ad0795cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,6 +66,7 @@ crypto_secretbox = { version = "0.1.1", optional = true } rand = "0.8.5" flate2 = { version = "1.0.30", optional = true } webpki-roots = "0.26.3" +pubserve = { version = "1.1.0-alpha.1", features = ["async", "send"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] rustls = "0.21.10" diff --git a/examples/gateway_observers.rs b/examples/gateway_observers.rs index 17390b6d..96bd56b2 100644 --- a/examples/gateway_observers.rs +++ b/examples/gateway_observers.rs @@ -17,9 +17,9 @@ use async_trait::async_trait; use chorus::gateway::{Gateway, GatewayOptions}; use chorus::{ self, - gateway::Observer, types::{GatewayIdentifyPayload, GatewayReady}, }; +use pubserve::Subscriber; use std::{sync::Arc, time::Duration}; use tokio::{self}; @@ -38,7 +38,7 @@ pub struct ExampleObserver {} // The Observer trait can be implemented for a struct for a given websocketevent to handle observing it // One struct can be an observer of multiple websocketevents, if needed #[async_trait] -impl Observer for ExampleObserver { +impl Subscriber for ExampleObserver { // After we subscribe to an event this function is called every time we receive it async fn update(&self, _data: &GatewayReady) { println!("Observed Ready!"); @@ -56,7 +56,9 @@ async fn main() { let options = GatewayOptions::default(); // Initiate the gateway connection - let gateway = Gateway::spawn(gateway_websocket_url, options).await.unwrap(); + let gateway = Gateway::spawn(gateway_websocket_url, options) + .await + .unwrap(); // Create an instance of our observer let observer = ExampleObserver {}; diff --git a/src/gateway/events.rs b/src/gateway/events.rs index 8d38cca1..049434be 100644 --- a/src/gateway/events.rs +++ b/src/gateway/events.rs @@ -2,6 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use pubserve::Publisher; + use super::*; use crate::types; @@ -23,144 +25,144 @@ pub struct Events { pub call: Call, pub voice: Voice, pub webhooks: Webhooks, - pub gateway_identify_payload: GatewayEvent, - pub gateway_resume: GatewayEvent, - pub error: GatewayEvent, + pub gateway_identify_payload: Publisher, + pub gateway_resume: Publisher, + pub error: Publisher, } #[derive(Default, Debug)] pub struct Application { - pub command_permissions_update: GatewayEvent, + pub command_permissions_update: Publisher, } #[derive(Default, Debug)] pub struct AutoModeration { - pub rule_create: GatewayEvent, - pub rule_update: GatewayEvent, - pub rule_delete: GatewayEvent, - pub action_execution: GatewayEvent, + pub rule_create: Publisher, + pub rule_update: Publisher, + pub rule_delete: Publisher, + pub action_execution: Publisher, } #[derive(Default, Debug)] pub struct Session { - pub ready: GatewayEvent, - pub ready_supplemental: GatewayEvent, - pub replace: GatewayEvent, - pub reconnect: GatewayEvent, - pub invalid: GatewayEvent, + pub ready: Publisher, + pub ready_supplemental: Publisher, + pub replace: Publisher, + pub reconnect: Publisher, + pub invalid: Publisher, } #[derive(Default, Debug)] pub struct StageInstance { - pub create: GatewayEvent, - pub update: GatewayEvent, - pub delete: GatewayEvent, + pub create: Publisher, + pub update: Publisher, + pub delete: Publisher, } #[derive(Default, Debug)] pub struct Message { - pub create: GatewayEvent, - pub update: GatewayEvent, - pub delete: GatewayEvent, - pub delete_bulk: GatewayEvent, - pub reaction_add: GatewayEvent, - pub reaction_remove: GatewayEvent, - pub reaction_remove_all: GatewayEvent, - pub reaction_remove_emoji: GatewayEvent, - pub ack: GatewayEvent, + pub create: Publisher, + pub update: Publisher, + pub delete: Publisher, + pub delete_bulk: Publisher, + pub reaction_add: Publisher, + pub reaction_remove: Publisher, + pub reaction_remove_all: Publisher, + pub reaction_remove_emoji: Publisher, + pub ack: Publisher, } #[derive(Default, Debug)] pub struct User { - pub update: GatewayEvent, - pub guild_settings_update: GatewayEvent, - pub presence_update: GatewayEvent, - pub typing_start: GatewayEvent, + pub update: Publisher, + pub guild_settings_update: Publisher, + pub presence_update: Publisher, + pub typing_start: Publisher, } #[derive(Default, Debug)] pub struct Relationship { - pub add: GatewayEvent, - pub remove: GatewayEvent, + pub add: Publisher, + pub remove: Publisher, } #[derive(Default, Debug)] pub struct Channel { - pub create: GatewayEvent, - pub update: GatewayEvent, - pub unread_update: GatewayEvent, - pub delete: GatewayEvent, - pub pins_update: GatewayEvent, + pub create: Publisher, + pub update: Publisher, + pub unread_update: Publisher, + pub delete: Publisher, + pub pins_update: Publisher, } #[derive(Default, Debug)] pub struct Thread { - pub create: GatewayEvent, - pub update: GatewayEvent, - pub delete: GatewayEvent, - pub list_sync: GatewayEvent, - pub member_update: GatewayEvent, - pub members_update: GatewayEvent, + pub create: Publisher, + pub update: Publisher, + pub delete: Publisher, + pub list_sync: Publisher, + pub member_update: Publisher, + pub members_update: Publisher, } #[derive(Default, Debug)] pub struct Guild { - pub create: GatewayEvent, - pub update: GatewayEvent, - pub delete: GatewayEvent, - pub audit_log_entry_create: GatewayEvent, - pub ban_add: GatewayEvent, - pub ban_remove: GatewayEvent, - pub emojis_update: GatewayEvent, - pub stickers_update: GatewayEvent, - pub integrations_update: GatewayEvent, - pub member_add: GatewayEvent, - pub member_remove: GatewayEvent, - pub member_update: GatewayEvent, - pub members_chunk: GatewayEvent, - pub role_create: GatewayEvent, - pub role_update: GatewayEvent, - pub role_delete: GatewayEvent, - pub role_scheduled_event_create: GatewayEvent, - pub role_scheduled_event_update: GatewayEvent, - pub role_scheduled_event_delete: GatewayEvent, - pub role_scheduled_event_user_add: GatewayEvent, - pub role_scheduled_event_user_remove: GatewayEvent, - pub passive_update_v1: GatewayEvent, + pub create: Publisher, + pub update: Publisher, + pub delete: Publisher, + pub audit_log_entry_create: Publisher, + pub ban_add: Publisher, + pub ban_remove: Publisher, + pub emojis_update: Publisher, + pub stickers_update: Publisher, + pub integrations_update: Publisher, + pub member_add: Publisher, + pub member_remove: Publisher, + pub member_update: Publisher, + pub members_chunk: Publisher, + pub role_create: Publisher, + pub role_update: Publisher, + pub role_delete: Publisher, + pub role_scheduled_event_create: Publisher, + pub role_scheduled_event_update: Publisher, + pub role_scheduled_event_delete: Publisher, + pub role_scheduled_event_user_add: Publisher, + pub role_scheduled_event_user_remove: Publisher, + pub passive_update_v1: Publisher, } #[derive(Default, Debug)] pub struct Invite { - pub create: GatewayEvent, - pub delete: GatewayEvent, + pub create: Publisher, + pub delete: Publisher, } #[derive(Default, Debug)] pub struct Integration { - pub create: GatewayEvent, - pub update: GatewayEvent, - pub delete: GatewayEvent, + pub create: Publisher, + pub update: Publisher, + pub delete: Publisher, } #[derive(Default, Debug)] pub struct Interaction { - pub create: GatewayEvent, + pub create: Publisher, } #[derive(Default, Debug)] pub struct Call { - pub create: GatewayEvent, - pub update: GatewayEvent, - pub delete: GatewayEvent, + pub create: Publisher, + pub update: Publisher, + pub delete: Publisher, } #[derive(Default, Debug)] pub struct Voice { - pub state_update: GatewayEvent, - pub server_update: GatewayEvent, + pub state_update: Publisher, + pub server_update: Publisher, } #[derive(Default, Debug)] pub struct Webhooks { - pub update: GatewayEvent, + pub update: Publisher, } diff --git a/src/gateway/gateway.rs b/src/gateway/gateway.rs index 1312137b..f1fc03cc 100644 --- a/src/gateway/gateway.rs +++ b/src/gateway/gateway.rs @@ -7,6 +7,7 @@ use std::time::Duration; use flate2::Decompress; use futures_util::{SinkExt, StreamExt}; use log::*; +use pubserve::Publisher; #[cfg(not(target_arch = "wasm32"))] use tokio::task; @@ -197,7 +198,7 @@ impl Gateway { #[allow(dead_code)] // TODO: Remove this allow annotation async fn handle_event<'a, T: WebSocketEvent + serde::Deserialize<'a>>( data: &'a str, - event: &mut GatewayEvent, + event: &mut Publisher, ) -> Result<(), serde_json::Error> { let data_deserialize_result: Result = serde_json::from_str(data); @@ -205,7 +206,7 @@ impl Gateway { return Err(data_deserialize_result.err().unwrap()); } - event.notify(data_deserialize_result.unwrap()).await; + event.publish(data_deserialize_result.unwrap()).await; Ok(()) } @@ -253,7 +254,7 @@ impl Gateway { if let Some(error) = msg.error() { warn!("GW: Received error {:?}, connection will close..", error); self.close().await; - self.events.lock().await.error.notify(error).await; + self.events.lock().await.error.publish(error).await; } else { warn!( "Message unrecognised: {:?}, please open an issue on the chorus github", @@ -292,7 +293,7 @@ impl Gateway { let id = if message.id().is_some() { message.id().unwrap() } else { - event.notify(message).await; + event.publish(message).await; return; }; if let Some(to_update) = store.get(&id) { @@ -314,7 +315,7 @@ impl Gateway { } } )? - event.notify(message).await; + event.publish(message).await; } } },)* @@ -329,7 +330,7 @@ impl Gateway { return; } Ok(sessions) => { - self.events.lock().await.session.replace.notify( + self.events.lock().await.session.replace.publish( types::SessionsReplace {sessions} ).await; } @@ -446,7 +447,7 @@ impl Gateway { .await .session .reconnect - .notify(reconnect) + .publish(reconnect) .await; } GATEWAY_INVALID_SESSION => { @@ -471,7 +472,7 @@ impl Gateway { .await .session .invalid - .notify(invalid_session) + .publish(invalid_session) .await; } // Starts our heartbeat diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index 3e96af07..fcbd1258 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -82,56 +82,3 @@ pub type ObservableObject = dyn Send + Sync + Any; pub trait Updateable: 'static + Send + Sync { fn id(&self) -> Snowflake; } - -/// Trait which defines the behavior of an Observer. An Observer is an object which is subscribed to -/// an Observable. The Observer is notified when the Observable's data changes. -/// In this case, the Observable is a [`GatewayEvent`], which is a wrapper around a WebSocketEvent. -/// Note that `Debug` is used to tell `Observer`s apart when unsubscribing. -#[async_trait] -pub trait Observer: Sync + Send + std::fmt::Debug { - async fn update(&self, data: &T); -} - -/// GatewayEvent is a wrapper around a WebSocketEvent. It is used to notify the observers of a -/// change in the WebSocketEvent. GatewayEvents are observable. -#[derive(Default, Debug)] -pub struct GatewayEvent { - observers: Vec>>, -} - -impl GatewayEvent { - pub fn new() -> Self { - Self { - observers: Vec::new(), - } - } - - /// Returns true if the GatewayEvent is observed by at least one Observer. - pub fn is_observed(&self) -> bool { - !self.observers.is_empty() - } - - /// Subscribes an Observer to the GatewayEvent. - pub fn subscribe(&mut self, observable: Arc>) { - self.observers.push(observable); - } - - /// Unsubscribes an Observer from the GatewayEvent. - pub fn unsubscribe(&mut self, observable: &dyn Observer) { - // .retain()'s closure retains only those elements of the vector, which have a different - // pointer value than observable. - // The usage of the debug format to compare the generic T of observers is quite stupid, but the only thing to compare between them is T and if T == T they are the same - // anddd there is no way to do that without using format - let to_remove = format!("{:?}", observable); - self.observers - .retain(|obs| format!("{:?}", obs) != to_remove); - } - - /// Notifies the observers of the GatewayEvent. - pub(crate) async fn notify(&self, new_event_data: T) { - for observer in &self.observers { - observer.update(&new_event_data).await; - } - } -} - diff --git a/src/voice/gateway/events.rs b/src/voice/gateway/events.rs index af043b3b..90de2cec 100644 --- a/src/voice/gateway/events.rs +++ b/src/voice/gateway/events.rs @@ -14,15 +14,15 @@ use crate::{ #[derive(Default, Debug)] pub struct VoiceEvents { - pub voice_ready: GatewayEvent, - pub backend_version: GatewayEvent, - pub session_description: GatewayEvent, - pub session_update: GatewayEvent, - pub speaking: GatewayEvent, - pub ssrc_definition: GatewayEvent, - pub client_disconnect: GatewayEvent, - pub client_connect_flags: GatewayEvent, - pub client_connect_platform: GatewayEvent, - pub media_sink_wants: GatewayEvent, - pub error: GatewayEvent, + pub voice_ready: Publisher, + pub backend_version: Publisher, + pub session_description: Publisher, + pub session_update: Publisher, + pub speaking: Publisher, + pub ssrc_definition: Publisher, + pub client_disconnect: Publisher, + pub client_connect_flags: Publisher, + pub client_connect_platform: Publisher, + pub media_sink_wants: Publisher, + pub error: Publisher, } diff --git a/src/voice/gateway/gateway.rs b/src/voice/gateway/gateway.rs index 6ff2a379..f1bde916 100644 --- a/src/voice/gateway/gateway.rs +++ b/src/voice/gateway/gateway.rs @@ -160,7 +160,7 @@ impl VoiceGateway { /// (Called for every event in handle_message) async fn handle_event<'a, T: WebSocketEvent + serde::Deserialize<'a>>( data: &'a str, - event: &mut GatewayEvent, + event: &mut Publisher, ) -> Result<(), serde_json::Error> { let data_deserialize_result: Result = serde_json::from_str(data); @@ -168,7 +168,7 @@ impl VoiceGateway { return Err(data_deserialize_result.err().unwrap()); } - event.notify(data_deserialize_result.unwrap()).await; + event.publish(data_deserialize_result.unwrap()).await; Ok(()) } @@ -182,7 +182,7 @@ impl VoiceGateway { if let Some(error) = msg.error() { warn!("GW: Received error {:?}, connection will close..", error); self.close().await; - self.events.lock().await.error.notify(error).await; + self.events.lock().await.error.publish(error).await; } else { warn!( "Message unrecognised: {:?}, please open an issue on the chorus github", diff --git a/src/voice/udp/events.rs b/src/voice/udp/events.rs index d4917fe9..dfa26e74 100644 --- a/src/voice/udp/events.rs +++ b/src/voice/udp/events.rs @@ -11,8 +11,8 @@ impl WebSocketEvent for Rtcp {} #[derive(Debug)] pub struct VoiceUDPEvents { - pub rtp: GatewayEvent, - pub rtcp: GatewayEvent, + pub rtp: Publisher, + pub rtcp: Publisher, } impl Default for VoiceUDPEvents { diff --git a/src/voice/udp/handler.rs b/src/voice/udp/handler.rs index c21709b8..df2a57c9 100644 --- a/src/voice/udp/handler.rs +++ b/src/voice/udp/handler.rs @@ -214,7 +214,7 @@ impl UdpHandler { .lock() .await .rtp - .notify(rtp_with_decrypted_data) + .publish(rtp_with_decrypted_data) .await; } Demuxed::Rtcp(rtcp) => { @@ -251,7 +251,7 @@ impl UdpHandler { } }; - self.events.lock().await.rtcp.notify(rtcp_data).await; + self.events.lock().await.rtcp.publish(rtcp_data).await; } Demuxed::FailedParse(e) => { trace!("VUDP: Failed to parse packet: {:?}", e); diff --git a/tests/gateway.rs b/tests/gateway.rs index 99911245..b16b3b2e 100644 --- a/tests/gateway.rs +++ b/tests/gateway.rs @@ -14,6 +14,7 @@ use chorus::types::{ self, Channel, ChannelCreateSchema, ChannelModifySchema, GatewayReady, IntoShared, RoleCreateModifySchema, RoleObject, }; +use pubserve::Subscriber; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; #[cfg(target_arch = "wasm32")] @@ -30,7 +31,9 @@ use wasmtimer::tokio::sleep; async fn test_gateway_establish() { let bundle = common::setup().await; - let _: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone(), GatewayOptions::default()).await.unwrap(); + let _: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone(), GatewayOptions::default()) + .await + .unwrap(); common::teardown(bundle).await } @@ -40,7 +43,7 @@ struct GatewayReadyObserver { } #[async_trait] -impl Observer for GatewayReadyObserver { +impl Subscriber for GatewayReadyObserver { async fn update(&self, _data: &GatewayReady) { self.channel.send(()).await.unwrap(); } @@ -52,7 +55,9 @@ impl Observer for GatewayReadyObserver { async fn test_gateway_authenticate() { let bundle = common::setup().await; - let gateway: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone(), GatewayOptions::default()).await.unwrap(); + let gateway: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone(), GatewayOptions::default()) + .await + .unwrap(); let (ready_send, mut ready_receive) = tokio::sync::mpsc::channel(1); From ebcb6b65e40c1c8f32935131dc6e52d0be5eb881 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 13 Jul 2024 14:53:04 +0200 Subject: [PATCH 085/162] Fix voice, voice_udp features --- src/ratelimiter.rs | 1 - src/voice/gateway/events.rs | 3 ++- src/voice/gateway/gateway.rs | 2 +- src/voice/udp/events.rs | 7 ++++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ratelimiter.rs b/src/ratelimiter.rs index 2b080829..5ffcca66 100644 --- a/src/ratelimiter.rs +++ b/src/ratelimiter.rs @@ -6,7 +6,6 @@ use std::collections::HashMap; -use log::{self, debug}; use reqwest::{Client, RequestBuilder, Response}; use serde::Deserialize; use serde_json::from_str; diff --git a/src/voice/gateway/events.rs b/src/voice/gateway/events.rs index 90de2cec..22db83be 100644 --- a/src/voice/gateway/events.rs +++ b/src/voice/gateway/events.rs @@ -2,9 +2,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use pubserve::Publisher; + use crate::{ errors::VoiceGatewayError, - gateway::GatewayEvent, types::{ SessionDescription, SessionUpdate, Speaking, SsrcDefinition, VoiceBackendVersion, VoiceClientConnectFlags, VoiceClientConnectPlatform, VoiceClientDisconnection, diff --git a/src/voice/gateway/gateway.rs b/src/voice/gateway/gateway.rs index f1bde916..ba4df806 100644 --- a/src/voice/gateway/gateway.rs +++ b/src/voice/gateway/gateway.rs @@ -6,6 +6,7 @@ use std::{sync::Arc, time::Duration}; use log::*; +use pubserve::Publisher; use tokio::sync::Mutex; use futures_util::SinkExt; @@ -16,7 +17,6 @@ use crate::gateway::Stream; use crate::gateway::WebSocketBackend; use crate::{ errors::VoiceGatewayError, - gateway::GatewayEvent, types::{ VoiceGatewayReceivePayload, VoiceHelloData, WebSocketEvent, VOICE_BACKEND_VERSION, VOICE_CLIENT_CONNECT_FLAGS, VOICE_CLIENT_CONNECT_PLATFORM, VOICE_CLIENT_DISCONNECT, diff --git a/src/voice/udp/events.rs b/src/voice/udp/events.rs index dfa26e74..8958b712 100644 --- a/src/voice/udp/events.rs +++ b/src/voice/udp/events.rs @@ -3,8 +3,9 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use discortp::{rtcp::Rtcp, rtp::Rtp}; +use pubserve::Publisher; -use crate::{gateway::GatewayEvent, types::WebSocketEvent}; +use crate::types::WebSocketEvent; impl WebSocketEvent for Rtp {} impl WebSocketEvent for Rtcp {} @@ -18,8 +19,8 @@ pub struct VoiceUDPEvents { impl Default for VoiceUDPEvents { fn default() -> Self { Self { - rtp: GatewayEvent::new(), - rtcp: GatewayEvent::new(), + rtp: Publisher::new(), + rtcp: Publisher::new(), } } } From 491cd255de93b1608c3061b436a882908594b0e0 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 18 Jul 2024 23:04:35 +0200 Subject: [PATCH 086/162] Add one BILLION derives --- src/api/channels/reactions.rs | 2 +- src/gateway/backends/tungstenite.rs | 2 +- src/gateway/handle.rs | 2 +- src/gateway/mod.rs | 3 +- src/gateway/options.rs | 34 ++- src/instance.rs | 27 +- src/lib.rs | 5 +- .../config/types/defaults_configuration.rs | 2 +- src/types/config/types/login_configuration.rs | 4 +- .../config/types/metrics_configuration.rs | 2 +- .../types/password_reset_configuration.rs | 4 +- .../config/types/subconfigs/defaults/guild.rs | 2 +- .../config/types/subconfigs/defaults/user.rs | 2 +- .../types/subconfigs/guild/discovery.rs | 2 +- .../config/types/subconfigs/limits/channel.rs | 2 +- .../config/types/subconfigs/limits/global.rs | 4 +- .../config/types/subconfigs/limits/guild.rs | 2 +- .../config/types/subconfigs/limits/message.rs | 2 +- .../subconfigs/limits/ratelimits/auth.rs | 2 +- .../types/subconfigs/limits/ratelimits/mod.rs | 2 +- .../subconfigs/limits/ratelimits/route.rs | 2 +- .../config/types/subconfigs/limits/rates.rs | 16 +- .../config/types/subconfigs/limits/user.rs | 2 +- .../config/types/subconfigs/region/mod.rs | 4 +- .../subconfigs/register/date_of_birth.rs | 2 +- .../types/subconfigs/register/password.rs | 2 +- .../types/subconfigs/security/twofactor.rs | 2 +- .../config/types/template_configuration.rs | 2 +- src/types/entities/application.rs | 55 ++++- src/types/entities/audit_log.rs | 61 ++++- src/types/entities/auto_moderation.rs | 32 ++- src/types/entities/channel.rs | 69 ++++-- src/types/entities/emoji.rs | 36 ++- src/types/entities/guild.rs | 232 +++++++++++------- src/types/entities/guild_member.rs | 22 +- src/types/entities/integration.rs | 8 +- src/types/entities/message.rs | 63 +++-- src/types/entities/mod.rs | 39 +++ src/types/entities/ratelimits.rs | 6 +- src/types/entities/relationship.rs | 20 +- src/types/entities/role.rs | 2 +- src/types/entities/stage_instance.rs | 2 +- src/types/entities/sticker.rs | 89 ++----- src/types/entities/team.rs | 25 +- src/types/entities/user_settings.rs | 6 +- src/types/entities/voice_state.rs | 24 ++ src/types/entities/webhook.rs | 27 +- src/types/errors.rs | 8 +- src/types/events/call.rs | 29 ++- src/types/events/channel.rs | 4 +- src/types/events/guild.rs | 130 +++++++--- src/types/events/heartbeat.rs | 4 +- src/types/events/hello.rs | 4 +- src/types/events/integration.rs | 2 +- src/types/events/invalid_session.rs | 2 +- src/types/events/message.rs | 47 +++- src/types/events/reconnect.rs | 2 +- src/types/events/relationship.rs | 2 +- src/types/events/voice_gateway/speaking.rs | 2 +- src/types/events/webhooks.rs | 2 +- src/types/interfaces/interaction.rs | 6 +- src/types/schema/apierror.rs | 4 +- src/types/schema/audit_log.rs | 13 +- src/types/schema/channel.rs | 4 +- src/types/schema/guild.rs | 84 +++++-- src/types/schema/message.rs | 26 +- src/types/schema/role.rs | 6 +- src/types/schema/voice_state.rs | 6 +- src/types/utils/serde.rs | 76 +++--- src/voice/udp/backends/tokio.rs | 2 +- tests/channels.rs | 6 +- tests/gateway.rs | 2 +- tests/messages.rs | 5 +- tests/relationships.rs | 16 +- tests/types.rs | 72 +----- 75 files changed, 961 insertions(+), 562 deletions(-) diff --git a/src/api/channels/reactions.rs b/src/api/channels/reactions.rs index b7c42e10..f2de33d7 100644 --- a/src/api/channels/reactions.rs +++ b/src/api/channels/reactions.rs @@ -10,7 +10,7 @@ use crate::{ }; /// Useful metadata for working with [`types::Reaction`], bundled together nicely. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash, PartialOrd, Ord)] pub struct ReactionMeta { pub message_id: types::Snowflake, pub channel_id: types::Snowflake, diff --git a/src/gateway/backends/tungstenite.rs b/src/gateway/backends/tungstenite.rs index 7e007719..34dc8255 100644 --- a/src/gateway/backends/tungstenite.rs +++ b/src/gateway/backends/tungstenite.rs @@ -14,7 +14,7 @@ use tokio_tungstenite::{ use crate::gateway::{GatewayMessage, RawGatewayMessage}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct TungsteniteBackend; // These could be made into inherent associated types when that's stabilized diff --git a/src/gateway/handle.rs b/src/gateway/handle.rs index bfaeb177..6bcdba85 100644 --- a/src/gateway/handle.rs +++ b/src/gateway/handle.rs @@ -154,7 +154,7 @@ impl GatewayHandle { /// Sends a call sync to the server pub async fn send_call_sync(&self, to_send: types::CallSync) { - 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 Call Sync.."); diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index fcbd1258..4550a2f2 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -2,7 +2,6 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use async_trait::async_trait; pub mod backends; pub mod events; @@ -20,7 +19,7 @@ pub use message::*; pub use options::*; use crate::errors::GatewayError; -use crate::types::{Snowflake, WebSocketEvent}; +use crate::types::{Snowflake}; use std::any::Any; use std::collections::HashMap; diff --git a/src/gateway/options.rs b/src/gateway/options.rs index e5c0314e..23942b23 100644 --- a/src/gateway/options.rs +++ b/src/gateway/options.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Debug, Default)] +#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Debug, Default, Copy)] /// Options passed when initializing the gateway connection. /// /// E.g. compression @@ -17,8 +17,8 @@ /// /// See pub struct GatewayOptions { - pub encoding: GatewayEncoding, - pub transport_compression: GatewayTransportCompression, + pub encoding: GatewayEncoding, + pub transport_compression: GatewayTransportCompression, } impl GatewayOptions { @@ -26,11 +26,10 @@ impl GatewayOptions { /// /// Returns the new url pub(crate) fn add_to_url(&self, url: String) -> String { - let mut url = url; let mut parameters = Vec::with_capacity(2); - + let encoding = self.encoding.to_url_parameter(); parameters.push(encoding); @@ -54,8 +53,7 @@ impl GatewayOptions { if !has_parameters { url = format!("{}?{}", url, parameter); has_parameters = true; - } - else { + } else { url = format!("{}&{}", url, parameter); } } @@ -78,15 +76,15 @@ pub enum GatewayTransportCompression { impl GatewayTransportCompression { /// Returns the option as a url parameter. - /// + /// /// If set to [GatewayTransportCompression::None] returns [None]. /// /// If set to anything else, returns a string like "compress=zlib-stream" pub(crate) fn to_url_parameter(self) -> Option { - match self { - Self::None => None, - Self::ZLibStream => Some(String::from("compress=zlib-stream")) - } + match self { + Self::None => None, + Self::ZLibStream => Some(String::from("compress=zlib-stream")), + } } } @@ -102,17 +100,17 @@ pub enum GatewayEncoding { /// Should be lighter and faster than json. /// /// !! Chorus does not implement ETF yet !! - ETF + ETF, } impl GatewayEncoding { /// Returns the option as a url parameter. - /// + /// /// Returns a string like "encoding=json" pub(crate) fn to_url_parameter(self) -> String { - match self { - Self::Json => String::from("encoding=json"), - Self::ETF => String::from("encoding=etf") - } + match self { + Self::Json => String::from("encoding=json"), + Self::ETF => String::from("encoding=etf"), + } } } diff --git a/src/instance.rs b/src/instance.rs index e6ba5c8a..f826ab58 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -35,24 +35,6 @@ pub struct Instance { pub gateway_options: GatewayOptions, } -impl PartialEq for Instance { - fn eq(&self, other: &Self) -> bool { - self.urls == other.urls - && self.instance_info == other.instance_info - && self.limits_information == other.limits_information - } -} - -impl std::hash::Hash for Instance { - fn hash(&self, state: &mut H) { - self.urls.hash(state); - self.instance_info.hash(state); - if let Some(inf) = &self.limits_information { - inf.hash(state); - } - } -} - #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq)] pub struct LimitsInformation { pub ratelimits: HashMap, @@ -69,6 +51,7 @@ impl std::hash::Hash for LimitsInformation { } } +#[cfg(not(tarpaulin_include))] impl PartialEq for LimitsInformation { fn eq(&self, other: &Self) -> bool { self.ratelimits.iter().eq(other.ratelimits.iter()) @@ -175,14 +158,6 @@ pub struct ChorusUser { pub gateway: GatewayHandle, } -impl PartialEq for ChorusUser { - fn eq(&self, other: &Self) -> bool { - self.token == other.token - && self.limits == other.limits - && self.gateway.url == other.gateway.url - } -} - impl ChorusUser { pub fn token(&self) -> String { self.token.clone() diff --git a/src/lib.rs b/src/lib.rs index 6ffd8b84..7767480f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,7 +98,6 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read )] #![allow(clippy::module_inception)] #![deny( - missing_debug_implementations, clippy::extra_unused_lifetimes, clippy::from_over_into, clippy::needless_borrow, @@ -110,7 +109,9 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read clippy::unimplemented, clippy::dbg_macro, clippy::print_stdout, - clippy::print_stderr + clippy::print_stderr, + missing_debug_implementations, + missing_copy_implementations )] #[cfg(all(feature = "rt", feature = "rt_multi_thread"))] compile_error!("feature \"rt\" and feature \"rt_multi_thread\" cannot be enabled at the same time"); diff --git a/src/types/config/types/defaults_configuration.rs b/src/types/config/types/defaults_configuration.rs index e6e08671..f607c9b0 100644 --- a/src/types/config/types/defaults_configuration.rs +++ b/src/types/config/types/defaults_configuration.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use crate::types::config::types::subconfigs::defaults::{guild::GuildDefaults, user::UserDefaults}; -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Copy)] #[serde(rename_all = "camelCase")] pub struct DefaultsConfiguration { pub guild: GuildDefaults, diff --git a/src/types/config/types/login_configuration.rs b/src/types/config/types/login_configuration.rs index 83125e05..ed797b53 100644 --- a/src/types/config/types/login_configuration.rs +++ b/src/types/config/types/login_configuration.rs @@ -4,7 +4,9 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +#[derive( + Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Copy, Hash, PartialOrd, Ord, +)] #[serde(rename_all = "camelCase")] pub struct LoginConfiguration { pub require_captcha: bool, diff --git a/src/types/config/types/metrics_configuration.rs b/src/types/config/types/metrics_configuration.rs index 98d35369..d11644ba 100644 --- a/src/types/config/types/metrics_configuration.rs +++ b/src/types/config/types/metrics_configuration.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd, Copy, Hash)] #[serde(rename_all = "camelCase")] pub struct MetricsConfiguration { pub timeout: u64, diff --git a/src/types/config/types/password_reset_configuration.rs b/src/types/config/types/password_reset_configuration.rs index d1c730e9..e7de663f 100644 --- a/src/types/config/types/password_reset_configuration.rs +++ b/src/types/config/types/password_reset_configuration.rs @@ -4,7 +4,9 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +#[derive( + Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Copy, Hash, PartialOrd, Ord, +)] #[serde(rename_all = "camelCase")] pub struct PasswordResetConfiguration { pub require_captcha: bool, diff --git a/src/types/config/types/subconfigs/defaults/guild.rs b/src/types/config/types/subconfigs/defaults/guild.rs index 8509fe57..f33f2795 100644 --- a/src/types/config/types/subconfigs/defaults/guild.rs +++ b/src/types/config/types/subconfigs/defaults/guild.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use crate::types::{ExplicitContentFilterLevel, MessageNotificationLevel}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, Hash, PartialOrd, Ord)] #[serde(rename_all = "camelCase")] pub struct GuildDefaults { pub max_presences: u64, diff --git a/src/types/config/types/subconfigs/defaults/user.rs b/src/types/config/types/subconfigs/defaults/user.rs index d7dc7b3e..a533b0ac 100644 --- a/src/types/config/types/subconfigs/defaults/user.rs +++ b/src/types/config/types/subconfigs/defaults/user.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, Hash, PartialOrd, Ord)] #[serde(rename_all = "camelCase")] pub struct UserDefaults { pub premium: bool, diff --git a/src/types/config/types/subconfigs/guild/discovery.rs b/src/types/config/types/subconfigs/guild/discovery.rs index 50738f13..689528b7 100644 --- a/src/types/config/types/subconfigs/guild/discovery.rs +++ b/src/types/config/types/subconfigs/guild/discovery.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)] #[serde(rename_all = "camelCase")] pub struct DiscoverConfiguration { pub show_all_guilds: bool, diff --git a/src/types/config/types/subconfigs/limits/channel.rs b/src/types/config/types/subconfigs/limits/channel.rs index 24157264..9e032836 100644 --- a/src/types/config/types/subconfigs/limits/channel.rs +++ b/src/types/config/types/subconfigs/limits/channel.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord)] #[serde(rename_all = "camelCase")] pub struct ChannelLimits { pub max_pins: u16, diff --git a/src/types/config/types/subconfigs/limits/global.rs b/src/types/config/types/subconfigs/limits/global.rs index 0140447b..2a23bf4f 100644 --- a/src/types/config/types/subconfigs/limits/global.rs +++ b/src/types/config/types/subconfigs/limits/global.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)] pub struct GlobalRateLimit { pub limit: u16, pub window: u64, @@ -21,7 +21,7 @@ impl Default for GlobalRateLimit { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)] #[serde(rename_all = "camelCase")] pub struct GlobalRateLimits { pub register: GlobalRateLimit, diff --git a/src/types/config/types/subconfigs/limits/guild.rs b/src/types/config/types/subconfigs/limits/guild.rs index 9ef8f906..4c58404d 100644 --- a/src/types/config/types/subconfigs/limits/guild.rs +++ b/src/types/config/types/subconfigs/limits/guild.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, Hash, PartialOrd, Ord)] #[serde(rename_all = "camelCase")] pub struct GuildLimits { pub max_roles: u16, diff --git a/src/types/config/types/subconfigs/limits/message.rs b/src/types/config/types/subconfigs/limits/message.rs index 3beb76e2..fc2237bd 100644 --- a/src/types/config/types/subconfigs/limits/message.rs +++ b/src/types/config/types/subconfigs/limits/message.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)] #[serde(rename_all = "camelCase")] pub struct MessageLimits { pub max_characters: u32, diff --git a/src/types/config/types/subconfigs/limits/ratelimits/auth.rs b/src/types/config/types/subconfigs/limits/ratelimits/auth.rs index 78f1908a..25adcab1 100644 --- a/src/types/config/types/subconfigs/limits/ratelimits/auth.rs +++ b/src/types/config/types/subconfigs/limits/ratelimits/auth.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use crate::types::config::types::subconfigs::limits::ratelimits::RateLimitOptions; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)] pub struct AuthRateLimit { pub login: RateLimitOptions, pub register: RateLimitOptions, diff --git a/src/types/config/types/subconfigs/limits/ratelimits/mod.rs b/src/types/config/types/subconfigs/limits/ratelimits/mod.rs index 501afe90..16106cdf 100644 --- a/src/types/config/types/subconfigs/limits/ratelimits/mod.rs +++ b/src/types/config/types/subconfigs/limits/ratelimits/mod.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; pub mod auth; pub mod route; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, PartialOrd, Ord, Copy)] #[serde(rename_all = "camelCase")] pub struct RateLimitOptions { pub bot: Option, diff --git a/src/types/config/types/subconfigs/limits/ratelimits/route.rs b/src/types/config/types/subconfigs/limits/ratelimits/route.rs index 7c70fdc1..8379c265 100644 --- a/src/types/config/types/subconfigs/limits/ratelimits/route.rs +++ b/src/types/config/types/subconfigs/limits/ratelimits/route.rs @@ -8,7 +8,7 @@ use crate::types::config::types::subconfigs::limits::ratelimits::{ auth::AuthRateLimit, RateLimitOptions, }; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Copy, PartialOrd, Ord)] pub struct RouteRateLimit { pub guild: RateLimitOptions, pub webhook: RateLimitOptions, diff --git a/src/types/config/types/subconfigs/limits/rates.rs b/src/types/config/types/subconfigs/limits/rates.rs index 4c9b9a15..e837d968 100644 --- a/src/types/config/types/subconfigs/limits/rates.rs +++ b/src/types/config/types/subconfigs/limits/rates.rs @@ -50,14 +50,14 @@ impl Default for RateLimits { impl RateLimits { pub fn to_hash_map(&self) -> HashMap { let mut map = HashMap::new(); - map.insert(LimitType::AuthLogin, self.routes.auth.login.clone()); - map.insert(LimitType::AuthRegister, self.routes.auth.register.clone()); - map.insert(LimitType::ChannelBaseline, self.routes.channel.clone()); - map.insert(LimitType::Error, self.error.clone()); - map.insert(LimitType::Global, self.global.clone()); - map.insert(LimitType::Ip, self.ip.clone()); - map.insert(LimitType::WebhookBaseline, self.routes.webhook.clone()); - map.insert(LimitType::GuildBaseline, self.routes.guild.clone()); + map.insert(LimitType::AuthLogin, self.routes.auth.login); + map.insert(LimitType::AuthRegister, self.routes.auth.register); + map.insert(LimitType::ChannelBaseline, self.routes.channel); + map.insert(LimitType::Error, self.error); + map.insert(LimitType::Global, self.global); + map.insert(LimitType::Ip, self.ip); + map.insert(LimitType::WebhookBaseline, self.routes.webhook); + map.insert(LimitType::GuildBaseline, self.routes.guild); map } } diff --git a/src/types/config/types/subconfigs/limits/user.rs b/src/types/config/types/subconfigs/limits/user.rs index 473535ad..4ac0e9d1 100644 --- a/src/types/config/types/subconfigs/limits/user.rs +++ b/src/types/config/types/subconfigs/limits/user.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Copy, Hash)] #[serde(rename_all = "camelCase")] pub struct UserLimits { pub max_guilds: u64, diff --git a/src/types/config/types/subconfigs/region/mod.rs b/src/types/config/types/subconfigs/region/mod.rs index 1661c099..42ad564a 100644 --- a/src/types/config/types/subconfigs/region/mod.rs +++ b/src/types/config/types/subconfigs/region/mod.rs @@ -4,13 +4,13 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, PartialOrd, Copy)] pub struct LatLong { pub latitude: f64, pub longitude: f64, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, PartialOrd)] pub struct Region { pub id: String, pub name: String, diff --git a/src/types/config/types/subconfigs/register/date_of_birth.rs b/src/types/config/types/subconfigs/register/date_of_birth.rs index 66892973..961fca41 100644 --- a/src/types/config/types/subconfigs/register/date_of_birth.rs +++ b/src/types/config/types/subconfigs/register/date_of_birth.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)] pub struct DateOfBirthConfiguration { pub required: bool, pub minimum: u8, diff --git a/src/types/config/types/subconfigs/register/password.rs b/src/types/config/types/subconfigs/register/password.rs index 1d380bab..a192dc50 100644 --- a/src/types/config/types/subconfigs/register/password.rs +++ b/src/types/config/types/subconfigs/register/password.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)] #[serde(rename_all = "camelCase")] pub struct PasswordConfiguration { pub required: bool, diff --git a/src/types/config/types/subconfigs/security/twofactor.rs b/src/types/config/types/subconfigs/security/twofactor.rs index 1182a458..248ba110 100644 --- a/src/types/config/types/subconfigs/security/twofactor.rs +++ b/src/types/config/types/subconfigs/security/twofactor.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, Hash, PartialOrd, Ord)] #[serde(rename_all = "camelCase")] pub struct TwoFactorConfiguration { pub generate_backup_codes: bool, diff --git a/src/types/config/types/template_configuration.rs b/src/types/config/types/template_configuration.rs index 9f370b47..b88fe2e7 100644 --- a/src/types/config/types/template_configuration.rs +++ b/src/types/config/types/template_configuration.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)] #[serde(rename_all = "camelCase")] pub struct TemplateConfiguration { pub enabled: bool, diff --git a/src/types/entities/application.rs b/src/types/entities/application.rs index ac4cb971..754c9652 100644 --- a/src/types/entities/application.rs +++ b/src/types/entities/application.rs @@ -7,10 +7,12 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_repr::{Deserialize_repr, Serialize_repr}; -use crate::types::Shared; use crate::types::utils::Snowflake; +use crate::types::Shared; use crate::types::{Team, User}; +use super::{arc_rwlock_ptr_eq, option_arc_rwlock_ptr_eq}; + #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] /// # Reference @@ -59,6 +61,39 @@ pub struct Application { pub team: Option, } +#[cfg(not(tarpaulin_include))] +impl PartialEq for Application { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + && self.name == other.name + && self.icon == other.icon + && self.description == other.description + && self.summary == other.summary + && self.r#type == other.r#type + && self.hook == other.hook + && self.bot_public == other.bot_public + && self.bot_require_code_grant == other.bot_require_code_grant + && self.verify_key == other.verify_key + && arc_rwlock_ptr_eq(&self.owner, &other.owner) + && self.flags == other.flags + && self.redirect_uris == other.redirect_uris + && self.rpc_application_state == other.rpc_application_state + && self.store_application_state == other.store_application_state + && self.verification_state == other.verification_state + && self.interactions_endpoint_url == other.interactions_endpoint_url + && self.integration_public == other.integration_public + && self.integration_require_code_grant == other.integration_require_code_grant + && self.discoverability_state == other.discoverability_state + && self.discovery_eligibility_flags == other.discovery_eligibility_flags + && self.tags == other.tags + && self.cover_image == other.cover_image + && option_arc_rwlock_ptr_eq(&self.install_params, &other.install_params) + && self.terms_of_service_url == other.terms_of_service_url + && self.privacy_policy_url == other.privacy_policy_url + && self.team == other.team + } +} + impl Default for Application { fn default() -> Self { Self { @@ -207,7 +242,9 @@ pub struct GuildApplicationCommandPermissions { pub permissions: Vec>, } -#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] +#[derive( + Debug, Default, Clone, PartialEq, Serialize, Deserialize, Copy, Eq, Hash, PartialOrd, Ord, +)] /// See pub struct ApplicationCommandPermission { pub id: Snowflake, @@ -217,7 +254,19 @@ pub struct ApplicationCommandPermission { pub permission: bool, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, PartialEq, Eq, Hash)] +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Default, + Clone, + PartialEq, + Eq, + Hash, + Copy, + PartialOrd, + Ord, +)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[repr(u8)] /// See diff --git a/src/types/entities/audit_log.rs b/src/types/entities/audit_log.rs index 48dc9d49..ca997a1a 100644 --- a/src/types/entities/audit_log.rs +++ b/src/types/entities/audit_log.rs @@ -2,11 +2,15 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use std::sync::Arc; + use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use crate::types::{AutoModerationRuleTriggerType, IntegrationType, PermissionOverwriteType, Shared}; use crate::types::utils::Snowflake; +use crate::types::{ + AutoModerationRuleTriggerType, IntegrationType, PermissionOverwriteType, Shared, +}; #[derive(Serialize, Deserialize, Debug, Default, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -27,6 +31,38 @@ pub struct AuditLogEntry { pub reason: Option, } +#[cfg(not(tarpaulin_include))] +impl PartialEq for AuditLogEntry { + fn eq(&self, other: &Self) -> bool { + let everything_else = self.target_id == other.target_id + && self.user_id == other.user_id + && self.id == other.id + && self.action_type == other.action_type + && self.options == other.options + && self.reason == other.reason; + // Compare the Vec> separately, since Shared doesn't implement PartialEq + match (&self.changes, &other.changes) { + // If both are Some, compare the contents + (Some(self_changes), Some(other_changes)) => { + let mut changes_equal = true; + // Iterate over both Vecs and compare the Arc pointers. If any are different, the + // Vecs are not equal + for (self_change, other_change) in self_changes.iter().zip(other_changes.iter()) { + if !Arc::ptr_eq(self_change, other_change) { + changes_equal = false; + break; + } + } + everything_else && changes_equal + } + // If both are None, they're equal + (None, None) => everything_else, + // If one is Some and the other is None, they're not equal + _ => false, + } + } +} + #[derive(Serialize, Deserialize, Debug, Default, Clone)] /// See pub struct AuditLogChange { @@ -35,8 +71,19 @@ pub struct AuditLogChange { pub key: String, } - -#[derive(Default, Serialize_repr, Deserialize_repr, Debug, Clone, Copy)] +#[derive( + Default, + Serialize_repr, + Deserialize_repr, + Debug, + Clone, + Copy, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, +)] #[repr(u8)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] /// # Reference: @@ -170,10 +217,10 @@ pub enum AuditLogActionType { /// Voice channel status was updated VoiceChannelStatusUpdate = 192, /// Voice channel status was deleted - VoiceChannelStatusDelete = 193 + VoiceChannelStatusDelete = 193, } -#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)] pub struct AuditEntryInfo { pub application_id: Option, pub auto_moderation_rule_name: Option, @@ -193,5 +240,5 @@ pub struct AuditEntryInfo { pub role_name: Option, #[serde(rename = "type")] pub overwrite_type: Option, - pub status: Option -} \ No newline at end of file + pub status: Option, +} diff --git a/src/types/entities/auto_moderation.rs b/src/types/entities/auto_moderation.rs index 021185ec..3caa16cf 100644 --- a/src/types/entities/auto_moderation.rs +++ b/src/types/entities/auto_moderation.rs @@ -2,9 +2,9 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use crate::types::Shared; #[cfg(feature = "client")] use crate::gateway::Updateable; +use crate::types::Shared; #[cfg(feature = "client")] use chorus_macros::Updateable; @@ -31,7 +31,7 @@ pub struct AutoModerationRule { pub exempt_channels: Vec, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] +#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default, Copy)] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See @@ -40,7 +40,9 @@ pub enum AutoModerationRuleEventType { MessageSend = 1, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] +#[derive( + Serialize_repr, Deserialize_repr, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy, +)] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See @@ -52,7 +54,7 @@ pub enum AutoModerationRuleTriggerType { MentionSpam = 5, } -#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] #[serde(untagged)] /// See pub enum AutoModerationRuleTriggerMetadata { @@ -63,7 +65,7 @@ pub enum AutoModerationRuleTriggerMetadata { None, } -#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] /// See pub struct AutoModerationRuleTriggerMetadataForKeyword { pub keyword_filter: Vec, @@ -71,14 +73,14 @@ pub struct AutoModerationRuleTriggerMetadataForKeyword { pub allow_list: Vec, } -#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] /// See pub struct AutoModerationRuleTriggerMetadataForKeywordPreset { pub presets: Vec, pub allow_list: Vec, } -#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy)] /// See pub struct AutoModerationRuleTriggerMetadataForMentionSpam { /// Max 50 @@ -86,7 +88,9 @@ pub struct AutoModerationRuleTriggerMetadataForMentionSpam { pub mention_raid_protection_enabled: bool, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] +#[derive( + Serialize_repr, Deserialize_repr, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy, +)] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See @@ -105,7 +109,9 @@ pub struct AutoModerationAction { pub metadata: Option>, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] +#[derive( + Serialize_repr, Deserialize_repr, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy, Hash +)] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See @@ -116,7 +122,7 @@ pub enum AutoModerationActionType { Timeout = 3, } -#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] #[serde(untagged)] /// See pub enum AutoModerationActionMetadata { @@ -127,19 +133,19 @@ pub enum AutoModerationActionMetadata { None, } -#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] /// See pub struct AutoModerationActionMetadataForBlockMessage { pub custom_message: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy)] /// See pub struct AutoModerationActionMetadataForSendAlertMessage { pub channel_id: Snowflake, } -#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy)] /// See pub struct AutoModerationActionMetadataForTimeout { /// Max 2419200 diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 19bdcef6..00477cdf 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -9,10 +9,9 @@ use std::fmt::{Debug, Formatter}; use std::str::FromStr; use crate::types::{ - PermissionFlags, Shared, entities::{GuildMember, User}, utils::Snowflake, - serde::string_or_u64 + PermissionFlags, Shared, }; #[cfg(feature = "client")] @@ -28,6 +27,7 @@ use crate::gateway::Updateable; use chorus_macros::{observe_option_vec, Composite, Updateable}; use serde::de::{Error, Visitor}; +use super::{option_arc_rwlock_ptr_eq, option_vec_arc_rwlock_ptr_eq}; #[derive(Default, Debug, Serialize, Deserialize, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -97,14 +97,21 @@ pub struct Channel { pub video_quality_mode: Option, } +#[cfg(not(tarpaulin_include))] impl PartialEq for Channel { fn eq(&self, other: &Self) -> bool { self.application_id == other.application_id + && self.applied_tags == other.applied_tags + && self.applied_tags == other.applied_tags + && self.available_tags == other.available_tags + && self.available_tags == other.available_tags && 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_reaction_emoji == other.default_reaction_emoji + && self.default_reaction_emoji == other.default_reaction_emoji && 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 @@ -114,16 +121,23 @@ impl PartialEq for Channel { && self.last_message_id == other.last_message_id && self.last_pin_timestamp == other.last_pin_timestamp && self.managed == other.managed + && self.member == other.member && 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 + && option_vec_arc_rwlock_ptr_eq( + &self.permission_overwrites, + &other.permission_overwrites, + ) && self.permissions == other.permissions && self.position == other.position && self.rate_limit_per_user == other.rate_limit_per_user + && option_vec_arc_rwlock_ptr_eq(&self.recipients, &other.recipients) && self.rtc_region == other.rtc_region + && self.thread_metadata == other.thread_metadata && self.topic == other.topic && self.total_message_sent == other.total_message_sent && self.user_limit == other.user_limit @@ -131,7 +145,7 @@ impl PartialEq for Channel { } } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] /// A tag that can be applied to a thread in a [ChannelType::GuildForum] or [ChannelType::GuildMedia] channel. /// /// # Reference @@ -158,8 +172,7 @@ pub struct PermissionOverwrite { pub deny: PermissionFlags, } - -#[derive(Debug, Serialize_repr, Clone, PartialEq, Eq, PartialOrd)] +#[derive(Debug, Serialize_repr, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] #[repr(u8)] /// # Reference /// @@ -200,33 +213,47 @@ impl<'de> Visitor<'de> for PermissionOverwriteTypeVisitor { formatter.write_str("a valid permission overwrite type") } - fn visit_u8(self, v: u8) -> Result where E: Error { + fn visit_u8(self, v: u8) -> Result + where + E: Error, + { Ok(PermissionOverwriteType::from(v)) } - fn visit_u64(self, v: u64) -> Result where E: Error { + fn visit_u64(self, v: u64) -> Result + where + E: Error, + { self.visit_u8(v as u8) } - fn visit_str(self, v: &str) -> Result where E: Error { - PermissionOverwriteType::from_str(v) - .map_err(E::custom) + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + PermissionOverwriteType::from_str(v).map_err(E::custom) } - fn visit_string(self, v: String) -> Result where E: Error { + fn visit_string(self, v: String) -> Result + where + E: Error, + { self.visit_str(v.as_str()) } } impl<'de> Deserialize<'de> for PermissionOverwriteType { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { let val = deserializer.deserialize_any(PermissionOverwriteTypeVisitor)?; Ok(val) } } -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] /// # Reference /// See pub struct ThreadMetadata { @@ -249,6 +276,17 @@ pub struct ThreadMember { pub member: Option>, } +#[cfg(not(tarpaulin_include))] +impl PartialEq for ThreadMember { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + && self.user_id == other.user_id + && self.join_timestamp == other.join_timestamp + && self.flags == other.flags + && option_arc_rwlock_ptr_eq(&self.member, &other.member) + } +} + #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd)] /// Specifies the emoji to use as the default way to react to a [ChannelType::GuildForum] or [ChannelType::GuildMedia] channel post. /// @@ -329,11 +367,10 @@ pub enum ChannelType { Unhandled = 255, } - /// # Reference /// See -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Copy, Hash, PartialOrd, Ord)] pub struct FollowedChannel { pub channel_id: Snowflake, - pub webhook_id: Snowflake + pub webhook_id: Snowflake, } diff --git a/src/types/entities/emoji.rs b/src/types/entities/emoji.rs index 23956b5d..55ebb84c 100644 --- a/src/types/entities/emoji.rs +++ b/src/types/entities/emoji.rs @@ -6,9 +6,9 @@ use std::fmt::Debug; use serde::{Deserialize, Serialize}; -use crate::types::{PartialEmoji, Shared}; use crate::types::entities::User; use crate::types::Snowflake; +use crate::types::{PartialEmoji, Shared}; #[cfg(feature = "client")] use crate::gateway::GatewayHandle; @@ -22,6 +22,8 @@ use crate::gateway::Updateable; #[cfg(feature = "client")] use chorus_macros::{Composite, Updateable}; +use super::option_arc_rwlock_ptr_eq; + #[derive(Debug, Clone, Deserialize, Serialize, Default)] #[cfg_attr(feature = "client", derive(Updateable, Composite))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -42,28 +44,18 @@ pub struct Emoji { pub available: Option, } -impl std::hash::Hash for Emoji { - fn hash(&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); - } -} - +#[cfg(not(tarpaulin_include))] impl PartialEq for Emoji { fn eq(&self, other: &Self) -> bool { - !(self.id != other.id - || self.name != other.name - || self.roles != other.roles - || self.require_colons != other.require_colons - || self.managed != other.managed - || self.animated != other.animated - || self.available != other.available) + self.id == other.id + && self.name == other.name + && self.roles == other.roles + && self.roles == other.roles + && option_arc_rwlock_ptr_eq(&self.user, &other.user) + && self.require_colons == other.require_colons + && self.managed == other.managed + && self.animated == other.animated + && self.available == other.available } } @@ -80,4 +72,4 @@ impl From for Emoji { available: None, } } -} \ No newline at end of file +} diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 72e6a7eb..76256c77 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -3,21 +3,22 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use std::fmt::Debug; +use std::hash::Hash; use bitflags::bitflags; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use crate::types::Shared; use crate::types::types::guild_configuration::GuildFeaturesList; +use crate::types::Shared; use crate::types::{ entities::{Channel, Emoji, RoleObject, Sticker, User, VoiceState, Webhook}, interfaces::WelcomeScreenObject, utils::Snowflake, }; -use super::PublicUser; +use super::{option_arc_rwlock_ptr_eq, vec_arc_rwlock_ptr_eq, PublicUser}; #[cfg(feature = "client")] use crate::gateway::Updateable; @@ -126,59 +127,8 @@ pub struct Guild { pub widget_enabled: Option, } -impl std::hash::Hash for Guild { - fn hash(&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 { +#[cfg(not(tarpaulin_include))] +impl PartialEq for Guild { fn eq(&self, other: &Self) -> bool { self.afk_channel_id == other.afk_channel_id && self.afk_timeout == other.afk_timeout @@ -187,14 +137,17 @@ impl std::cmp::PartialEq for Guild { && self.approximate_presence_count == other.approximate_presence_count && self.banner == other.banner && self.bans == other.bans + && vec_arc_rwlock_ptr_eq(&self.channels, &other.channels) && self.default_message_notifications == other.default_message_notifications && self.description == other.description && self.discovery_splash == other.discovery_splash + && vec_arc_rwlock_ptr_eq(&self.emojis, &other.emojis) && 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.invites == other.invites && self.joined_at == other.joined_at && self.large == other.large && self.max_members == other.max_members @@ -214,6 +167,7 @@ impl std::cmp::PartialEq for Guild { && self.primary_category_id == other.primary_category_id && self.public_updates_channel_id == other.public_updates_channel_id && self.region == other.region + && vec_arc_rwlock_ptr_eq(&self.roles, &other.roles) && self.rules_channel == other.rules_channel && self.rules_channel_id == other.rules_channel_id && self.splash == other.splash @@ -222,6 +176,8 @@ impl std::cmp::PartialEq for Guild { && self.system_channel_id == other.system_channel_id && self.vanity_url_code == other.vanity_url_code && self.verification_level == other.verification_level + && vec_arc_rwlock_ptr_eq(&self.voice_states, &other.voice_states) + && vec_arc_rwlock_ptr_eq(&self.webhooks, &other.webhooks) && self.welcome_screen == other.welcome_screen && self.welcome_screen == other.welcome_screen && self.widget_channel_id == other.widget_channel_id @@ -261,32 +217,36 @@ pub struct GuildInvite { pub vanity_url: Option, } -impl std::hash::Hash for GuildInvite { - fn hash(&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); +#[cfg(not(tarpaulin_include))] +impl PartialEq for GuildInvite { + fn eq(&self, other: &Self) -> bool { + self.code == other.code + && self.temporary == other.temporary + && self.uses == other.uses + && self.max_uses == other.max_uses + && self.max_age == other.max_age + && self.created_at == other.created_at + && self.expires_at == other.expires_at + && self.guild_id == other.guild_id + && option_arc_rwlock_ptr_eq(&self.guild, &other.guild) + && self.channel_id == other.channel_id + && option_arc_rwlock_ptr_eq(&self.channel, &other.channel) + && self.inviter_id == other.inviter_id + && option_arc_rwlock_ptr_eq(&self.inviter, &other.inviter) + && self.target_user_id == other.target_user_id + && self.target_user == other.target_user + && self.target_user_type == other.target_user_type + && self.vanity_url == other.vanity_url } } -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Hash)] +#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Hash, Eq, PartialOrd, Ord, Copy)] pub struct UnavailableGuild { pub id: Snowflake, pub unavailable: bool, } -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] pub struct GuildCreateResponse { pub id: Snowflake, } @@ -312,7 +272,29 @@ pub struct GuildScheduledEvent { pub image: Option, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)] +#[cfg(not(tarpaulin_include))] +impl PartialEq for GuildScheduledEvent { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + && self.guild_id == other.guild_id + && self.channel_id == other.channel_id + && self.creator_id == other.creator_id + && self.name == other.name + && self.description == other.description + && self.scheduled_start_time == other.scheduled_start_time + && self.scheduled_end_time == other.scheduled_end_time + && self.privacy_level == other.privacy_level + && self.status == other.status + && self.entity_type == other.entity_type + && self.entity_id == other.entity_id + && self.entity_metadata == other.entity_metadata + && option_arc_rwlock_ptr_eq(&self.creator, &other.creator) + && self.user_count == other.user_count + && self.image == other.image + } +} + +#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, PartialEq, Copy)] #[repr(u8)] /// See pub enum GuildScheduledEventPrivacyLevel { @@ -320,7 +302,7 @@ pub enum GuildScheduledEventPrivacyLevel { GuildOnly = 2, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)] +#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, PartialEq, Copy)] #[repr(u8)] /// See pub enum GuildScheduledEventStatus { @@ -331,7 +313,19 @@ pub enum GuildScheduledEventStatus { Canceled = 4, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)] +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Default, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Copy, + Hash, +)] #[repr(u8)] /// See pub enum GuildScheduledEventEntityType { @@ -341,7 +335,7 @@ pub enum GuildScheduledEventEntityType { External = 3, } -#[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] /// See pub struct GuildScheduledEventEntityMetadata { pub location: Option, @@ -356,7 +350,19 @@ pub struct VoiceRegion { custom: bool, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)] +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Default, + Clone, + Eq, + PartialEq, + Hash, + Copy, + PartialOrd, + Ord, +)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] @@ -367,7 +373,19 @@ pub enum MessageNotificationLevel { OnlyMentions = 1, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)] +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Default, + Clone, + Eq, + PartialEq, + Hash, + Copy, + PartialOrd, + Ord, +)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] @@ -379,7 +397,19 @@ pub enum ExplicitContentFilterLevel { AllMembers = 2, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)] +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Default, + Clone, + Eq, + PartialEq, + Hash, + Copy, + PartialOrd, + Ord, +)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] @@ -393,7 +423,19 @@ pub enum VerificationLevel { VeryHigh = 4, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)] +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Default, + Clone, + Eq, + PartialEq, + Hash, + Copy, + PartialOrd, + Ord, +)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] @@ -404,7 +446,19 @@ pub enum MFALevel { Elevated = 1, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)] +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Default, + Clone, + Eq, + PartialEq, + Hash, + Copy, + PartialOrd, + Ord, +)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] @@ -417,7 +471,19 @@ pub enum NSFWLevel { AgeRestricted = 3, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, Eq, PartialEq, Hash, Copy)] +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Default, + Clone, + Eq, + PartialEq, + Hash, + Copy, + PartialOrd, + Ord, +)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index 5b1308d4..87d94a76 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -5,8 +5,10 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::types::{GuildMemberFlags, PermissionFlags, Shared}; use crate::types::{entities::PublicUser, Snowflake}; +use crate::types::{GuildMemberFlags, PermissionFlags, Shared}; + +use super::option_arc_rwlock_ptr_eq; #[derive(Debug, Deserialize, Default, Serialize, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -31,3 +33,21 @@ pub struct GuildMember { pub permissions: PermissionFlags, pub communication_disabled_until: Option>, } + +#[cfg(not(tarpaulin_include))] +impl PartialEq for GuildMember { + fn eq(&self, other: &Self) -> bool { + self.nick == other.nick + && self.avatar == other.avatar + && self.roles == other.roles + && self.joined_at == other.joined_at + && self.premium_since == other.premium_since + && self.deaf == other.deaf + && self.mute == other.mute + && self.flags == other.flags + && self.pending == other.pending + && self.permissions == other.permissions + && self.communication_disabled_until == other.communication_disabled_until + && option_arc_rwlock_ptr_eq(&self.user, &other.user) + } +} diff --git a/src/types/entities/integration.rs b/src/types/entities/integration.rs index 4b42f463..16cd9914 100644 --- a/src/types/entities/integration.rs +++ b/src/types/entities/integration.rs @@ -6,9 +6,9 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::types::{ - Shared, entities::{Application, User}, utils::Snowflake, + Shared, }; #[derive(Default, Debug, Deserialize, Serialize, Clone)] @@ -44,7 +44,9 @@ pub struct IntegrationAccount { pub name: String, } -#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)] +#[derive( + Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, +)] #[serde(rename_all = "snake_case")] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", sqlx(rename_all = "snake_case"))] @@ -54,4 +56,4 @@ pub enum IntegrationType { Youtube, Discord, GuildSubscription, -} \ No newline at end of file +} diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index 0a8169b5..dbea3d5b 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -8,14 +8,16 @@ use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; use crate::types::{ - Shared, entities::{ Application, Attachment, Channel, Emoji, GuildMember, PublicUser, RoleSubscriptionData, Sticker, StickerItem, User, }, utils::Snowflake, + Shared, }; +use super::option_arc_rwlock_ptr_eq; + #[derive(Debug, Serialize, Deserialize, Default, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] /// Represents a message sent in a channel. @@ -83,6 +85,7 @@ pub struct Message { pub role_subscription_data: Option, } +#[cfg(not(tarpaulin_include))] impl PartialEq for Message { fn eq(&self, other: &Self) -> bool { self.id == other.id @@ -99,26 +102,31 @@ impl PartialEq for Message { && self.attachments == other.attachments && self.embeds == other.embeds && self.embeds == other.embeds + && self.reactions == other.reactions + && self.reactions == other.reactions && self.nonce == other.nonce && self.pinned == other.pinned && self.webhook_id == other.webhook_id && self.message_type == other.message_type && self.activity == other.activity && self.activity == other.activity + && self.application == other.application && self.application_id == other.application_id && self.message_reference == other.message_reference && self.message_reference == other.message_reference && self.flags == other.flags && self.referenced_message == other.referenced_message + && self.interaction == other.interaction && self.thread == other.thread && self.components == other.components + && self.components == other.components && self.sticker_items == other.sticker_items - // && self.position == other.position + && self.stickers == other.stickers && self.role_subscription_data == other.role_subscription_data } } -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Eq, Ord, PartialOrd)] +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Eq, Ord, PartialOrd, Copy)] /// # Reference /// See pub struct MessageReference { @@ -130,7 +138,7 @@ pub struct MessageReference { pub fail_if_not_exists: Option, } -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Eq, Ord, PartialOrd)] +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Eq, Ord, PartialOrd, Copy)] pub enum MessageReferenceType { /// A standard reference used by replies and system messages Default = 0, @@ -148,7 +156,18 @@ pub struct MessageInteraction { pub member: Option>, } -#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, Eq, PartialOrd, Ord)] +#[cfg(not(tarpaulin_include))] +impl PartialEq for MessageInteraction { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + && self.interaction_type == other.interaction_type + && self.name == other.name + && self.user == other.user + && option_arc_rwlock_ptr_eq(&self.member, &other.member) + } +} + +#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, Eq, PartialOrd, Ord, Hash)] pub struct AllowedMention { parse: Vec, roles: Vec, @@ -156,7 +175,7 @@ pub struct AllowedMention { replied_user: bool, } -#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, Eq, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, Eq, PartialOrd, Ord, Hash)] #[serde(rename_all = "snake_case")] pub enum AllowedMentionType { Roles, @@ -173,7 +192,7 @@ pub struct ChannelMention { name: String, } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Hash, Ord)] pub struct Embed { title: Option, #[serde(rename = "type")] @@ -191,7 +210,7 @@ pub struct Embed { fields: Option>, } -#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)] #[serde(rename_all = "snake_case")] pub enum EmbedType { #[deprecated] @@ -206,17 +225,17 @@ pub enum EmbedType { Link, PostPreview, Rich, - Video + Video, } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct EmbedFooter { text: String, icon_url: Option, proxy_icon_url: Option, } -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord, Hash)] pub struct EmbedImage { url: String, proxy_url: String, @@ -224,7 +243,7 @@ pub struct EmbedImage { width: Option, } -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord, Hash)] pub struct EmbedThumbnail { url: String, proxy_url: Option, @@ -232,7 +251,7 @@ pub struct EmbedThumbnail { width: Option, } -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord, Hash)] struct EmbedVideo { url: Option, proxy_url: Option, @@ -240,13 +259,13 @@ struct EmbedVideo { width: Option, } -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord, Hash)] pub struct EmbedProvider { name: Option, url: Option, } -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord, Hash)] pub struct EmbedAuthor { name: String, url: Option, @@ -254,7 +273,7 @@ pub struct EmbedAuthor { proxy_icon_url: Option, } -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, PartialOrd, Ord, Hash)] pub struct EmbedField { name: String, value: String, @@ -273,7 +292,7 @@ pub struct Reaction { pub emoji: Emoji, #[cfg(feature = "sqlx")] #[serde(skip)] - pub user_ids: Vec + pub user_ids: Vec, } #[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, Eq, PartialOrd, Ord)] @@ -297,7 +316,9 @@ pub struct MessageActivity { pub party_id: Option, } -#[derive(Debug, Default, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr, Eq, PartialOrd, Ord)] +#[derive( + Debug, Default, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr, Eq, PartialOrd, Ord, +)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[repr(u8)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] @@ -393,7 +414,7 @@ pub enum MessageType { CustomGift = 41, GuildGamingStatsPrompt = 42, /// A message sent when a user purchases a guild product - PurchaseNotification = 44 + PurchaseNotification = 44, } bitflags! { @@ -437,10 +458,10 @@ pub struct PartialEmoji { pub id: Option, pub name: String, #[serde(default)] - pub animated: bool + pub animated: bool, } -#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, PartialOrd)] +#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, PartialOrd, Ord, Eq, Hash)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[repr(u8)] diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index 4227e242..b413e8e8 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -141,3 +141,42 @@ impl IntoShared for T { Arc::new(RwLock::new(self)) } } + +/// Internal function to compare two `Arc>`s by comparing their pointers. +pub(crate) fn arc_rwlock_ptr_eq(a: &Arc>, b: &Arc>) -> bool { + Arc::ptr_eq(a, b) +} + +/// Internal function to compare two `Vec>>`s by comparing their pointers. +pub(crate) fn vec_arc_rwlock_ptr_eq(a: &Vec>>, b: &Vec>>) -> bool { + for (a, b) in a.iter().zip(b.iter()) { + if !arc_rwlock_ptr_eq(a, b) { + return false; + } + } + true +} + +/// Internal function to compare two `Option>>`s by comparing their pointers. +pub(crate) fn option_arc_rwlock_ptr_eq( + a: &Option>>, + b: &Option>>, +) -> bool { + match (a, b) { + (Some(a), Some(b)) => arc_rwlock_ptr_eq(a, b), + (None, None) => true, + _ => false, + } +} + +/// Internal function to compare two `Option>>>`s by comparing their pointers. +pub(crate) fn option_vec_arc_rwlock_ptr_eq( + a: &Option>>>, + b: &Option>>>, +) -> bool { + match (a, b) { + (Some(a), Some(b)) => vec_arc_rwlock_ptr_eq(a, b), + (None, None) => true, + _ => false, + } +} diff --git a/src/types/entities/ratelimits.rs b/src/types/entities/ratelimits.rs index 1823e763..dc084cf4 100644 --- a/src/types/entities/ratelimits.rs +++ b/src/types/entities/ratelimits.rs @@ -11,7 +11,9 @@ use crate::types::Snowflake; /// The different types of ratelimits that can be applied to a request. Includes "Baseline"-variants /// for when the Snowflake is not yet known. /// See for more information. -#[derive(Clone, Copy, Eq, PartialEq, Debug, Default, Hash, Serialize, Deserialize)] +#[derive( + Clone, Copy, Eq, PartialEq, Debug, Default, Hash, Serialize, Deserialize, PartialOrd, Ord, +)] pub enum LimitType { AuthRegister, AuthLogin, @@ -29,7 +31,7 @@ pub enum LimitType { /// A struct that represents the current ratelimits, either instance-wide or user-wide. /// See for more information. -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)] pub struct Limit { pub bucket: LimitType, pub limit: u64, diff --git a/src/types/entities/relationship.rs b/src/types/entities/relationship.rs index b5e2004a..e3276db8 100644 --- a/src/types/entities/relationship.rs +++ b/src/types/entities/relationship.rs @@ -8,7 +8,7 @@ use serde_repr::{Deserialize_repr, Serialize_repr}; use crate::types::{Shared, Snowflake}; -use super::PublicUser; +use super::{arc_rwlock_ptr_eq, PublicUser}; #[derive(Debug, Deserialize, Serialize, Clone, Default)] /// See @@ -21,16 +21,30 @@ pub struct Relationship { pub since: Option>, } +#[cfg(not(tarpaulin_include))] 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 + && arc_rwlock_ptr_eq(&self.user, &other.user) + && self.since == other.since } } -#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default, Eq, PartialEq)] +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Clone, + Default, + Eq, + PartialEq, + PartialOrd, + Ord, + Copy, + Hash, +)] #[repr(u8)] /// See pub enum RelationshipType { diff --git a/src/types/entities/role.rs b/src/types/entities/role.rs index 8c00b41c..20d2fcfe 100644 --- a/src/types/entities/role.rs +++ b/src/types/entities/role.rs @@ -51,7 +51,7 @@ pub struct RoleSubscriptionData { pub is_renewal: bool, } -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)] /// See pub struct RoleTags { #[serde(default)] diff --git a/src/types/entities/stage_instance.rs b/src/types/entities/stage_instance.rs index d48231b8..38e28170 100644 --- a/src/types/entities/stage_instance.rs +++ b/src/types/entities/stage_instance.rs @@ -21,7 +21,7 @@ pub struct StageInstance { pub guild_scheduled_event_id: Option, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] +#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See diff --git a/src/types/entities/sticker.rs b/src/types/entities/sticker.rs index 22affcbb..6fcc708b 100644 --- a/src/types/entities/sticker.rs +++ b/src/types/entities/sticker.rs @@ -7,6 +7,8 @@ use serde_repr::{Deserialize_repr, Serialize_repr}; use crate::types::{entities::User, utils::Snowflake, Shared}; +use super::option_arc_rwlock_ptr_eq; + #[derive(Debug, Serialize, Deserialize, Clone, Default)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] /// Represents a sticker that can be sent in messages. @@ -33,22 +35,7 @@ pub struct Sticker { pub sort_value: Option, } -impl std::hash::Hash for Sticker { - fn hash(&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); - } -} - +#[cfg(not(tarpaulin_include))] impl PartialEq for Sticker { fn eq(&self, other: &Self) -> bool { self.id == other.id @@ -61,65 +48,16 @@ impl PartialEq for Sticker { && self.format_type == other.format_type && self.available == other.available && self.guild_id == other.guild_id + && option_arc_rwlock_ptr_eq(&self.user, &other.user) && self.sort_value == other.sort_value } } -impl PartialOrd for Sticker { - fn partial_cmp(&self, other: &Self) -> Option { - match self.id.partial_cmp(&other.id) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.pack_id.partial_cmp(&other.pack_id) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.name.partial_cmp(&other.name) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.description.partial_cmp(&other.description) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.tags.partial_cmp(&other.tags) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.asset.partial_cmp(&other.asset) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.sticker_type.partial_cmp(&other.sticker_type) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.format_type.partial_cmp(&other.format_type) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.available.partial_cmp(&other.available) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - match self.guild_id.partial_cmp(&other.guild_id) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - self.sort_value.partial_cmp(&other.sort_value) - } -} - impl Sticker { pub fn tags(&self) -> Vec { - self.tags - .as_ref() - .map_or(vec![], |s| - s.split(',') - .map(|tag| tag.trim().to_string()) - .collect() - ) + self.tags.as_ref().map_or(vec![], |s| { + s.split(',').map(|tag| tag.trim().to_string()).collect() + }) } } @@ -136,7 +74,9 @@ pub struct StickerItem { pub format_type: StickerFormatType, } -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Serialize_repr, Deserialize_repr)] +#[derive( + Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Serialize_repr, Deserialize_repr, +)] #[repr(u8)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename = "SCREAMING_SNAKE_CASE")] @@ -150,7 +90,9 @@ pub enum StickerType { Guild = 2, } -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Serialize_repr, Deserialize_repr)] +#[derive( + Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Serialize_repr, Deserialize_repr, +)] #[repr(u8)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] /// # Reference @@ -169,7 +111,10 @@ pub enum StickerFormatType { impl StickerFormatType { pub fn is_animated(&self) -> bool { - matches!(self, StickerFormatType::APNG | StickerFormatType::LOTTIE | StickerFormatType::GIF) + matches!( + self, + StickerFormatType::APNG | StickerFormatType::LOTTIE | StickerFormatType::GIF + ) } pub const fn to_mime(&self) -> &'static str { diff --git a/src/types/entities/team.rs b/src/types/entities/team.rs index 8fed8190..4748fad3 100644 --- a/src/types/entities/team.rs +++ b/src/types/entities/team.rs @@ -5,8 +5,10 @@ use serde::{Deserialize, Serialize}; use crate::types::entities::User; -use crate::types::Snowflake; use crate::types::Shared; +use crate::types::Snowflake; + +use super::arc_rwlock_ptr_eq; #[derive(Debug, Deserialize, Serialize, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -19,6 +21,17 @@ pub struct Team { pub owner_user_id: Snowflake, } +#[cfg(not(tarpaulin_include))] +impl PartialEq for Team { + fn eq(&self, other: &Self) -> bool { + self.icon == other.icon + && self.id == other.id + && self.members == other.members + && self.name == other.name + && self.owner_user_id == other.owner_user_id + } +} + #[derive(Debug, Deserialize, Serialize, Clone)] pub struct TeamMember { pub membership_state: u8, @@ -26,3 +39,13 @@ pub struct TeamMember { pub team_id: Snowflake, pub user: Shared, } + +#[cfg(not(tarpaulin_include))] +impl PartialEq for TeamMember { + fn eq(&self, other: &Self) -> bool { + self.membership_state == other.membership_state + && self.permissions == other.permissions + && self.team_id == other.team_id + && arc_rwlock_ptr_eq(&self.user, &other.user) + } +} diff --git a/src/types/entities/user_settings.rs b/src/types/entities/user_settings.rs index fa3433af..395db2d9 100644 --- a/src/types/entities/user_settings.rs +++ b/src/types/entities/user_settings.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use crate::types::Shared; use serde_aux::field_attributes::deserialize_option_number_from_string; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Copy, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "lowercase")] pub enum UserStatus { @@ -26,7 +26,7 @@ impl std::fmt::Display for UserStatus { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Copy, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "lowercase")] pub enum UserTheme { @@ -136,7 +136,7 @@ pub struct CustomStatus { pub text: Option, } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)] pub struct FriendSourceFlags { pub all: bool, } diff --git a/src/types/entities/voice_state.rs b/src/types/entities/voice_state.rs index 9953b7bf..4491beaa 100644 --- a/src/types/entities/voice_state.rs +++ b/src/types/entities/voice_state.rs @@ -25,6 +25,8 @@ use crate::types::{ utils::Snowflake, }; +use super::option_arc_rwlock_ptr_eq; + /// The VoiceState struct. Note, that Discord does not have an `id` field for this, whereas Spacebar /// does. /// @@ -54,6 +56,28 @@ pub struct VoiceState { pub id: Option, // Only exists on Spacebar } +#[cfg(not(tarpaulin_include))] +impl PartialEq for VoiceState { + fn eq(&self, other: &Self) -> bool { + self.guild_id == other.guild_id + && self.guild == other.guild + && self.channel_id == other.channel_id + && self.user_id == other.user_id + && option_arc_rwlock_ptr_eq(&self.member, &other.member) + && self.session_id == other.session_id + && self.token == other.token + && self.deaf == other.deaf + && self.mute == other.mute + && self.self_deaf == other.self_deaf + && self.self_mute == other.self_mute + && self.self_stream == other.self_stream + && self.self_video == other.self_video + && self.suppress == other.suppress + && self.request_to_speak_timestamp == other.request_to_speak_timestamp + && self.id == other.id + } +} + #[cfg(feature = "client")] impl Updateable for VoiceState { #[cfg(not(tarpaulin_include))] diff --git a/src/types/entities/webhook.rs b/src/types/entities/webhook.rs index aea9f412..19f6203f 100644 --- a/src/types/entities/webhook.rs +++ b/src/types/entities/webhook.rs @@ -25,6 +25,8 @@ use crate::types::{ utils::Snowflake, }; +use super::option_arc_rwlock_ptr_eq; + /// See #[derive(Serialize, Deserialize, Debug, Default, Clone)] #[cfg_attr(feature = "client", derive(Updateable, Composite))] @@ -36,7 +38,7 @@ pub struct Webhook { pub name: String, pub avatar: String, pub token: String, - pub guild_id: Snowflake, + pub guild_id: Snowflake, pub channel_id: Snowflake, pub application_id: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -49,7 +51,26 @@ pub struct Webhook { pub url: Option, } -#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy)] +#[cfg(not(tarpaulin_include))] +impl PartialEq for Webhook { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + && self.webhook_type == other.webhook_type + && self.name == other.name + && self.avatar == other.avatar + && self.token == other.token + && self.guild_id == other.guild_id + && self.channel_id == other.channel_id + && self.application_id == other.application_id + && option_arc_rwlock_ptr_eq(&self.user, &other.user) + && option_arc_rwlock_ptr_eq(&self.source_guild, &other.source_guild) + && self.url == other.url + } +} + +#[derive( + Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, +)] #[repr(u8)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] pub enum WebhookType { @@ -57,4 +78,4 @@ pub enum WebhookType { Incoming = 1, ChannelFollower = 2, Application = 3, -} \ No newline at end of file +} diff --git a/src/types/errors.rs b/src/types/errors.rs index f417aef4..7e2aa780 100644 --- a/src/types/errors.rs +++ b/src/types/errors.rs @@ -21,18 +21,18 @@ pub enum Error { #[error(transparent)] Guild(#[from] GuildError), - + #[error("Invalid flags value: {0}")] - InvalidFlags(u64) + InvalidFlags(u64), } -#[derive(Debug, PartialEq, Eq, thiserror::Error)] +#[derive(Debug, PartialEq, Eq, thiserror::Error, Copy, Clone)] pub enum GuildError { #[error("Invalid Guild Feature")] InvalidGuildFeature, } -#[derive(Debug, PartialEq, Eq, thiserror::Error)] +#[derive(Debug, PartialEq, Eq, thiserror::Error, Copy, Clone)] pub enum FieldFormatError { #[error("Password must be between 1 and 72 characters.")] PasswordError, diff --git a/src/types/events/call.rs b/src/types/events/call.rs index 5dc59113..7efdce10 100644 --- a/src/types/events/call.rs +++ b/src/types/events/call.rs @@ -39,7 +39,19 @@ pub struct CallUpdate { pub channel_id: Snowflake, } -#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq, WebSocketEvent)] +#[derive( + Debug, + Deserialize, + Serialize, + Default, + Clone, + PartialEq, + Eq, + WebSocketEvent, + Copy, + PartialOrd, + Ord, +)] /// Officially Undocumented; /// Deletes a ringing call; /// Ex: {"t":"CALL_DELETE","s":8,"op":0,"d":{"channel_id":"837609115475771392"}} @@ -47,7 +59,19 @@ pub struct CallDelete { pub channel_id: Snowflake, } -#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq, WebSocketEvent)] +#[derive( + Debug, + Deserialize, + Serialize, + Default, + Clone, + PartialEq, + Eq, + WebSocketEvent, + Copy, + PartialOrd, + Ord, +)] /// Officially Undocumented; /// See ; /// @@ -55,4 +79,3 @@ pub struct CallDelete { pub struct CallSync { pub channel_id: Snowflake, } - diff --git a/src/types/events/channel.rs b/src/types/events/channel.rs index 73d89f61..a51a74b0 100644 --- a/src/types/events/channel.rs +++ b/src/types/events/channel.rs @@ -20,7 +20,7 @@ use crate::types::IntoShared; #[cfg(feature = "client")] use crate::types::Guild; -#[derive(Debug, Default, Deserialize, Serialize, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, WebSocketEvent, Copy, PartialEq, Clone, Eq, Hash, PartialOrd, Ord)] /// See pub struct ChannelPinsUpdate { pub guild_id: Option, @@ -86,7 +86,7 @@ pub struct ChannelUnreadUpdate { pub guild_id: Snowflake, } -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] /// Contains very few fields from [Channel] /// See also [ChannelUnreadUpdate] pub struct ChannelUnreadUpdateObject { diff --git a/src/types/events/guild.rs b/src/types/events/guild.rs index f2cc009c..f599d1fa 100644 --- a/src/types/events/guild.rs +++ b/src/types/events/guild.rs @@ -9,8 +9,8 @@ use serde::{Deserialize, Serialize}; use crate::types::entities::{Guild, PublicUser, UnavailableGuild}; use crate::types::events::WebSocketEvent; use crate::types::{ - AuditLogEntry, Emoji, GuildMember, GuildScheduledEvent, JsonField, RoleObject, - Snowflake, SourceUrlField, Sticker, + AuditLogEntry, Emoji, GuildMember, GuildScheduledEvent, JsonField, RoleObject, Snowflake, + SourceUrlField, Sticker, }; use super::PresenceUpdate; @@ -18,11 +18,21 @@ use super::PresenceUpdate; #[cfg(feature = "client")] use super::UpdateMessage; #[cfg(feature = "client")] -use crate::types::Shared; -#[cfg(feature = "client")] use crate::types::IntoShared; +#[cfg(feature = "client")] +use crate::types::Shared; -#[derive(Debug, Deserialize, Serialize, Default, Clone, SourceUrlField, JsonField, WebSocketEvent)] +#[derive( + Debug, + Deserialize, + Serialize, + Default, + Clone, + SourceUrlField, + JsonField, + WebSocketEvent, + PartialEq, +)] /// See ; /// 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 @@ -49,7 +59,7 @@ impl UpdateMessage for GuildCreate { fn update(&mut self, _: Shared) {} } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] #[serde(untagged)] pub enum GuildCreateDataOption { UnavailableGuild(UnavailableGuild), @@ -62,7 +72,31 @@ impl Default for GuildCreateDataOption { } } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Clone, PartialEq)] +pub enum GuildEvents { + Create(GuildCreate), + Update(GuildUpdate), + Delete(GuildDelete), + BanAdd(GuildBanAdd), + BanRemove(GuildBanRemove), + EmojisUpdate(GuildEmojisUpdate), + StickersUpdate(GuildStickersUpdate), + IntegrationsUpdate(GuildIntegrationsUpdate), + MemberAdd(GuildMemberAdd), + MemberRemove(GuildMemberRemove), + MemberUpdate(GuildMemberUpdate), + MembersChunk(GuildMembersChunk), + RoleCreate(GuildRoleCreate), + RoleUpdate(GuildRoleUpdate), + RoleDelete(GuildRoleDelete), + ScheduledEventCreate(GuildScheduledEventCreate), + ScheduledEventUpdate(GuildScheduledEventUpdate), + ScheduledEventDelete(GuildScheduledEventDelete), + ScheduledEventUserAdd(GuildScheduledEventUserAdd), + ScheduledEventUserRemove(GuildScheduledEventUserRemove), + AuditLogEntryCreate(GuildAuditLogEntryCreate), +} +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)] /// See ; /// Received to give info about a user being banned from a guild; pub struct GuildBanAdd { @@ -70,7 +104,7 @@ pub struct GuildBanAdd { pub user: PublicUser, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)] /// See ; /// Received to give info about a user being unbanned from a guild; pub struct GuildBanRemove { @@ -78,7 +112,17 @@ pub struct GuildBanRemove { pub user: PublicUser, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, SourceUrlField, JsonField, WebSocketEvent)] +#[derive( + Debug, + Default, + Deserialize, + Serialize, + Clone, + SourceUrlField, + JsonField, + WebSocketEvent, + PartialEq, +)] /// See ; /// Received to give info about a guild being updated; pub struct GuildUpdate { @@ -98,7 +142,17 @@ impl UpdateMessage for GuildUpdate { } } -#[derive(Debug, Default, Deserialize, Serialize, Clone, SourceUrlField, JsonField, WebSocketEvent)] +#[derive( + Debug, + Default, + Deserialize, + Serialize, + Clone, + SourceUrlField, + JsonField, + WebSocketEvent, + PartialEq, +)] /// See ; /// Received to tell the client about a guild being deleted; pub struct GuildDelete { @@ -119,7 +173,7 @@ impl UpdateMessage for GuildDelete { fn update(&mut self, _: Shared) {} } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)] /// See ; /// Received to the client about an audit log entry being added; pub struct GuildAuditLogEntryCreate { @@ -127,7 +181,7 @@ pub struct GuildAuditLogEntryCreate { pub entry: AuditLogEntry, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)] /// See ; /// Received to tell the client about a change to a guild's emoji list; pub struct GuildEmojisUpdate { @@ -135,7 +189,7 @@ pub struct GuildEmojisUpdate { pub emojis: Vec, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)] /// See ; /// Received to tell the client about a change to a guild's sticker list; pub struct GuildStickersUpdate { @@ -143,13 +197,13 @@ pub struct GuildStickersUpdate { pub stickers: Vec, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq, Copy, Eq, Hash, PartialOrd, Ord)] /// See pub struct GuildIntegrationsUpdate { pub guild_id: Snowflake, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)] /// See ; /// Received to tell the client about a user joining a guild; pub struct GuildMemberAdd { @@ -158,7 +212,7 @@ pub struct GuildMemberAdd { pub guild_id: Snowflake, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)] /// See ; /// Received to tell the client about a user leaving a guild; pub struct GuildMemberRemove { @@ -166,7 +220,7 @@ pub struct GuildMemberRemove { pub user: PublicUser, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)] /// See pub struct GuildMemberUpdate { pub guild_id: Snowflake, @@ -182,7 +236,7 @@ pub struct GuildMemberUpdate { pub communication_disabled_until: Option>, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)] /// See pub struct GuildMembersChunk { pub guild_id: Snowflake, @@ -194,7 +248,17 @@ pub struct GuildMembersChunk { pub nonce: Option, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField, WebSocketEvent)] +#[derive( + Debug, + Default, + Deserialize, + Serialize, + Clone, + JsonField, + SourceUrlField, + WebSocketEvent, + PartialEq, +)] /// See pub struct GuildRoleCreate { pub guild_id: Snowflake, @@ -214,13 +278,21 @@ impl UpdateMessage for GuildRoleCreate { fn update(&mut self, object_to_update: Shared) { let mut object_to_update = object_to_update.write().unwrap(); - object_to_update - .roles - .push(self.role.clone().into_shared()); + object_to_update.roles.push(self.role.clone().into_shared()); } } -#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField, SourceUrlField, WebSocketEvent)] +#[derive( + Debug, + Default, + Deserialize, + Serialize, + Clone, + JsonField, + SourceUrlField, + WebSocketEvent, + PartialEq, +)] /// See pub struct GuildRoleUpdate { pub guild_id: Snowflake, @@ -244,35 +316,35 @@ impl UpdateMessage for GuildRoleUpdate { } } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] /// See pub struct GuildRoleDelete { pub guild_id: Snowflake, pub role_id: Snowflake, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)] /// See pub struct GuildScheduledEventCreate { #[serde(flatten)] pub event: GuildScheduledEvent, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)] /// See pub struct GuildScheduledEventUpdate { #[serde(flatten)] pub event: GuildScheduledEvent, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq)] /// See pub struct GuildScheduledEventDelete { #[serde(flatten)] pub event: GuildScheduledEvent, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq, Copy, Eq, Hash, PartialOrd, Ord)] /// See pub struct GuildScheduledEventUserAdd { pub guild_scheduled_event_id: Snowflake, @@ -280,7 +352,7 @@ pub struct GuildScheduledEventUserAdd { pub guild_id: Snowflake, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, PartialEq, Copy, Eq, Hash, PartialOrd, Ord)] /// See pub struct GuildScheduledEventUserRemove { pub guild_scheduled_event_id: Snowflake, diff --git a/src/types/events/heartbeat.rs b/src/types/events/heartbeat.rs index b7a00246..6008ffba 100644 --- a/src/types/events/heartbeat.rs +++ b/src/types/events/heartbeat.rs @@ -5,13 +5,13 @@ use crate::types::events::WebSocketEvent; use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Deserialize, Serialize, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, WebSocketEvent, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct GatewayHeartbeat { pub op: u8, pub d: Option, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct GatewayHeartbeatAck { pub op: i32, } diff --git a/src/types/events/hello.rs b/src/types/events/hello.rs index f72720bd..779b657c 100644 --- a/src/types/events/hello.rs +++ b/src/types/events/hello.rs @@ -7,13 +7,13 @@ use chorus_macros::WebSocketEvent; use serde::{Deserialize, Serialize}; /// Received on gateway init, tells the client how often to send heartbeats; -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent, Copy, Hash, PartialOrd, Ord)] pub struct GatewayHello { pub op: i32, pub d: HelloData, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, Copy, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, Copy, WebSocketEvent, Hash, PartialOrd, Ord)] /// Contains info on how often the client should send heartbeats to the server; pub struct HelloData { /// How often a client should send heartbeats, in milliseconds diff --git a/src/types/events/integration.rs b/src/types/events/integration.rs index cf167c90..716cc30c 100644 --- a/src/types/events/integration.rs +++ b/src/types/events/integration.rs @@ -23,7 +23,7 @@ pub struct IntegrationUpdate { pub guild_id: Snowflake, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] /// See pub struct IntegrationDelete { pub id: Snowflake, diff --git a/src/types/events/invalid_session.rs b/src/types/events/invalid_session.rs index ee94eeb3..12b8fb97 100644 --- a/src/types/events/invalid_session.rs +++ b/src/types/events/invalid_session.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use super::WebSocketEvent; -#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)] /// Your session is now invalid. /// /// Either reauthenticate and reidentify or resume if possible. diff --git a/src/types/events/message.rs b/src/types/events/message.rs index 62a9d9d9..1b855dfc 100644 --- a/src/types/events/message.rs +++ b/src/types/events/message.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use crate::types::{ entities::{Emoji, GuildMember, Message, PublicUser}, - Snowflake, WebSocketEvent + Snowflake, WebSocketEvent, }; use chorus_macros::WebSocketEvent; @@ -51,7 +51,20 @@ pub struct MessageUpdate { pub mentions: Option>, } -#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] +#[derive( + Debug, + Serialize, + Deserialize, + Default, + Clone, + WebSocketEvent, + Copy, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, +)] /// # Reference /// See pub struct MessageDelete { @@ -60,7 +73,19 @@ pub struct MessageDelete { pub guild_id: Option, } -#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] +#[derive( + Debug, + Serialize, + Deserialize, + Default, + Clone, + WebSocketEvent, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, +)] /// # Reference /// See pub struct MessageDeleteBulk { @@ -92,7 +117,20 @@ pub struct MessageReactionRemove { pub emoji: Emoji, } -#[derive(Debug, Serialize, Deserialize, Default, Clone, WebSocketEvent)] +#[derive( + Debug, + Serialize, + Deserialize, + Default, + Clone, + WebSocketEvent, + Copy, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, +)] /// # Reference /// See pub struct MessageReactionRemoveAll { @@ -131,4 +169,3 @@ pub struct MessageACK { pub flags: Option, pub channel_id: Snowflake, } - diff --git a/src/types/events/reconnect.rs b/src/types/events/reconnect.rs index 558d9535..17381b2a 100644 --- a/src/types/events/reconnect.rs +++ b/src/types/events/reconnect.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use super::WebSocketEvent; -#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] /// "The reconnect event is dispatched when a client should reconnect to the Gateway (and resume their existing session, if they have one). This event usually occurs during deploys to migrate sessions gracefully off old hosts" /// /// # Reference diff --git a/src/types/events/relationship.rs b/src/types/events/relationship.rs index b12d73df..eaeea562 100644 --- a/src/types/events/relationship.rs +++ b/src/types/events/relationship.rs @@ -13,7 +13,7 @@ pub struct RelationshipAdd { pub should_notify: bool, } -#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)] /// See pub struct RelationshipRemove { pub id: Snowflake, diff --git a/src/types/events/voice_gateway/speaking.rs b/src/types/events/voice_gateway/speaking.rs index 7a505fde..0d503453 100644 --- a/src/types/events/voice_gateway/speaking.rs +++ b/src/types/events/voice_gateway/speaking.rs @@ -13,7 +13,7 @@ use chorus_macros::WebSocketEvent; /// Essentially, what allows us to send UDP data and lights up the green circle around your avatar. /// /// See -#[derive(Debug, Deserialize, Serialize, Clone, Default, WebSocketEvent)] +#[derive(Debug, Deserialize, Serialize, Clone, Default, WebSocketEvent, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)] pub struct Speaking { /// Data about the audio we're transmitting. /// diff --git a/src/types/events/webhooks.rs b/src/types/events/webhooks.rs index 3f09492c..be39e3d9 100644 --- a/src/types/events/webhooks.rs +++ b/src/types/events/webhooks.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::types::{Snowflake, WebSocketEvent}; use chorus_macros::WebSocketEvent; -#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] /// See pub struct WebhooksUpdate { pub guild_id: Snowflake, diff --git a/src/types/interfaces/interaction.rs b/src/types/interfaces/interaction.rs index f88eaf93..1a4bb6ae 100644 --- a/src/types/interfaces/interaction.rs +++ b/src/types/interfaces/interaction.rs @@ -20,7 +20,7 @@ pub struct Interaction { pub version: i32, } -#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, Eq, PartialOrd, Ord, Hash, Copy)] pub enum InteractionType { #[default] SelfCommand = 0, @@ -28,7 +28,7 @@ pub enum InteractionType { ApplicationCommand = 2, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Copy, Eq, Hash, PartialOrd, Ord)] pub enum InteractionResponseType { SelfCommandResponse = 0, Pong = 1, @@ -38,7 +38,7 @@ pub enum InteractionResponseType { AcknowledgeWithSource = 5, } -#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, Eq, Hash, PartialOrd, Ord)] pub struct InteractionApplicationCommandCallbackData { pub tts: bool, pub content: String, diff --git a/src/types/schema/apierror.rs b/src/types/schema/apierror.rs index 0dd1f6f0..4a242c80 100644 --- a/src/types/schema/apierror.rs +++ b/src/types/schema/apierror.rs @@ -6,7 +6,7 @@ use poem::{http::StatusCode, IntoResponse, Response}; use serde_json::{json, Value}; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, Copy, Clone, PartialEq, Eq, Hash)] pub enum APIError { #[error(transparent)] Auth(#[from] AuthError), @@ -20,7 +20,7 @@ impl APIError { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, Clone, Copy, PartialEq, Eq, Hash)] pub enum AuthError { #[error("INVALID_LOGIN")] InvalidLogin, diff --git a/src/types/schema/audit_log.rs b/src/types/schema/audit_log.rs index ddee8325..e5c19e59 100644 --- a/src/types/schema/audit_log.rs +++ b/src/types/schema/audit_log.rs @@ -1,5 +1,8 @@ +use crate::types::{ + ApplicationCommand, AuditLogActionType, AuditLogEntry, AutoModerationRule, Channel, + GuildScheduledEvent, Integration, Snowflake, User, Webhook, +}; use serde::{Deserialize, Serialize}; -use crate::types::{ApplicationCommand, AuditLogActionType, AuditLogEntry, AutoModerationRule, Channel, GuildScheduledEvent, Integration, Snowflake, User, Webhook}; #[derive(Debug, Deserialize, Serialize, Clone)] pub struct AuditLogObject { @@ -13,11 +16,13 @@ pub struct AuditLogObject { pub webhooks: Vec, } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive( + Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default, +)] pub struct GetAuditLogsQuery { pub before: Option, pub after: Option, pub limit: Option, pub user_id: Option, - pub action_type: Option -} \ No newline at end of file + pub action_type: Option, +} diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index c3c02f49..0a3d4684 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -169,7 +169,7 @@ pub struct AddChannelRecipientSchema { } /// See -#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq)] +#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Copy, Hash)] pub struct ModifyChannelPositionsSchema { pub id: Snowflake, pub position: Option, @@ -178,7 +178,7 @@ pub struct ModifyChannelPositionsSchema { } /// See -#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq)] +#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Copy, Hash)] pub struct AddFollowingChannelSchema { pub webhook_channel_id: Snowflake, } diff --git a/src/types/schema/guild.rs b/src/types/schema/guild.rs index 6405d946..f53494ec 100644 --- a/src/types/schema/guild.rs +++ b/src/types/schema/guild.rs @@ -2,16 +2,20 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::collections::HashMap; use bitflags::bitflags; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; +use std::collections::HashMap; use crate::types::entities::Channel; use crate::types::types::guild_configuration::GuildFeatures; -use crate::types::{Emoji, ExplicitContentFilterLevel, GenericSearchQueryWithLimit, MessageNotificationLevel, Snowflake, Sticker, StickerFormatType, SystemChannelFlags, VerificationLevel, WelcomeScreenChannel}; +use crate::types::{ + Emoji, ExplicitContentFilterLevel, GenericSearchQueryWithLimit, MessageNotificationLevel, + Snowflake, Sticker, StickerFormatType, SystemChannelFlags, VerificationLevel, + WelcomeScreenChannel, +}; -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +#[derive(Debug, Deserialize, Serialize, Clone)] #[serde(rename_all = "snake_case")] /// Represents the schema which needs to be sent to create a Guild. /// See: @@ -25,6 +29,19 @@ pub struct GuildCreateSchema { pub rules_channel_id: Option, } +#[cfg(not(tarpaulin_include))] +impl PartialEq for GuildCreateSchema { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + && self.region == other.region + && self.icon == other.icon + && self.channels == other.channels + && self.guild_template_code == other.guild_template_code + && self.system_channel_id == other.system_channel_id + && self.rules_channel_id == other.rules_channel_id + } +} + #[derive(Debug, Deserialize, Serialize, Default, Clone, Copy, Eq, PartialEq)] #[serde(rename_all = "snake_case")] /// Represents the schema which needs to be sent to create a Guild Ban. @@ -77,7 +94,7 @@ pub struct GuildModifySchema { pub premium_progress_bar_enabled: Option, } -#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)] pub struct GetUserGuildSchema { pub before: Option, pub after: Option, @@ -152,7 +169,7 @@ impl Default for GuildMemberSearchSchema { } } -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Eq, Ord)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Eq, Ord, Copy, Hash)] pub struct GuildGetMembersQuery { pub limit: Option, pub after: Option, @@ -206,7 +223,7 @@ pub struct ModifyGuildMemberProfileSchema { pub emoji_id: Option, } -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Eq, Ord)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Eq, Ord, Copy, Hash)] /// The limit argument is a number between 1 and 1000. pub struct GuildBansQuery { pub before: Option, @@ -214,7 +231,6 @@ pub struct GuildBansQuery { pub limit: Option, } - /// Max query length is 32 characters. /// The limit argument is a number between 1 and 10, defaults to 10. pub type GuildBansSearchQuery = GenericSearchQueryWithLimit; @@ -262,7 +278,7 @@ pub struct GuildDiscoveryNsfwProperties { pub description_banned_keywords: Vec, } -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Copy)] /// Activity metrics are recalculated weekly, as an 8-week rolling average. If they are not yet eligible to be calculated, all fields will be null. /// /// # Reference: @@ -283,7 +299,7 @@ pub struct EmojiCreateSchema { /// See pub image: String, #[serde(default)] - pub roles: Vec + pub roles: Vec, } #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] @@ -291,7 +307,7 @@ pub struct EmojiCreateSchema { /// See pub struct EmojiModifySchema { pub name: Option, - pub roles: Option> + pub roles: Option>, } #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] @@ -303,10 +319,10 @@ pub struct GuildPruneQuerySchema { #[serde(default, skip_serializing_if = "Option::is_none")] pub compute_prune_count: Option, #[serde(default)] - pub include_roles: Vec + pub include_roles: Vec, } -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Copy)] /// # Reference: /// See pub struct GuildPruneResult { @@ -325,7 +341,7 @@ pub struct GuildCreateStickerSchema { pub tags: Option, pub file_data: Vec, #[serde(skip)] - pub sticker_format_type: StickerFormatType + pub sticker_format_type: StickerFormatType, } impl GuildCreateStickerSchema { @@ -333,7 +349,10 @@ impl GuildCreateStickerSchema { pub async fn from_multipart(mut multipart: poem::web::Multipart) -> Result { let mut _self = GuildCreateStickerSchema::default(); while let Some(field) = multipart.next_field().await? { - let name = field.name().ok_or(poem::Error::from_string("All fields must be named", poem::http::StatusCode::BAD_REQUEST))?; + let name = field.name().ok_or(poem::Error::from_string( + "All fields must be named", + poem::http::StatusCode::BAD_REQUEST, + ))?; match name { "name" => { _self.name = field.text().await?; @@ -346,17 +365,35 @@ impl GuildCreateStickerSchema { } "file_data" => { if _self.name.is_empty() { - _self.name = field.file_name().map(String::from).ok_or(poem::Error::from_string("File name must be set", poem::http::StatusCode::BAD_REQUEST))?; + _self.name = + field + .file_name() + .map(String::from) + .ok_or(poem::Error::from_string( + "File name must be set", + poem::http::StatusCode::BAD_REQUEST, + ))?; } - _self.sticker_format_type = StickerFormatType::from_mime(field.content_type().ok_or(poem::Error::from_string("Content type must be set", poem::http::StatusCode::BAD_REQUEST))?).ok_or(poem::Error::from_string("Unknown sticker format", poem::http::StatusCode::BAD_REQUEST))?; + _self.sticker_format_type = StickerFormatType::from_mime( + field.content_type().ok_or(poem::Error::from_string( + "Content type must be set", + poem::http::StatusCode::BAD_REQUEST, + ))?, + ) + .ok_or(poem::Error::from_string( + "Unknown sticker format", + poem::http::StatusCode::BAD_REQUEST, + ))?; _self.file_data = field.bytes().await?; } _ => {} } - } if _self.name.is_empty() || _self.file_data.is_empty() { - return Err(poem::Error::from_string("At least the name and file_data are required", poem::http::StatusCode::BAD_REQUEST)); + return Err(poem::Error::from_string( + "At least the name and file_data are required", + poem::http::StatusCode::BAD_REQUEST, + )); } Ok(_self) @@ -366,7 +403,12 @@ impl GuildCreateStickerSchema { pub fn to_multipart(&self) -> reqwest::multipart::Form { let mut form = reqwest::multipart::Form::new() .text("name", self.name.clone()) - .part("file_data", reqwest::multipart::Part::bytes(self.file_data.clone()).mime_str(self.sticker_format_type.to_mime()).unwrap()); + .part( + "file_data", + reqwest::multipart::Part::bytes(self.file_data.clone()) + .mime_str(self.sticker_format_type.to_mime()) + .unwrap(), + ); if let Some(description) = &self.description { form = form.text("description", description.to_owned()); @@ -388,7 +430,7 @@ pub struct GuildModifyStickerSchema { #[serde(default)] pub description: Option, #[serde(default)] - pub tags: Option + pub tags: Option, } #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] @@ -408,5 +450,5 @@ pub struct GuildTemplateCreateSchema { /// Name of the template (1-100 characters) pub name: String, /// Description of the template (max 120 characters) - pub description: Option + pub description: Option, } diff --git a/src/types/schema/message.rs b/src/types/schema/message.rs index 4d50b25e..e8d57c7e 100644 --- a/src/types/schema/message.rs +++ b/src/types/schema/message.rs @@ -7,7 +7,9 @@ use serde::{Deserialize, Serialize}; use crate::types::entities::{ AllowedMention, Component, Embed, MessageReference, PartialDiscordFileAttachment, }; -use crate::types::{Attachment, EmbedType, Message, MessageFlags, MessageType, ReactionType, Snowflake}; +use crate::types::{ + Attachment, EmbedType, Message, MessageFlags, MessageType, ReactionType, Snowflake, +}; #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)] #[serde(rename_all = "snake_case")] @@ -25,7 +27,7 @@ pub struct MessageSendSchema { pub attachments: Option>, } -#[derive(Debug)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum MessageSearchEndpoint { GuildChannel(Snowflake), Channel(Snowflake), @@ -102,7 +104,7 @@ impl std::default::Default for MessageSearchQuery { } } -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)] #[serde(rename_all = "snake_case")] pub enum AuthorType { User, @@ -116,7 +118,7 @@ pub enum AuthorType { NotWebhook, } -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)] #[serde(rename_all = "snake_case")] pub enum HasType { Image, @@ -148,15 +150,19 @@ pub enum HasType { NotSnapshot, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive( + Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, +)] #[serde(rename_all = "snake_case")] pub enum SortType { #[default] Timestamp, - Relevance + Relevance, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive( + Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, +)] pub enum SortOrder { #[default] #[serde(rename = "desc")] @@ -198,10 +204,10 @@ pub struct MessageModifySchema { pub attachments: Option>, } -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Copy, Eq, Hash, Ord)] pub struct ReactionQuerySchema { pub after: Option, pub limit: Option, #[serde(rename = "type")] - pub reaction_type: Option -} \ No newline at end of file + pub reaction_type: Option, +} diff --git a/src/types/schema/role.rs b/src/types/schema/role.rs index 5dce8773..805d0263 100644 --- a/src/types/schema/role.rs +++ b/src/types/schema/role.rs @@ -2,10 +2,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use serde::{Deserialize, Serialize}; use crate::types::{PermissionFlags, Snowflake}; +use serde::{Deserialize, Serialize}; -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] #[serde(rename_all = "snake_case")] /// Represents the schema which needs to be sent to create or modify a Role. /// See: [https://docs.spacebar.chat/routes/#cmp--schemas-rolemodifyschema](https://docs.spacebar.chat/routes/#cmp--schemas-rolemodifyschema) @@ -20,7 +20,7 @@ pub struct RoleCreateModifySchema { pub position: Option, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[serde(rename_all = "snake_case")] /// Represents the schema which needs to be sent to update a roles' position. /// See: [https://docs.spacebar.chat/routes/#cmp--schemas-rolepositionupdateschema](https://docs.spacebar.chat/routes/#cmp--schemas-rolepositionupdateschema) diff --git a/src/types/schema/voice_state.rs b/src/types/schema/voice_state.rs index d5576ad2..3beafa6e 100644 --- a/src/types/schema/voice_state.rs +++ b/src/types/schema/voice_state.rs @@ -1,8 +1,8 @@ +use crate::types::Snowflake; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::types::Snowflake; -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Copy)] /// # Reference: /// See pub struct VoiceStateUpdateSchema { @@ -12,4 +12,4 @@ pub struct VoiceStateUpdateSchema { pub suppress: Option, /// The time at which the user requested to speak pub request_to_speak_timestamp: Option>, -} \ No newline at end of file +} diff --git a/src/types/utils/serde.rs b/src/types/utils/serde.rs index 544a3052..da41f4ac 100644 --- a/src/types/utils/serde.rs +++ b/src/types/utils/serde.rs @@ -1,13 +1,12 @@ -use core::fmt; use chrono::{LocalResult, NaiveDateTime}; -use serde::{de, Deserialize, Deserializer}; +use core::fmt; use serde::de::Error; +use serde::{de, Deserialize, Deserializer}; #[doc(hidden)] -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub struct SecondsStringTimestampVisitor; - /// Ser/de to/from timestamps in seconds /// /// Intended for use with `serde`'s `with` attribute. @@ -37,12 +36,12 @@ pub struct SecondsStringTimestampVisitor; /// ``` pub mod ts_seconds_str { - use core::fmt; - use chrono::{DateTime, LocalResult, Utc}; + use super::serde_from; use super::SecondsStringTimestampVisitor; - use serde::{de, ser}; use chrono::TimeZone; - use super::serde_from; + use chrono::{DateTime, LocalResult, Utc}; + use core::fmt; + use serde::{de, ser}; /// Serialize a UTC datetime into an integer number of seconds since the epoch /// @@ -68,8 +67,8 @@ pub mod ts_seconds_str { /// # Ok::<(), serde_json::Error>(()) /// ``` pub fn serialize(dt: &DateTime, serializer: S) -> Result - where - S: ser::Serializer, + where + S: ser::Serializer, { serializer.serialize_str(&format!("{}", dt.timestamp())) } @@ -95,8 +94,8 @@ pub mod ts_seconds_str { /// # Ok::<(), serde_json::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> - where - D: de::Deserializer<'de>, + where + D: de::Deserializer<'de>, { d.deserialize_str(SecondsStringTimestampVisitor) } @@ -110,10 +109,13 @@ pub mod ts_seconds_str { /// Deserialize a timestamp in seconds since the epoch fn visit_str(self, value: &str) -> Result - where - E: de::Error, + where + E: de::Error, { - serde_from(Utc.timestamp_opt(value.parse::().map_err(|e| E::custom(e))?, 0), &value) + serde_from( + Utc.timestamp_opt(value.parse::().map_err(|e| E::custom(e))?, 0), + &value, + ) } } } @@ -146,10 +148,10 @@ pub mod ts_seconds_str { /// # Ok::<(), serde_json::Error>(()) /// ``` pub mod ts_seconds_option_str { - use core::fmt; + use super::SecondsStringTimestampVisitor; use chrono::{DateTime, Utc}; + use core::fmt; use serde::{de, ser}; - use super::SecondsStringTimestampVisitor; /// Serialize a UTC datetime into an integer number of seconds since the epoch or none /// @@ -175,8 +177,8 @@ pub mod ts_seconds_option_str { /// # Ok::<(), serde_json::Error>(()) /// ``` pub fn serialize(opt: &Option>, serializer: S) -> Result - where - S: ser::Serializer, + where + S: ser::Serializer, { match *opt { Some(ref dt) => serializer.serialize_some(&dt.timestamp().to_string()), @@ -205,8 +207,8 @@ pub mod ts_seconds_option_str { /// # Ok::<(), serde_json::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> - where - D: de::Deserializer<'de>, + where + D: de::Deserializer<'de>, { d.deserialize_option(OptionSecondsTimestampVisitor) } @@ -222,24 +224,24 @@ pub mod ts_seconds_option_str { /// Deserialize a timestamp in seconds since the epoch fn visit_some(self, d: D) -> Result - where - D: de::Deserializer<'de>, + where + D: de::Deserializer<'de>, { d.deserialize_str(SecondsStringTimestampVisitor).map(Some) } /// Deserialize a timestamp in seconds since the epoch fn visit_none(self) -> Result - where - E: de::Error, + where + E: de::Error, { Ok(None) } /// Deserialize a timestamp in seconds since the epoch fn visit_unit(self) -> Result - where - E: de::Error, + where + E: de::Error, { Ok(None) } @@ -247,17 +249,15 @@ pub mod ts_seconds_option_str { } pub(crate) fn serde_from(me: LocalResult, _ts: &V) -> Result - where - E: de::Error, - V: fmt::Display, - T: fmt::Display, +where + E: de::Error, + V: fmt::Display, + T: fmt::Display, { // TODO: Make actual error type match me { LocalResult::None => Err(E::custom("value is not a legal timestamp")), - LocalResult::Ambiguous(_min, _max) => { - Err(E::custom("value is an ambiguous timestamp")) - } + LocalResult::Ambiguous(_min, _max) => Err(E::custom("value is an ambiguous timestamp")), LocalResult::Single(val) => Ok(val), } } @@ -270,9 +270,11 @@ enum StringOrU64 { } pub fn string_or_u64<'de, D>(d: D) -> Result -where D: Deserializer<'de> { +where + D: Deserializer<'de>, +{ match StringOrU64::deserialize(d)? { StringOrU64::String(s) => s.parse::().map_err(D::Error::custom), - StringOrU64::U64(u) => Ok(u) + StringOrU64::U64(u) => Ok(u), } -} \ No newline at end of file +} diff --git a/src/voice/udp/backends/tokio.rs b/src/voice/udp/backends/tokio.rs index e529a0cc..de3ffe5e 100644 --- a/src/voice/udp/backends/tokio.rs +++ b/src/voice/udp/backends/tokio.rs @@ -6,7 +6,7 @@ use std::net::SocketAddr; use crate::errors::VoiceUdpError; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct TokioBackend; pub type TokioSocket = tokio::net::UdpSocket; diff --git a/tests/channels.rs b/tests/channels.rs index e00744a4..eb1c1200 100644 --- a/tests/channels.rs +++ b/tests/channels.rs @@ -168,8 +168,7 @@ async fn create_dm() { dm_channel .recipients .as_ref() - .unwrap() - .get(0) + .unwrap().first() .unwrap() .read() .unwrap() @@ -242,8 +241,7 @@ async fn remove_add_person_from_to_dm() { dm_channel .recipients .as_ref() - .unwrap() - .get(0) + .unwrap().first() .unwrap() .read() .unwrap() diff --git a/tests/gateway.rs b/tests/gateway.rs index b16b3b2e..1c8f56a8 100644 --- a/tests/gateway.rs +++ b/tests/gateway.rs @@ -206,7 +206,7 @@ async fn test_recursive_self_updating_structs() { let guild = bundle.user.gateway.observe(bundle.guild.clone()).await; let inner_guild = guild.read().unwrap().clone(); let guild_roles = inner_guild.roles; - let guild_role_inner = guild_roles.get(0).unwrap().read().unwrap().clone(); + let guild_role_inner = guild_roles.first().unwrap().read().unwrap().clone(); assert_eq!(guild_role_inner.name, "yippieee".to_string()); common::teardown(bundle).await; } diff --git a/tests/messages.rs b/tests/messages.rs index 3ca6e161..c4ceca5b 100644 --- a/tests/messages.rs +++ b/tests/messages.rs @@ -114,7 +114,7 @@ async fn search_messages() { .await .unwrap(); assert!(!query_result.is_empty()); - assert_eq!(query_result.get(0).unwrap().id, message.id); + assert_eq!(query_result.first().unwrap().id, message.id); } #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] @@ -139,8 +139,7 @@ async fn test_stickies() { assert_eq!( Message::get_sticky(channel.id, &mut bundle.user) .await - .unwrap() - .get(0) + .unwrap().first() .unwrap() .id, message.id diff --git a/tests/relationships.rs b/tests/relationships.rs index 2eea5b3f..4e57b22e 100644 --- a/tests/relationships.rs +++ b/tests/relationships.rs @@ -50,7 +50,7 @@ async fn test_get_relationships() { .unwrap(); let relationships = user.get_relationships().await.unwrap(); assert_eq!( - relationships.get(0).unwrap().id, + relationships.first().unwrap().id, other_user.object.read().unwrap().id ); common::teardown(bundle).await @@ -71,20 +71,20 @@ async fn test_modify_relationship_friends() { .unwrap(); let relationships = user.get_relationships().await.unwrap(); assert_eq!( - relationships.get(0).unwrap().id, + relationships.first().unwrap().id, other_user.object.read().unwrap().id ); assert_eq!( - relationships.get(0).unwrap().relationship_type, + relationships.first().unwrap().relationship_type, RelationshipType::Incoming ); let relationships = other_user.get_relationships().await.unwrap(); assert_eq!( - relationships.get(0).unwrap().id, + relationships.first().unwrap().id, user.object.read().unwrap().id ); assert_eq!( - relationships.get(0).unwrap().relationship_type, + relationships.first().unwrap().relationship_type, RelationshipType::Outgoing ); let _ = user @@ -95,7 +95,7 @@ async fn test_modify_relationship_friends() { .get_relationships() .await .unwrap() - .get(0) + .first() .unwrap() .relationship_type, RelationshipType::Friends @@ -124,11 +124,11 @@ async fn test_modify_relationship_block() { assert_eq!(relationships, Vec::::new()); let relationships = other_user.get_relationships().await.unwrap(); assert_eq!( - relationships.get(0).unwrap().id, + relationships.first().unwrap().id, user.object.read().unwrap().id ); assert_eq!( - relationships.get(0).unwrap().relationship_type, + relationships.first().unwrap().relationship_type, RelationshipType::Blocked ); other_user.remove_relationship(user_id).await.unwrap(); diff --git a/tests/types.rs b/tests/types.rs index 48b132cd..27f32399 100644 --- a/tests/types.rs +++ b/tests/types.rs @@ -953,45 +953,7 @@ mod entities { } mod guild { - use std::hash::{Hash, Hasher}; - - use chorus::types::{Guild, GuildInvite}; - - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn guild_hash() { - let id: u64 = 1; - let mut guild1 = Guild::default(); - let mut guild2 = Guild::default(); - guild1.id = id.into(); - guild2.id = id.into(); - let mut hasher1 = std::collections::hash_map::DefaultHasher::new(); - guild1.hash(&mut hasher1); - - let mut hasher2 = std::collections::hash_map::DefaultHasher::new(); - guild2.hash(&mut hasher2); - - assert_eq!(hasher1.finish(), hasher2.finish()); - } - - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn guild_invite_hash() { - let id: u64 = 1; - let mut invite1 = GuildInvite::default(); - let mut invite2 = GuildInvite::default(); - invite1.channel_id = id.into(); - invite2.channel_id = id.into(); - invite1.guild_id = id.into(); - invite2.guild_id = id.into(); - let mut hasher1 = std::collections::hash_map::DefaultHasher::new(); - invite1.hash(&mut hasher1); - - let mut hasher2 = std::collections::hash_map::DefaultHasher::new(); - invite2.hash(&mut hasher2); - - assert_eq!(hasher1.finish(), hasher2.finish()); - } + use chorus::types::Guild; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), test)] @@ -1006,38 +968,6 @@ mod entities { } } - mod relationship { - use chorus::types::{IntoShared, Relationship, User}; - - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - #[cfg_attr(not(target_arch = "wasm32"), test)] - fn relationship_partial_eq() { - let user = User::default(); - // These 2 users are different, because they do not have the same Snowflake "id". - let user_2 = User::default(); - let relationship_1 = Relationship { - id: 32_u64.into(), - relationship_type: chorus::types::RelationshipType::Friends, - nickname: Some("Xenia".to_string()), - user: user.into_public_user().into_shared(), - since: None, - }; - - let relationship_2 = Relationship { - id: 32_u64.into(), - relationship_type: chorus::types::RelationshipType::Friends, - nickname: Some("Xenia".to_string()), - user: user_2.into_public_user().into_shared(), - since: None, - }; - - // This should succeed, even though the two users' IDs are different. This is because - // `User` is only `PartialEq`, and the actual user object is not checked, since the - // `RwLock` would have to be locked. - assert_eq!(relationship_1, relationship_2); - } - } - mod message { use chorus::types::{Message, Snowflake}; From cd0230e64d40330bb2f0610be51392e63e17f9b9 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 20 Jul 2024 16:54:47 +0200 Subject: [PATCH 087/162] Provide alternative implementations for PartialEq for some types when sqlx feature is enabled --- src/types/entities/application.rs | 39 +++++++++++++++++++++++++ src/types/entities/audit_log.rs | 17 +++++++++++ src/types/entities/channel.rs | 48 +++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) diff --git a/src/types/entities/application.rs b/src/types/entities/application.rs index 754c9652..03b0cef5 100644 --- a/src/types/entities/application.rs +++ b/src/types/entities/application.rs @@ -62,6 +62,7 @@ pub struct Application { } #[cfg(not(tarpaulin_include))] +#[cfg(not(feature = "sqlx"))] impl PartialEq for Application { fn eq(&self, other: &Self) -> bool { self.id == other.id @@ -94,6 +95,44 @@ impl PartialEq for Application { } } +#[cfg(not(tarpaulin_include))] +#[cfg(feature = "sqlx")] +impl PartialEq for Application { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + && self.name == other.name + && self.icon == other.icon + && self.description == other.description + && self.summary == other.summary + && self.r#type == other.r#type + && self.r#type == other.r#type + && self.hook == other.hook + && self.bot_public == other.bot_public + && self.bot_require_code_grant == other.bot_require_code_grant + && self.verify_key == other.verify_key + && arc_rwlock_ptr_eq(&self.owner, &other.owner) + && self.flags == other.flags + && self.redirect_uris == other.redirect_uris + && self.redirect_uris == other.redirect_uris + && self.rpc_application_state == other.rpc_application_state + && self.store_application_state == other.store_application_state + && self.verification_state == other.verification_state + && self.interactions_endpoint_url == other.interactions_endpoint_url + && self.integration_public == other.integration_public + && self.integration_require_code_grant == other.integration_require_code_grant + && self.discoverability_state == other.discoverability_state + && self.discovery_eligibility_flags == other.discovery_eligibility_flags + && self.tags == other.tags + && self.tags == other.tags + && self.cover_image == other.cover_image + && self.install_params == other.install_params + && self.install_params == other.install_params + && self.terms_of_service_url == other.terms_of_service_url + && self.privacy_policy_url == other.privacy_policy_url + && self.team == other.team + } +} + impl Default for Application { fn default() -> Self { Self { diff --git a/src/types/entities/audit_log.rs b/src/types/entities/audit_log.rs index ca997a1a..b05776b1 100644 --- a/src/types/entities/audit_log.rs +++ b/src/types/entities/audit_log.rs @@ -32,6 +32,7 @@ pub struct AuditLogEntry { } #[cfg(not(tarpaulin_include))] +#[cfg(not(feature = "sqlx"))] impl PartialEq for AuditLogEntry { fn eq(&self, other: &Self) -> bool { let everything_else = self.target_id == other.target_id @@ -63,6 +64,22 @@ impl PartialEq for AuditLogEntry { } } +#[cfg(not(tarpaulin_include))] +#[cfg(feature = "sqlx")] +impl PartialEq for AuditLogEntry { + fn eq(&self, other: &Self) -> bool { + self.target_id == other.target_id + // Serialize the `Vec>` to a string and compare them + && self.changes.encode_to_string() == other.changes.encode_to_string() + && self.user_id == other.user_id + && self.id == other.id + && self.action_type == other.action_type + && self.options == other.options + && self.options == other.options + && self.reason == other.reason + } +} + #[derive(Serialize, Deserialize, Debug, Default, Clone)] /// See pub struct AuditLogChange { diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 00477cdf..818916d0 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -98,6 +98,7 @@ pub struct Channel { } #[cfg(not(tarpaulin_include))] +#[cfg(not(feature = "sqlx"))] impl PartialEq for Channel { fn eq(&self, other: &Self) -> bool { self.application_id == other.application_id @@ -145,6 +146,53 @@ impl PartialEq for Channel { } } +#[cfg(not(tarpaulin_include))] +#[cfg(feature = "sqlx")] +impl PartialEq for Channel { + #[allow(clippy::nonminimal_bool)] + fn eq(&self, other: &Self) -> bool { + self.application_id == other.application_id + && self.applied_tags == other.applied_tags + && self.applied_tags == other.applied_tags + && self.available_tags == other.available_tags + && self.available_tags == other.available_tags + && 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_reaction_emoji == other.default_reaction_emoji + && self.default_reaction_emoji == other.default_reaction_emoji + && 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 == other.member + && 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.permission_overwrites == other.permission_overwrites + && self.permissions == other.permissions + && self.position == other.position + && self.rate_limit_per_user == other.rate_limit_per_user + && option_vec_arc_rwlock_ptr_eq(&self.recipients, &other.recipients) + && self.rtc_region == other.rtc_region + && self.thread_metadata == other.thread_metadata + && 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, PartialEq, Eq, PartialOrd, Ord, Hash)] /// A tag that can be applied to a thread in a [ChannelType::GuildForum] or [ChannelType::GuildMedia] channel. /// From 98b129aca0fd17935ef566590e01c3ff2ee99703 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 20 Jul 2024 17:18:23 +0200 Subject: [PATCH 088/162] Provide alternative implementations for PartialEq for some types when sqlx feature is enabled --- src/types/entities/application.rs | 25 ++++++++++- src/types/entities/audit_log.rs | 69 +++++++++++++++++++------------ src/types/entities/channel.rs | 26 +++++++++++- src/types/entities/emoji.rs | 3 +- 4 files changed, 94 insertions(+), 29 deletions(-) diff --git a/src/types/entities/application.rs b/src/types/entities/application.rs index 754c9652..f265f21a 100644 --- a/src/types/entities/application.rs +++ b/src/types/entities/application.rs @@ -11,6 +11,7 @@ use crate::types::utils::Snowflake; use crate::types::Shared; use crate::types::{Team, User}; +#[allow(unused_imports)] use super::{arc_rwlock_ptr_eq, option_arc_rwlock_ptr_eq}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -87,13 +88,35 @@ impl PartialEq for Application { && self.discovery_eligibility_flags == other.discovery_eligibility_flags && self.tags == other.tags && self.cover_image == other.cover_image - && option_arc_rwlock_ptr_eq(&self.install_params, &other.install_params) + && compare_install_params(&self.install_params, &other.install_params) && self.terms_of_service_url == other.terms_of_service_url && self.privacy_policy_url == other.privacy_policy_url && self.team == other.team } } +#[cfg(not(tarpaulin_include))] +#[cfg(feature = "sqlx")] +fn compare_install_params( + a: &Option>, + b: &Option>, +) -> bool { + match (a, b) { + (Some(a), Some(b)) => a.encode_to_string() == b.encode_to_string(), + (None, None) => true, + _ => false, + } +} + +#[cfg(not(tarpaulin_include))] +#[cfg(not(feature = "sqlx"))] +fn compare_install_params( + a: &Option>, + b: &Option>, +) -> bool { + option_arc_rwlock_ptr_eq(a, b) +} + impl Default for Application { fn default() -> Self { Self { diff --git a/src/types/entities/audit_log.rs b/src/types/entities/audit_log.rs index ca997a1a..b1456b18 100644 --- a/src/types/entities/audit_log.rs +++ b/src/types/entities/audit_log.rs @@ -2,7 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::sync::Arc; +#[allow(unused_imports)] +use super::option_vec_arc_rwlock_ptr_eq; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; @@ -30,39 +31,55 @@ pub struct AuditLogEntry { pub options: Option, pub reason: Option, } - -#[cfg(not(tarpaulin_include))] impl PartialEq for AuditLogEntry { fn eq(&self, other: &Self) -> bool { - let everything_else = self.target_id == other.target_id + self.target_id == other.target_id && self.user_id == other.user_id && self.id == other.id && self.action_type == other.action_type - && self.options == other.options - && self.reason == other.reason; - // Compare the Vec> separately, since Shared doesn't implement PartialEq - match (&self.changes, &other.changes) { - // If both are Some, compare the contents - (Some(self_changes), Some(other_changes)) => { - let mut changes_equal = true; - // Iterate over both Vecs and compare the Arc pointers. If any are different, the - // Vecs are not equal - for (self_change, other_change) in self_changes.iter().zip(other_changes.iter()) { - if !Arc::ptr_eq(self_change, other_change) { - changes_equal = false; - break; - } - } - everything_else && changes_equal - } - // If both are None, they're equal - (None, None) => everything_else, - // If one is Some and the other is None, they're not equal - _ => false, - } + && compare_options(&self.options, &other.options) + && self.reason == other.reason + && compare_changes(&self.changes, &other.changes) + } +} + +#[cfg(not(tarpaulin_include))] +#[cfg(feature = "sqlx")] +fn compare_options( + a: &Option>, + b: &Option>, +) -> bool { + match (a, b) { + (Some(a), Some(b)) => a.encode_to_string() == b.encode_to_string(), + (None, None) => true, + _ => false, } } +#[cfg(not(tarpaulin_include))] +#[cfg(not(feature = "sqlx"))] +fn compare_options(a: &Option, b: &Option) -> bool { + a == b +} + +#[cfg(not(tarpaulin_include))] +#[cfg(feature = "sqlx")] +fn compare_changes( + a: &sqlx::types::Json>>>, + b: &sqlx::types::Json>>>, +) -> bool { + a.encode_to_string() == b.encode_to_string() +} + +#[cfg(not(tarpaulin_include))] +#[cfg(not(feature = "sqlx"))] +fn compare_changes( + a: &Option>>, + b: &Option>>, +) -> bool { + option_vec_arc_rwlock_ptr_eq(a, b) +} + #[derive(Serialize, Deserialize, Debug, Default, Clone)] /// See pub struct AuditLogChange { diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 00477cdf..612111f7 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -5,6 +5,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Deserializer, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; +use sqlx::types::Json; use std::fmt::{Debug, Formatter}; use std::str::FromStr; @@ -98,6 +99,7 @@ pub struct Channel { } #[cfg(not(tarpaulin_include))] +#[allow(clippy::nonminimal_bool)] impl PartialEq for Channel { fn eq(&self, other: &Self) -> bool { self.application_id == other.application_id @@ -128,7 +130,7 @@ impl PartialEq for Channel { && self.nsfw == other.nsfw && self.owner_id == other.owner_id && self.parent_id == other.parent_id - && option_vec_arc_rwlock_ptr_eq( + && compare_permission_overwrites( &self.permission_overwrites, &other.permission_overwrites, ) @@ -145,6 +147,28 @@ impl PartialEq for Channel { } } +#[cfg(not(tarpaulin_include))] +#[cfg(feature = "sqlx")] +fn compare_permission_overwrites( + a: &Option>>, + b: &Option>>, +) -> bool { + match (a, b) { + (Some(a), Some(b)) => a.encode_to_string() == b.encode_to_string(), + (None, None) => true, + _ => false, + } +} + +#[cfg(not(tarpaulin_include))] +#[cfg(not(feature = "sqlx"))] +fn compare_permission_overrides( + a: &Option>>, + b: &Option>>, +) -> bool { + option_vec_arc_rwlock_ptr_eq(a, b) +} + #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] /// A tag that can be applied to a thread in a [ChannelType::GuildForum] or [ChannelType::GuildMedia] channel. /// diff --git a/src/types/entities/emoji.rs b/src/types/entities/emoji.rs index 55ebb84c..82f3e375 100644 --- a/src/types/entities/emoji.rs +++ b/src/types/entities/emoji.rs @@ -45,6 +45,7 @@ pub struct Emoji { } #[cfg(not(tarpaulin_include))] +#[allow(clippy::nonminimal_bool)] impl PartialEq for Emoji { fn eq(&self, other: &Self) -> bool { self.id == other.id @@ -62,7 +63,7 @@ impl PartialEq for Emoji { impl From for Emoji { fn from(value: PartialEmoji) -> Self { Self { - id: value.id.unwrap_or_default(), // TODO: this should be handled differently + id: value.id.unwrap_or_default(), // TODO: Make this method an impl to TryFrom<> instead name: Some(value.name), roles: None, user: None, From 0beb4484ca67b70b9a2d798793244bfff68babdc Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 20 Jul 2024 17:25:33 +0200 Subject: [PATCH 089/162] Fix: Wrong function name --- src/types/entities/channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 612111f7..dd56176f 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -162,7 +162,7 @@ fn compare_permission_overwrites( #[cfg(not(tarpaulin_include))] #[cfg(not(feature = "sqlx"))] -fn compare_permission_overrides( +fn compare_permission_overwrites( a: &Option>>, b: &Option>>, ) -> bool { From 88efef6015132468de6ba10b9816547f18197ec1 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 20 Jul 2024 17:30:21 +0200 Subject: [PATCH 090/162] Fix: Turn unconditional import of sqlx::types::Json into conditional one --- src/types/entities/channel.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index dd56176f..622f14d9 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -5,7 +5,6 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Deserializer, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use sqlx::types::Json; use std::fmt::{Debug, Formatter}; use std::str::FromStr; @@ -28,6 +27,9 @@ use crate::gateway::Updateable; use chorus_macros::{observe_option_vec, Composite, Updateable}; use serde::de::{Error, Visitor}; +#[cfg(feature = "sqlx")] +use sqlx::types::Json; + use super::{option_arc_rwlock_ptr_eq, option_vec_arc_rwlock_ptr_eq}; #[derive(Default, Debug, Serialize, Deserialize, Clone)] From 76146b0e8c4a4936bdcf79d02be902d2752033dc Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 20 Jul 2024 17:54:49 +0200 Subject: [PATCH 091/162] Fix: Compile error with no default features --- src/types/entities/mod.rs | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index b413e8e8..2fec4cae 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -142,13 +142,21 @@ impl IntoShared for T { } } -/// Internal function to compare two `Arc>`s by comparing their pointers. -pub(crate) fn arc_rwlock_ptr_eq(a: &Arc>, b: &Arc>) -> bool { - Arc::ptr_eq(a, b) +/// Internal function to compare two `Shared`s by comparing their pointers. +#[cfg_attr(not(feature = "client"), allow(unused_variables))] +pub(crate) fn arc_rwlock_ptr_eq(a: &Shared, b: &Shared) -> bool { + #[cfg(feature = "client")] + { + Shared::ptr_eq(a, b) + } + #[cfg(not(feature = "client"))] + { + true + } } -/// Internal function to compare two `Vec>>`s by comparing their pointers. -pub(crate) fn vec_arc_rwlock_ptr_eq(a: &Vec>>, b: &Vec>>) -> bool { +/// Internal function to compare two `Vec>`s by comparing their pointers. +pub(crate) fn vec_arc_rwlock_ptr_eq(a: &[Shared], b: &[Shared]) -> bool { for (a, b) in a.iter().zip(b.iter()) { if !arc_rwlock_ptr_eq(a, b) { return false; @@ -157,11 +165,8 @@ pub(crate) fn vec_arc_rwlock_ptr_eq(a: &Vec>>, b: &Vec>>`s by comparing their pointers. -pub(crate) fn option_arc_rwlock_ptr_eq( - a: &Option>>, - b: &Option>>, -) -> bool { +/// Internal function to compare two `Option>`s by comparing their pointers. +pub(crate) fn option_arc_rwlock_ptr_eq(a: &Option>, b: &Option>) -> bool { match (a, b) { (Some(a), Some(b)) => arc_rwlock_ptr_eq(a, b), (None, None) => true, @@ -169,10 +174,10 @@ pub(crate) fn option_arc_rwlock_ptr_eq( } } -/// Internal function to compare two `Option>>>`s by comparing their pointers. +/// Internal function to compare two `Option>>`s by comparing their pointers. pub(crate) fn option_vec_arc_rwlock_ptr_eq( - a: &Option>>>, - b: &Option>>>, + a: &Option>>, + b: &Option>>, ) -> bool { match (a, b) { (Some(a), Some(b)) => vec_arc_rwlock_ptr_eq(a, b), From 7a2666bde2faa9166d7467f3c7c26157cb24c799 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jul 2024 13:37:07 +0200 Subject: [PATCH 092/162] Update CONTRIBUTING.md --- CONTRIBUTING.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 34a1153a..84e70210 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,8 +3,10 @@ **Please refer to the [contribution guidelines](https://github.com/polyphony-chat/.github/blob/main/CONTRIBUTION_GUIDELINES.md) and [our Code of Conduct](https://github.com/polyphony-chat/.github/blob/main/CODE_OF_CONDUCT.md) before making a contribution.** +Contributions should always fork from and merge back into the `dev` branch. + Chorus is currently missing voice support and a lot of API endpoints, many of which should be trivial to implement, ever since [we streamlined the process of doing so](https://github.com/polyphony-chat/chorus/discussions/401). If you'd like to contribute new functionality, check out [The 'Meta'-issues.](https://github.com/polyphony-chat/chorus/issues?q=is%3Aissue+label%3A%22Type%3A+Meta%22+) They contain a comprehensive list of all features which are yet missing for full Discord.com compatibility. -Please feel free to open an Issue with the idea you have, or a Pull Request. \ No newline at end of file +Please feel free to open an Issue with the idea you have, or a Pull Request. From 6cd3c1081b048400aeaa775d84c4450dab04f45f Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jul 2024 13:58:19 +0200 Subject: [PATCH 093/162] Use cargo nextest --- .github/workflows/build_and_test.yml | 229 ++++++++++++--------------- 1 file changed, 103 insertions(+), 126 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index d37491ae..da195637 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -2,153 +2,130 @@ name: Build and Test on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main", "dev" ] + branches: ["main", "dev"] env: CARGO_TERM_COLOR: always jobs: linux: - runs-on: ubuntu-latest timeout-minutes: 30 - steps: - - uses: actions/checkout@v4 - - name: Clone spacebar server - run: | - git clone https://github.com/bitfl0wer/server.git - - uses: actions/setup-node@v4 - with: + - uses: actions/checkout@v4 + - name: Clone spacebar server + run: | + git clone https://github.com/bitfl0wer/server.git + - uses: actions/setup-node@v4 + with: node-version: 18 - cache: 'npm' + cache: "npm" cache-dependency-path: server/package-lock.json - - name: Prepare and start Spacebar server - run: | - npm install - npm run setup - npm run start & - working-directory: ./server - - uses: Swatinem/rust-cache@v2 - with: - cache-all-crates: "true" - prefix-key: "linux" - - name: Build, Test and Publish Coverage - run: | - if [ -n "${{ secrets.COVERALLS_REPO_TOKEN }}" ]; then - curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - cargo binstall --no-confirm cargo-tarpaulin --force - cargo tarpaulin --all-features --avoid-cfg-tarpaulin --tests --verbose --skip-clean --coveralls ${{ secrets.COVERALLS_REPO_TOKEN }} --timeout 120 - else - echo "Code Coverage step is skipped on forks!" - cargo build --verbose --all-features - cargo test --verbose --all-features - fi - - name: Check common non-default feature configurations - run: | - echo "No features:" - cargo check --features="" --no-default-features - echo "Only client:" - cargo check --features="client" --no-default-features - echo "Only backend:" - cargo check --features="backend" --no-default-features - echo "Only voice:" - cargo check --features="voice" --no-default-features - echo "Only voice gateway:" - cargo check --features="voice_gateway" --no-default-features - echo "Backend + client:" - cargo check --features="backend, client" --no-default-features - echo "Backend + voice:" - cargo check --features="backend, voice" --no-default-features - echo "Backend + voice gateway:" - cargo check --features="backend, voice_gateway" --no-default-features - echo "Client + voice gateway:" - cargo check --features="client, voice_gateway" --no-default-features - # wasm-safari: - # runs-on: macos-latest - # steps: - # - uses: actions/checkout@v4 - # - name: Clone spacebar server - # run: | - # git clone https://github.com/bitfl0wer/server.git - # - uses: actions/setup-node@v4 - # with: - # node-version: 18 - # cache: 'npm' - # cache-dependency-path: server/package-lock.json - # - name: Prepare and start Spacebar server - # run: | - # npm install - # npm run setup - # npm run start & - # working-directory: ./server - # - uses: Swatinem/rust-cache@v2 - # with: - # cache-all-crates: "true" - # prefix-key: "macos-safari" - # - name: Run WASM tests with Safari, Firefox, Chrome - # run: | - # rustup target add wasm32-unknown-unknown - # curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - # cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.88" --force - # SAFARIDRIVER=$(which safaridriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt" --no-fail-fast + - name: Prepare and start Spacebar server + run: | + npm install + npm run setup + npm run start & + working-directory: ./server + - uses: Swatinem/rust-cache@v2 + with: + cache-all-crates: "true" + prefix-key: "linux" + - uses: taiki-e/install-action@nextest + - name: Build, Test with nextest, Publish Coverage + run: | + if [ -n "${{ secrets.COVERALLS_REPO_TOKEN }}" ]; then + if [ "${github.event.pull_request.head.ref}" = "main" ]; then + curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash + cargo binstall --no-confirm cargo-tarpaulin --force + cargo tarpaulin --all-features --avoid-cfg-tarpaulin --tests --verbose --skip-clean --coveralls ${{ secrets.COVERALLS_REPO_TOKEN }} --timeout 120 + else + echo "Code Coverage step is skipped on non-main PRs and PRs from forks." + cargo build --verbose --all-features + cargo nextest run --verbose --all-features + fi + else + echo "Code Coverage step is skipped on non-main PRs and PRs from forks." + cargo build --verbose --all-features + cargo nextest run --verbose --all-features + fi + - name: Check common non-default feature configurations + run: | + echo "No features:" + cargo check --features="" --no-default-features + echo "Only client:" + cargo check --features="client" --no-default-features + echo "Only backend:" + cargo check --features="backend" --no-default-features + echo "Only voice:" + cargo check --features="voice" --no-default-features + echo "Only voice gateway:" + cargo check --features="voice_gateway" --no-default-features + echo "Backend + client:" + cargo check --features="backend, client" --no-default-features + echo "Backend + voice:" + cargo check --features="backend, voice" --no-default-features + echo "Backend + voice gateway:" + cargo check --features="backend, voice_gateway" --no-default-features + echo "Client + voice gateway:" + cargo check --features="client, voice_gateway" --no-default-features wasm-gecko: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v4 - - name: Clone spacebar server - run: | - git clone https://github.com/bitfl0wer/server.git - - uses: actions/setup-node@v4 - with: + - uses: actions/checkout@v4 + - name: Clone spacebar server + run: | + git clone https://github.com/bitfl0wer/server.git + - uses: actions/setup-node@v4 + with: node-version: 18 - cache: 'npm' + cache: "npm" cache-dependency-path: server/package-lock.json - - name: Prepare and start Spacebar server - run: | - npm install - npm run setup - npm run start & - working-directory: ./server - - uses: Swatinem/rust-cache@v2 - with: - cache-all-crates: "true" - prefix-key: "macos" - - name: Run WASM tests with Safari, Firefox, Chrome - run: | - rustup target add wasm32-unknown-unknown - curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force - GECKODRIVER=$(which geckodriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" + - name: Prepare and start Spacebar server + run: | + npm install + npm run setup + npm run start & + working-directory: ./server + - uses: Swatinem/rust-cache@v2 + with: + cache-all-crates: "true" + prefix-key: "macos" + - name: Run WASM tests with Safari, Firefox, Chrome + run: | + rustup target add wasm32-unknown-unknown + curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash + cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force + GECKODRIVER=$(which geckodriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" wasm-chrome: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v4 - - name: Clone spacebar server - run: | - git clone https://github.com/bitfl0wer/server.git - - uses: actions/setup-node@v4 - with: + - uses: actions/checkout@v4 + - name: Clone spacebar server + run: | + git clone https://github.com/bitfl0wer/server.git + - uses: actions/setup-node@v4 + with: node-version: 18 - cache: 'npm' + cache: "npm" cache-dependency-path: server/package-lock.json - - name: Prepare and start Spacebar server - run: | - npm install - npm run setup - npm run start & - working-directory: ./server - - uses: Swatinem/rust-cache@v2 - with: - cache-all-crates: "true" - prefix-key: "macos" - - name: Run WASM tests with Safari, Firefox, Chrome - run: | - rustup target add wasm32-unknown-unknown - curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force - CHROMEDRIVER=$(which chromedriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" + - name: Prepare and start Spacebar server + run: | + npm install + npm run setup + npm run start & + working-directory: ./server + - uses: Swatinem/rust-cache@v2 + with: + cache-all-crates: "true" + prefix-key: "macos" + - name: Run WASM tests with Safari, Firefox, Chrome + run: | + rustup target add wasm32-unknown-unknown + curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash + cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force + CHROMEDRIVER=$(which chromedriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" From 0bfab58f2f8c3b8efa8d1765526ade8176fd2d20 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jul 2024 13:58:19 +0200 Subject: [PATCH 094/162] Use cargo nextest --- .github/workflows/build_and_test.yml | 229 ++++++++++++--------------- 1 file changed, 103 insertions(+), 126 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index d37491ae..bf05cc01 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -2,153 +2,130 @@ name: Build and Test on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main", "dev" ] + branches: ["main", "dev"] env: CARGO_TERM_COLOR: always jobs: linux: - runs-on: ubuntu-latest timeout-minutes: 30 - steps: - - uses: actions/checkout@v4 - - name: Clone spacebar server - run: | - git clone https://github.com/bitfl0wer/server.git - - uses: actions/setup-node@v4 - with: + - uses: actions/checkout@v4 + - name: Clone spacebar server + run: | + git clone https://github.com/bitfl0wer/server.git + - uses: actions/setup-node@v4 + with: node-version: 18 - cache: 'npm' + cache: "npm" cache-dependency-path: server/package-lock.json - - name: Prepare and start Spacebar server - run: | - npm install - npm run setup - npm run start & - working-directory: ./server - - uses: Swatinem/rust-cache@v2 - with: - cache-all-crates: "true" - prefix-key: "linux" - - name: Build, Test and Publish Coverage - run: | - if [ -n "${{ secrets.COVERALLS_REPO_TOKEN }}" ]; then - curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - cargo binstall --no-confirm cargo-tarpaulin --force - cargo tarpaulin --all-features --avoid-cfg-tarpaulin --tests --verbose --skip-clean --coveralls ${{ secrets.COVERALLS_REPO_TOKEN }} --timeout 120 - else - echo "Code Coverage step is skipped on forks!" - cargo build --verbose --all-features - cargo test --verbose --all-features - fi - - name: Check common non-default feature configurations - run: | - echo "No features:" - cargo check --features="" --no-default-features - echo "Only client:" - cargo check --features="client" --no-default-features - echo "Only backend:" - cargo check --features="backend" --no-default-features - echo "Only voice:" - cargo check --features="voice" --no-default-features - echo "Only voice gateway:" - cargo check --features="voice_gateway" --no-default-features - echo "Backend + client:" - cargo check --features="backend, client" --no-default-features - echo "Backend + voice:" - cargo check --features="backend, voice" --no-default-features - echo "Backend + voice gateway:" - cargo check --features="backend, voice_gateway" --no-default-features - echo "Client + voice gateway:" - cargo check --features="client, voice_gateway" --no-default-features - # wasm-safari: - # runs-on: macos-latest - # steps: - # - uses: actions/checkout@v4 - # - name: Clone spacebar server - # run: | - # git clone https://github.com/bitfl0wer/server.git - # - uses: actions/setup-node@v4 - # with: - # node-version: 18 - # cache: 'npm' - # cache-dependency-path: server/package-lock.json - # - name: Prepare and start Spacebar server - # run: | - # npm install - # npm run setup - # npm run start & - # working-directory: ./server - # - uses: Swatinem/rust-cache@v2 - # with: - # cache-all-crates: "true" - # prefix-key: "macos-safari" - # - name: Run WASM tests with Safari, Firefox, Chrome - # run: | - # rustup target add wasm32-unknown-unknown - # curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - # cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.88" --force - # SAFARIDRIVER=$(which safaridriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt" --no-fail-fast + - name: Prepare and start Spacebar server + run: | + npm install + npm run setup + npm run start & + working-directory: ./server + - uses: Swatinem/rust-cache@v2 + with: + cache-all-crates: "true" + prefix-key: "linux" + - uses: taiki-e/install-action@nextest + - name: Build, Test with nextest, Publish Coverage + run: | + if [ -n "${{ secrets.COVERALLS_REPO_TOKEN }}" ]; then + if [ "${{github.event.pull_request.head.ref}}" = "main" ]; then + curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash + cargo binstall --no-confirm cargo-tarpaulin --force + cargo tarpaulin --all-features --avoid-cfg-tarpaulin --tests --verbose --skip-clean --coveralls ${{ secrets.COVERALLS_REPO_TOKEN }} --timeout 120 + else + echo "Code Coverage step is skipped on non-main PRs and PRs from forks." + cargo build --verbose --all-features + cargo nextest run --verbose --all-features + fi + else + echo "Code Coverage step is skipped on non-main PRs and PRs from forks." + cargo build --verbose --all-features + cargo nextest run --verbose --all-features + fi + - name: Check common non-default feature configurations + run: | + echo "No features:" + cargo check --features="" --no-default-features + echo "Only client:" + cargo check --features="client" --no-default-features + echo "Only backend:" + cargo check --features="backend" --no-default-features + echo "Only voice:" + cargo check --features="voice" --no-default-features + echo "Only voice gateway:" + cargo check --features="voice_gateway" --no-default-features + echo "Backend + client:" + cargo check --features="backend, client" --no-default-features + echo "Backend + voice:" + cargo check --features="backend, voice" --no-default-features + echo "Backend + voice gateway:" + cargo check --features="backend, voice_gateway" --no-default-features + echo "Client + voice gateway:" + cargo check --features="client, voice_gateway" --no-default-features wasm-gecko: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v4 - - name: Clone spacebar server - run: | - git clone https://github.com/bitfl0wer/server.git - - uses: actions/setup-node@v4 - with: + - uses: actions/checkout@v4 + - name: Clone spacebar server + run: | + git clone https://github.com/bitfl0wer/server.git + - uses: actions/setup-node@v4 + with: node-version: 18 - cache: 'npm' + cache: "npm" cache-dependency-path: server/package-lock.json - - name: Prepare and start Spacebar server - run: | - npm install - npm run setup - npm run start & - working-directory: ./server - - uses: Swatinem/rust-cache@v2 - with: - cache-all-crates: "true" - prefix-key: "macos" - - name: Run WASM tests with Safari, Firefox, Chrome - run: | - rustup target add wasm32-unknown-unknown - curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force - GECKODRIVER=$(which geckodriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" + - name: Prepare and start Spacebar server + run: | + npm install + npm run setup + npm run start & + working-directory: ./server + - uses: Swatinem/rust-cache@v2 + with: + cache-all-crates: "true" + prefix-key: "macos" + - name: Run WASM tests with Safari, Firefox, Chrome + run: | + rustup target add wasm32-unknown-unknown + curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash + cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force + GECKODRIVER=$(which geckodriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" wasm-chrome: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v4 - - name: Clone spacebar server - run: | - git clone https://github.com/bitfl0wer/server.git - - uses: actions/setup-node@v4 - with: + - uses: actions/checkout@v4 + - name: Clone spacebar server + run: | + git clone https://github.com/bitfl0wer/server.git + - uses: actions/setup-node@v4 + with: node-version: 18 - cache: 'npm' + cache: "npm" cache-dependency-path: server/package-lock.json - - name: Prepare and start Spacebar server - run: | - npm install - npm run setup - npm run start & - working-directory: ./server - - uses: Swatinem/rust-cache@v2 - with: - cache-all-crates: "true" - prefix-key: "macos" - - name: Run WASM tests with Safari, Firefox, Chrome - run: | - rustup target add wasm32-unknown-unknown - curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force - CHROMEDRIVER=$(which chromedriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" + - name: Prepare and start Spacebar server + run: | + npm install + npm run setup + npm run start & + working-directory: ./server + - uses: Swatinem/rust-cache@v2 + with: + cache-all-crates: "true" + prefix-key: "macos" + - name: Run WASM tests with Safari, Firefox, Chrome + run: | + rustup target add wasm32-unknown-unknown + curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash + cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force + CHROMEDRIVER=$(which chromedriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" From dd85a7de17328e66249be0afb619fb14f577f865 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jul 2024 15:55:29 +0200 Subject: [PATCH 095/162] Fix/Correct UnavailableGuild object --- src/types/entities/guild.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 76256c77..cca9b94a 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -240,13 +240,18 @@ impl PartialEq for GuildInvite { } } -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Hash, Eq, PartialOrd, Ord, Copy)] +#[derive( + Serialize, Deserialize, Debug, Default, Clone, PartialEq, Hash, Eq, PartialOrd, Ord, Copy, +)] pub struct UnavailableGuild { pub id: Snowflake, - pub unavailable: bool, + pub unavailable: Option, + pub geo_restricted: Option, } -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] +#[derive( + Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, +)] pub struct GuildCreateResponse { pub id: Snowflake, } From f0fc6eab4df17ccbf2362513537fb8963b0a3ccc Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jul 2024 15:55:49 +0200 Subject: [PATCH 096/162] Fix testcase that relied on false behavior implemented by older spacebar servers --- tests/guilds.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/guilds.rs b/tests/guilds.rs index e3a73f56..8399567a 100644 --- a/tests/guilds.rs +++ b/tests/guilds.rs @@ -70,15 +70,6 @@ async fn guild_create_ban() { ) .await .unwrap(); - assert!(Guild::create_ban( - guild.id, - other_user_id, - None, - GuildBanCreateSchema::default(), - &mut bundle.user, - ) - .await - .is_err()); common::teardown(bundle).await } From 7bb35e5ed838be34fe825a1ecd09ca92254bda2d Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jul 2024 15:57:12 +0200 Subject: [PATCH 097/162] Increase limit integer size to match spacebars' possibilities --- src/types/config/types/subconfigs/limits/global.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/config/types/subconfigs/limits/global.rs b/src/types/config/types/subconfigs/limits/global.rs index 2a23bf4f..87e25f6d 100644 --- a/src/types/config/types/subconfigs/limits/global.rs +++ b/src/types/config/types/subconfigs/limits/global.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)] pub struct GlobalRateLimit { - pub limit: u16, + pub limit: u64, pub window: u64, pub enabled: bool, } From f32b3060cf32d327cf6803744f6998c70b4c5545 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jul 2024 16:09:25 +0200 Subject: [PATCH 098/162] Cargo nextest on wasm, Parallelize "Check common non-default feat. cfg." --- .github/workflows/build_and_test.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 7a5edfad..a1b2291b 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -49,6 +49,11 @@ jobs: echo "Code Coverage step is skipped on non-main PRs and PRs from forks." cargo nextest run --verbose --all-features fi + linux-non-default-features: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 - name: Check common non-default feature configurations run: | echo "No features:" @@ -97,7 +102,7 @@ jobs: rustup target add wasm32-unknown-unknown curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force - GECKODRIVER=$(which geckodriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" + GECKODRIVER=$(which geckodriver) cargo nextest run --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" wasm-chrome: runs-on: ubuntu-latest timeout-minutes: 30 @@ -126,4 +131,4 @@ jobs: rustup target add wasm32-unknown-unknown curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force - CHROMEDRIVER=$(which chromedriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" + CHROMEDRIVER=$(which chromedriver) cargo nextest run --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" From 31509b99455e8466ff4f1e42416999f56be849c8 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jul 2024 16:12:06 +0200 Subject: [PATCH 099/162] forgor installing nextest --- .github/workflows/build_and_test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index a1b2291b..0535911c 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -97,6 +97,7 @@ jobs: with: cache-all-crates: "true" prefix-key: "macos" + - uses: taiki-e/install-action@nextest - name: Run WASM tests with Safari, Firefox, Chrome run: | rustup target add wasm32-unknown-unknown @@ -126,6 +127,7 @@ jobs: with: cache-all-crates: "true" prefix-key: "macos" + - uses: taiki-e/install-action@nextest - name: Run WASM tests with Safari, Firefox, Chrome run: | rustup target add wasm32-unknown-unknown From d15dfc302d99f4e69736fe9aad779f4831b134f8 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jul 2024 16:17:00 +0200 Subject: [PATCH 100/162] Revert: nextest on wasm --- .github/workflows/build_and_test.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 0535911c..a69aff69 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -97,13 +97,12 @@ jobs: with: cache-all-crates: "true" prefix-key: "macos" - - uses: taiki-e/install-action@nextest - name: Run WASM tests with Safari, Firefox, Chrome run: | rustup target add wasm32-unknown-unknown curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force - GECKODRIVER=$(which geckodriver) cargo nextest run --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" + GECKODRIVER=$(which geckodriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" wasm-chrome: runs-on: ubuntu-latest timeout-minutes: 30 @@ -127,10 +126,9 @@ jobs: with: cache-all-crates: "true" prefix-key: "macos" - - uses: taiki-e/install-action@nextest - name: Run WASM tests with Safari, Firefox, Chrome run: | rustup target add wasm32-unknown-unknown curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force - CHROMEDRIVER=$(which chromedriver) cargo nextest run --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" + CHROMEDRIVER=$(which chromedriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" From feb2b1b64c42e42c7946752a02ccfa427069f7c5 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 24 Jul 2024 21:55:10 +0200 Subject: [PATCH 101/162] Bump browser_version according to https://www.useragents.me/#most-common-desktop-useragents --- src/types/events/identify.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/events/identify.rs b/src/types/events/identify.rs index 84c46a7a..28297066 100644 --- a/src/types/events/identify.rs +++ b/src/types/events/identify.rs @@ -157,7 +157,7 @@ impl GatewayIdentifyConnectionProps { // 25% of the web //default.browser_user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36".to_string(); browser: String::from("Chrome"), - browser_version: String::from("113.0.0.0"), + browser_version: String::from("126.0.0.0"), system_locale: String::from("en-US"), os: String::from("Windows"), os_version: Some(String::from("10")), From 539460a552b446bb0e11ff3cde821c823a013040 Mon Sep 17 00:00:00 2001 From: kozabrada123 Date: Thu, 25 Jul 2024 11:27:30 +0200 Subject: [PATCH 102/162] Fix voice_simple example --- examples/voice_simple/Cargo.lock | 2148 +++++++++++++++++++++++++++++ examples/voice_simple/src/main.rs | 12 +- 2 files changed, 2153 insertions(+), 7 deletions(-) create mode 100644 examples/voice_simple/Cargo.lock diff --git a/examples/voice_simple/Cargo.lock b/examples/voice_simple/Cargo.lock new file mode 100644 index 00000000..0a94e975 --- /dev/null +++ b/examples/voice_simple/Cargo.lock @@ -0,0 +1,2148 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "async-trait" +version = "0.1.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" + +[[package]] +name = "cc" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chorus" +version = "0.15.0" +dependencies = [ + "async-trait", + "base64 0.21.7", + "bitflags 2.6.0", + "chorus-macros", + "chrono", + "crypto_secretbox", + "custom_error", + "discortp", + "flate2", + "futures-util", + "getrandom", + "hostname", + "http", + "jsonwebtoken", + "lazy_static", + "log", + "pubserve", + "rand", + "regex", + "reqwest", + "rustls", + "serde", + "serde-aux", + "serde_json", + "serde_repr", + "serde_with", + "thiserror", + "tokio", + "tokio-tungstenite", + "url", + "wasm-bindgen-futures", + "wasmtimer", + "webpki-roots 0.26.3", + "ws_stream_wasm", +] + +[[package]] +name = "chorus-macros" +version = "0.4.1" +dependencies = [ + "async-trait", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.6", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core", + "typenum", +] + +[[package]] +name = "crypto_secretbox" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d6cf87adf719ddf43a805e92c6870a531aedda35ff640442cbaf8674e141e1" +dependencies = [ + "aead", + "cipher", + "generic-array", + "poly1305", + "salsa20", + "subtle", + "zeroize", +] + +[[package]] +name = "custom_error" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f8a51dd197fa6ba5b4dc98a990a43cc13693c23eb0089ebb0fcc1f04152bca6" + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.72", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "discortp" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524b9439c09174aede2c88d58cfc6b83575b06569d1af4d07562f76595b2896b" +dependencies = [ + "pnet_macros", + "pnet_macros_support", +] + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.2.6", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", + "serde", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +dependencies = [ + "base64 0.21.7", + "pem", + "ring 0.16.20", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "no-std-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "object" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pnet_base" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d3a993d49e5fd5d4d854d6999d4addca1f72d86c65adf224a36757161c02b6" +dependencies = [ + "no-std-net", +] + +[[package]] +name = "pnet_macros" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48dd52a5211fac27e7acb14cfc9f30ae16ae0e956b7b779c8214c74559cef4c3" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", +] + +[[package]] +name = "pnet_macros_support" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89de095dc7739349559913aed1ef6a11e73ceade4897dadc77c5e09de6740750" +dependencies = [ + "pnet_base", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pubserve" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a2cf5f495fc9c61de736666ebcbc473fe28a2a1aaf7e5619e5925b13c0275a4" +dependencies = [ + "async-trait", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "reqwest" +version = "0.11.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bf93c4af7a8bb7d879d51cebe797356ff10ae8516ace542b5182d9dcac10b2" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "mime_guess", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-rustls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.25.4", + "winreg", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring 0.17.8", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-aux" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d2e8bfba469d06512e11e3311d4d051a4a387a5b42d010404fecf3200321c95" +dependencies = [ + "chrono", + "serde", + "serde_json", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "serde_json" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.2.6", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "simplelog" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" +dependencies = [ + "log", + "termcolor", + "time", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d040ac2b29ab03b09d4129c2f5bbd012a3ac2f79d38ff506a4bf8dd34b0eac8a" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "rustls", + "tokio", + "tokio-rustls", + "tungstenite", + "webpki-roots 0.25.4", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand", + "rustls", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "voice_simple" +version = "0.1.0" +dependencies = [ + "async-trait", + "chorus", + "log", + "simplelog", + "tokio", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.72", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wasmtimer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f656cd8858a5164932d8a90f936700860976ec21eb00e0fe2aa8cab13f6b4cf" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "webpki-roots" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version", + "send_wrapper", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/examples/voice_simple/src/main.rs b/examples/voice_simple/src/main.rs index a6f77db7..f0f5f8ff 100644 --- a/examples/voice_simple/src/main.rs +++ b/examples/voice_simple/src/main.rs @@ -22,11 +22,9 @@ use simplelog::{TermLogger, Config, WriteLogger}; use std::{net::SocketAddrV4, sync::Arc, fs::File, time::Duration}; use chorus::{ - gateway::{Observer, Gateway}, + gateway::{Gateway, GatewayOptions, Observer}, types::{ - GatewayReady, SelectProtocol, SelectProtocolData, SessionDescription, Snowflake, Speaking, - SpeakingBitflags, SsrcDefinition, VoiceEncryptionMode, VoiceIdentify, VoiceProtocol, - VoiceReady, VoiceServerUpdate, GatewayIdentifyPayload, UpdateVoiceState, + GatewayIdentifyPayload, GatewayReady, SelectProtocol, SelectProtocolData, SessionDescription, Snowflake, Speaking, SpeakingBitflags, SsrcDefinition, UpdateVoiceState, VoiceEncryptionMode, VoiceIdentify, VoiceProtocol, VoiceReady, VoiceServerUpdate }, voice::{ gateway::{VoiceGateway, VoiceGatewayHandle}, @@ -219,7 +217,7 @@ impl Observer for VoiceHandler { println!( "Received Speaking! (SRRC: {}, flags: {:?})", data.ssrc, - SpeakingBitflags::from_bits(data.speaking).unwrap() + SpeakingBitflags::from_bits(data.speaking.into()).unwrap() ); } } @@ -253,7 +251,7 @@ async fn main() { ]) .unwrap(); - let gateway = Gateway::spawn(GATEWAY_URL.to_string()) + let gateway = Gateway::spawn(GATEWAY_URL.to_string(), GatewayOptions::default()) .await .unwrap(); @@ -281,7 +279,7 @@ async fn main() { .session .ready .subscribe(voice_handler.clone()); - + // Data which channel to update the local user to be joined into. // // guild_id and channel_id can be some to join guild voice channels From 832576dbf498ce7e2094cfc83033f612a45d558d Mon Sep 17 00:00:00 2001 From: kozabrada123 Date: Thu, 25 Jul 2024 11:28:22 +0200 Subject: [PATCH 103/162] Update documentation in gateway_observers example --- examples/gateway_observers.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/gateway_observers.rs b/examples/gateway_observers.rs index 96bd56b2..a43d17cd 100644 --- a/examples/gateway_observers.rs +++ b/examples/gateway_observers.rs @@ -34,8 +34,13 @@ use wasmtimer::tokio::sleep; #[derive(Debug)] pub struct ExampleObserver {} -// This struct can observe GatewayReady events when subscribed, because it implements the trait Observer. -// The Observer trait can be implemented for a struct for a given websocketevent to handle observing it +// This struct can observe GatewayReady events when subscribed, because it implements the trait Subscriber. +// The Subscriber trait can be implemented for a struct for a given websocketevent to handle observing it +// +// Note that this trait is quite generic and can be use to observe any type. +// +// It is just used for WebSocketEvents in chorus. +// // One struct can be an observer of multiple websocketevents, if needed #[async_trait] impl Subscriber for ExampleObserver { From b9bc37fcd4c595d86a3c57ab0122fd18f12559f2 Mon Sep 17 00:00:00 2001 From: kozabrada123 Date: Thu, 25 Jul 2024 11:29:35 +0200 Subject: [PATCH 104/162] Readd Observer trait as reexport --- src/gateway/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index 4550a2f2..6ee06788 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -19,7 +19,7 @@ pub use message::*; pub use options::*; use crate::errors::GatewayError; -use crate::types::{Snowflake}; +use crate::types::Snowflake; use std::any::Any; use std::collections::HashMap; @@ -77,6 +77,10 @@ const GATEWAY_LAZY_REQUEST: u8 = 14; pub type ObservableObject = dyn Send + Sync + Any; +/// Note: this is a reexport of [pubserve::Subscriber], +/// exported not to break the public api and make development easier +pub use pubserve::Subscriber as Observer; + /// An entity type which is supposed to be updateable via the Gateway. This is implemented for all such types chorus supports, implementing it for your own types is likely a mistake. pub trait Updateable: 'static + Send + Sync { fn id(&self) -> Snowflake; From d829537713e8e93db09543b8364daf51f9eb8c78 Mon Sep 17 00:00:00 2001 From: kozabrada123 Date: Thu, 25 Jul 2024 11:31:16 +0200 Subject: [PATCH 105/162] remove cargo lock from example --- examples/voice_simple/Cargo.lock | 2148 ------------------------------ 1 file changed, 2148 deletions(-) delete mode 100644 examples/voice_simple/Cargo.lock diff --git a/examples/voice_simple/Cargo.lock b/examples/voice_simple/Cargo.lock deleted file mode 100644 index 0a94e975..00000000 --- a/examples/voice_simple/Cargo.lock +++ /dev/null @@ -1,2148 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "async-trait" -version = "0.1.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "async_io_stream" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" -dependencies = [ - "futures", - "pharos", - "rustc_version", -] - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "backtrace" -version = "0.3.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -dependencies = [ - "serde", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" - -[[package]] -name = "cc" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chorus" -version = "0.15.0" -dependencies = [ - "async-trait", - "base64 0.21.7", - "bitflags 2.6.0", - "chorus-macros", - "chrono", - "crypto_secretbox", - "custom_error", - "discortp", - "flate2", - "futures-util", - "getrandom", - "hostname", - "http", - "jsonwebtoken", - "lazy_static", - "log", - "pubserve", - "rand", - "regex", - "reqwest", - "rustls", - "serde", - "serde-aux", - "serde_json", - "serde_repr", - "serde_with", - "thiserror", - "tokio", - "tokio-tungstenite", - "url", - "wasm-bindgen-futures", - "wasmtimer", - "webpki-roots 0.26.3", - "ws_stream_wasm", -] - -[[package]] -name = "chorus-macros" -version = "0.4.1" -dependencies = [ - "async-trait", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-targets 0.52.6", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", - "zeroize", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "rand_core", - "typenum", -] - -[[package]] -name = "crypto_secretbox" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d6cf87adf719ddf43a805e92c6870a531aedda35ff640442cbaf8674e141e1" -dependencies = [ - "aead", - "cipher", - "generic-array", - "poly1305", - "salsa20", - "subtle", - "zeroize", -] - -[[package]] -name = "custom_error" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f8a51dd197fa6ba5b4dc98a990a43cc13693c23eb0089ebb0fcc1f04152bca6" - -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.72", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "data-encoding" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", - "serde", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "discortp" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524b9439c09174aede2c88d58cfc6b83575b06569d1af4d07562f76595b2896b" -dependencies = [ - "pnet_macros", - "pnet_macros_support", -] - -[[package]] -name = "encoding_rs" -version = "0.8.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "flate2" -version = "1.0.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "gimli" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" - -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap 2.2.6", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hostname" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -dependencies = [ - "libc", - "match_cfg", - "winapi", -] - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http", - "hyper", - "rustls", - "tokio", - "tokio-rustls", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" -dependencies = [ - "equivalent", - "hashbrown 0.14.5", - "serde", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "jsonwebtoken" -version = "8.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" -dependencies = [ - "base64 0.21.7", - "pem", - "ring 0.16.20", - "serde", - "serde_json", - "simple_asn1", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "match_cfg" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" -dependencies = [ - "hermit-abi", - "libc", - "wasi", - "windows-sys 0.52.0", -] - -[[package]] -name = "no-std-net" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_threads" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" -dependencies = [ - "libc", -] - -[[package]] -name = "object" -version = "0.36.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "pem" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" -dependencies = [ - "base64 0.13.1", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pharos" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" -dependencies = [ - "futures", - "rustc_version", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pnet_base" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d3a993d49e5fd5d4d854d6999d4addca1f72d86c65adf224a36757161c02b6" -dependencies = [ - "no-std-net", -] - -[[package]] -name = "pnet_macros" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48dd52a5211fac27e7acb14cfc9f30ae16ae0e956b7b779c8214c74559cef4c3" -dependencies = [ - "proc-macro2", - "quote", - "regex", - "syn 1.0.109", -] - -[[package]] -name = "pnet_macros_support" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89de095dc7739349559913aed1ef6a11e73ceade4897dadc77c5e09de6740750" -dependencies = [ - "pnet_base", -] - -[[package]] -name = "poly1305" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pubserve" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a2cf5f495fc9c61de736666ebcbc473fe28a2a1aaf7e5619e5925b13c0275a4" -dependencies = [ - "async-trait", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "regex" -version = "1.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - -[[package]] -name = "reqwest" -version = "0.11.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bf93c4af7a8bb7d879d51cebe797356ff10ae8516ace542b5182d9dcac10b2" -dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-rustls", - "ipnet", - "js-sys", - "log", - "mime", - "mime_guess", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-rustls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots 0.25.4", - "winreg", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "spin 0.9.8", - "untrusted 0.9.0", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring 0.17.8", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - -[[package]] -name = "rustls-pki-types" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" - -[[package]] -name = "send_wrapper" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" - -[[package]] -name = "serde" -version = "1.0.204" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-aux" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d2e8bfba469d06512e11e3311d4d051a4a387a5b42d010404fecf3200321c95" -dependencies = [ - "chrono", - "serde", - "serde_json", -] - -[[package]] -name = "serde_derive" -version = "1.0.204" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "serde_json" -version = "1.0.120" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "3.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.2.6", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "simple_asn1" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" -dependencies = [ - "num-bigint", - "num-traits", - "thiserror", - "time", -] - -[[package]] -name = "simplelog" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" -dependencies = [ - "log", - "termcolor", - "time", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "itoa", - "libc", - "num-conv", - "num_threads", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinyvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.39.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d040ac2b29ab03b09d4129c2f5bbd012a3ac2f79d38ff506a4bf8dd34b0eac8a" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log", - "rustls", - "tokio", - "tokio-rustls", - "tungstenite", - "webpki-roots 0.25.4", -] - -[[package]] -name = "tokio-util" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "rand", - "rustls", - "sha1", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "voice_simple" -version = "0.1.0" -dependencies = [ - "async-trait", - "chorus", - "log", - "simplelog", - "tokio", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.72", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "wasmtimer" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f656cd8858a5164932d8a90f936700860976ec21eb00e0fe2aa8cab13f6b4cf" -dependencies = [ - "futures", - "js-sys", - "parking_lot", - "pin-utils", - "slab", - "wasm-bindgen", -] - -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - -[[package]] -name = "webpki-roots" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "ws_stream_wasm" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" -dependencies = [ - "async_io_stream", - "futures", - "js-sys", - "log", - "pharos", - "rustc_version", - "send_wrapper", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" From 4292ab88e9988896208f492c769ac86d4cbd8a13 Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:02:11 +0200 Subject: [PATCH 106/162] Fix #525 (pr #532) --- src/types/events/relationship.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/events/relationship.rs b/src/types/events/relationship.rs index eaeea562..7f813758 100644 --- a/src/types/events/relationship.rs +++ b/src/types/events/relationship.rs @@ -5,7 +5,7 @@ use crate::types::{events::WebSocketEvent, Relationship, RelationshipType, Snowflake}; use serde::{Deserialize, Serialize}; -#[derive(Debug, Deserialize, Serialize, Default, WebSocketEvent)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// See pub struct RelationshipAdd { #[serde(flatten)] From 111a8c42f5ea8a7afcd1b7f59cd93486d05c8454 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Fri, 26 Jul 2024 14:54:55 +0200 Subject: [PATCH 107/162] change theme_colors from Vec to (u32, u32) --- src/types/entities/user.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index 81978b05..e3cf5cec 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -61,7 +61,7 @@ pub struct User { pub public_flags: Option, pub banner: Option, pub bio: Option, - pub theme_colors: Option>, + pub theme_colors: Option<(u32, u32)>, pub phone: Option, pub nsfw_allowed: Option, pub premium: Option, @@ -78,7 +78,7 @@ pub struct PublicUser { pub avatar: Option, pub accent_color: Option, pub banner: Option, - pub theme_colors: Option>, + pub theme_colors: Option<(u32, u32)>, pub pronouns: Option, pub bot: Option, pub bio: Option, From ffcf15d058d9b629c0e842efc02192421c498d33 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Fri, 26 Jul 2024 17:30:12 +0200 Subject: [PATCH 108/162] Custom ThemeColors type with sqlx::Encode and sqlx::Decode impls --- src/types/entities/user.rs | 67 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index e3cf5cec..6dae5c45 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -2,10 +2,12 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use crate::errors::ChorusError; use crate::types::utils::Snowflake; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_aux::prelude::deserialize_option_number_from_string; +use std::array::TryFromSliceError; use std::fmt::Debug; #[cfg(feature = "client")] @@ -61,7 +63,7 @@ pub struct User { pub public_flags: Option, pub banner: Option, pub bio: Option, - pub theme_colors: Option<(u32, u32)>, + pub theme_colors: Option, pub phone: Option, pub nsfw_allowed: Option, pub premium: Option, @@ -70,6 +72,65 @@ pub struct User { pub disabled: Option, } +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Copy)] +pub struct ThemeColors { + #[serde(flatten)] + inner: (u32, u32), +} + +impl TryFrom> for ThemeColors { + type Error = ChorusError; + + fn try_from(value: Vec) -> Result { + if value.len() % 4 != 0 || value.len() > 8 { + return Err(ChorusError::InvalidArguments { + error: "Value has incorrect length to be decodeable from Vec".to_string(), + }); + } + let first: Result<[u8; 4], TryFromSliceError> = value[0..3].try_into(); + let second: Result<[u8; 4], TryFromSliceError> = { + if value.len() == 8 { + value[0..3].try_into() + } else { + [0; 4][0..3].try_into() + } + }; + + match (first, second) { + (Ok(first), Ok(second)) => Ok(Self { + inner: (u32::from_be_bytes(first), u32::from_be_bytes(second)), + }), + _ => Err(ChorusError::InvalidArguments { + error: "ThemeColors cannot be built from this Vec".to_string(), + }), + } + } +} + +#[cfg(feature = "sqlx")] +// TODO: Add tests for Encode and Decode. +impl<'q> sqlx::Encode<'q, sqlx::MySql> for ThemeColors { + fn encode_by_ref( + &self, + buf: &mut >::ArgumentBuffer, + ) -> sqlx::encode::IsNull { + let mut vec_u8 = Vec::new(); + vec_u8.extend_from_slice(&self.inner.0.to_be_bytes()); + vec_u8.extend_from_slice(&self.inner.1.to_be_bytes()); + as sqlx::Encode<'q, sqlx::MySql>>::encode_by_ref(&vec_u8, buf) + } +} + +#[cfg(feature = "sqlx")] +impl<'d> sqlx::Decode<'d, sqlx::MySql> for ThemeColors { + fn decode( + value: >::ValueRef, + ) -> Result { + let value_vec = as sqlx::Decode<'d, sqlx::MySql>>::decode(value)?; + value_vec.try_into().map_err(|e: ChorusError| e.into()) + } +} + #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] pub struct PublicUser { pub id: Snowflake, @@ -78,7 +139,7 @@ pub struct PublicUser { pub avatar: Option, pub accent_color: Option, pub banner: Option, - pub theme_colors: Option<(u32, u32)>, + pub theme_colors: Option, pub pronouns: Option, pub bot: Option, pub bio: Option, @@ -144,7 +205,7 @@ pub struct UserProfileMetadata { pub bio: Option, pub banner: Option, pub accent_color: Option, - pub theme_colors: Option>, + pub theme_colors: Option, pub popout_animation_particle_type: Option, pub emoji: Option, } From 9dbb5ea77b7e323c50fbfb8ea3b7dfdd79ec652c Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Fri, 26 Jul 2024 17:40:42 +0200 Subject: [PATCH 109/162] impl sqlx::Type for ThemeColors --- src/types/entities/user.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index 6dae5c45..674c9319 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -131,6 +131,13 @@ impl<'d> sqlx::Decode<'d, sqlx::MySql> for ThemeColors { } } +#[cfg(feature = "sqlx")] +impl sqlx::Type for ThemeColors { + fn type_info() -> ::TypeInfo { + >::type_info() + } +} + #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] pub struct PublicUser { pub id: Snowflake, From d4f6a7e98a1cf5f87e73d8aeb10237c89a12395d Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Fri, 26 Jul 2024 23:28:23 +0200 Subject: [PATCH 110/162] More accurate "GatewayHello::default()" --- src/types/events/hello.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/types/events/hello.rs b/src/types/events/hello.rs index 779b657c..a828f130 100644 --- a/src/types/events/hello.rs +++ b/src/types/events/hello.rs @@ -7,16 +7,38 @@ use chorus_macros::WebSocketEvent; use serde::{Deserialize, Serialize}; /// Received on gateway init, tells the client how often to send heartbeats; -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent, Copy, Hash, PartialOrd, Ord)] +#[derive( + Debug, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent, Copy, Hash, PartialOrd, Ord, +)] pub struct GatewayHello { pub op: i32, pub d: HelloData, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, Copy, WebSocketEvent, Hash, PartialOrd, Ord)] +#[derive( + Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Copy, WebSocketEvent, Hash, PartialOrd, Ord, +)] /// Contains info on how often the client should send heartbeats to the server; pub struct HelloData { /// How often a client should send heartbeats, in milliseconds pub heartbeat_interval: u64, } +impl std::default::Default for GatewayHello { + fn default() -> Self { + Self { + // "HELLO" opcode is 10 + op: 10, + d: Default::default(), + } + } +} + +impl std::default::Default for HelloData { + fn default() -> Self { + Self { + // Discord docs mention 45000 seconds - discord.sex mentions 41250. Defaulting to 45s + heartbeat_interval: 45000, + } + } +} From 7bba7c6fcb27c20c1e6b275a24734bef2df5b07f Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 27 Jul 2024 15:31:47 +0200 Subject: [PATCH 111/162] Manually implement std::default::Default for GatewayHeartbeat and GatewayHeartbeatAck --- src/types/events/heartbeat.rs | 42 +++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/types/events/heartbeat.rs b/src/types/events/heartbeat.rs index 6008ffba..8be2a528 100644 --- a/src/types/events/heartbeat.rs +++ b/src/types/events/heartbeat.rs @@ -5,14 +5,52 @@ use crate::types::events::WebSocketEvent; use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Deserialize, Serialize, WebSocketEvent, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive( + Debug, Deserialize, Serialize, WebSocketEvent, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, +)] pub struct GatewayHeartbeat { pub op: u8, pub d: Option, } -#[derive(Debug, Default, Deserialize, Serialize, Clone, WebSocketEvent, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +impl GatewayHeartbeat { + /// The Heartbeat packet a server would receive from a new or fresh Gateway connection. + pub fn first() -> Self { + Self::default() + } + + /// Quickly create a [GatewayHeartbeat] with the correct `opcode` and the given `sequence_number`. + /// + /// Shorthand for + /// ```rs + /// Self { + /// op: 1, + /// d: Some(sequence_number) + /// } + /// ``` + pub fn new(sequence_number: u64) -> Self { + Self { + op: 1, + d: Some(sequence_number), + } + } +} + +impl std::default::Default for GatewayHeartbeat { + fn default() -> Self { + Self { op: 1, d: None } + } +} + +#[derive( + Debug, Deserialize, Serialize, Clone, WebSocketEvent, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, +)] pub struct GatewayHeartbeatAck { pub op: i32, } +impl std::default::Default for GatewayHeartbeatAck { + fn default() -> Self { + Self { op: 11 } + } +} From f2f45b4b860a5fb97f4bc0f8be7a200bf69646b2 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 28 Jul 2024 12:28:56 +0200 Subject: [PATCH 112/162] bump versions of packages to latest compatible versions --- Cargo.lock | 48 +++++++++++++++++++----------------------------- Cargo.toml | 42 +++++++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 91c5f986..5d3bba65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1227,13 +1227,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1345,16 +1346,6 @@ dependencies = [ "libm", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" version = "0.36.1" @@ -1597,9 +1588,9 @@ dependencies = [ [[package]] name = "pubserve" -version = "1.1.0-alpha.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1781b2a51798c98a381e839e61bc5ce6426bd89bb9c3f9142de2086a80591cd" +checksum = "6a2cf5f495fc9c61de736666ebcbc473fe28a2a1aaf7e5619e5925b13c0275a4" dependencies = [ "async-trait", ] @@ -1972,9 +1963,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.3" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e73139bc5ec2d45e6c5fd85be5a46949c1c39a4c18e56915f5eb4c12f975e377" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" dependencies = [ "base64 0.22.1", "chrono", @@ -1990,9 +1981,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.3" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b80d3d6b56b64335c0180e5ffde23b3c5e08c14c585b51a15bd0e95393f46703" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ "darling", "proc-macro2", @@ -2412,18 +2403,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", @@ -2478,26 +2469,25 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.0" +version = "1.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index ad0795cc..75a25f51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,33 +22,33 @@ voice_udp = ["dep:discortp", "dep:crypto_secretbox"] voice_gateway = [] [dependencies] -tokio = { version = "1.35.1", features = ["macros", "sync"] } -serde = { version = "1.0.195", features = ["derive", "rc"] } -serde_json = { version = "1.0.111", features = ["raw_value"] } -serde-aux = "4.3.1" -serde_with = "3.4.0" -serde_repr = "0.1.18" +tokio = { version = "1.38.1", features = ["macros", "sync"] } +serde = { version = "1.0.204", features = ["derive", "rc"] } +serde_json = { version = "1.0.120", features = ["raw_value"] } +serde-aux = "4.5.0" +serde_with = "3.9.0" +serde_repr = "0.1.19" reqwest = { features = [ "multipart", "json", "rustls-tls-webpki-roots", ], version = "=0.11.26", default-features = false } -url = "2.5.0" -chrono = { version = "0.4.31", features = ["serde"] } -regex = "1.10.2" +url = "2.5.2" +chrono = { version = "0.4.38", features = ["serde"] } +regex = "1.10.5" custom_error = "1.9.2" futures-util = "0.3.30" http = "0.2.12" base64 = "0.21.7" -bitflags = { version = "2.4.1", features = ["serde"] } -lazy_static = "1.4.0" +bitflags = { version = "2.6.0", features = ["serde"] } +lazy_static = "1.5.0" poem = { version = "3.0.1", features = ["multipart"], optional = true } -thiserror = "1.0.56" +thiserror = "1.0.63" jsonwebtoken = "8.3.0" -log = "0.4.20" -async-trait = "0.1.77" +log = "0.4.22" +async-trait = "0.1.81" chorus-macros = { path = "./chorus-macros", version = "0" } # Note: version here is used when releasing. This will use the latest release. Make sure to republish the crate when code in macros is changed! -sqlx = { version = "0.7.3", features = [ +sqlx = { version = "0.7.4", features = [ "mysql", "sqlite", "json", @@ -66,24 +66,24 @@ crypto_secretbox = { version = "0.1.1", optional = true } rand = "0.8.5" flate2 = { version = "1.0.30", optional = true } webpki-roots = "0.26.3" -pubserve = { version = "1.1.0-alpha.1", features = ["async", "send"] } +pubserve = { version = "1.1.0", features = ["async", "send"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -rustls = "0.21.10" +rustls = "0.21.12" tokio-tungstenite = { version = "0.20.1", features = [ "rustls-tls-webpki-roots", ] } hostname = "0.3.1" -getrandom = { version = "0.2.12" } +getrandom = { version = "0.2.15" } [target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.2.12", features = ["js"] } +getrandom = { version = "0.2.15", features = ["js"] } ws_stream_wasm = "0.7.4" -wasm-bindgen-futures = "0.4.39" +wasm-bindgen-futures = "0.4.42" wasmtimer = "0.2.0" [dev-dependencies] -lazy_static = "1.4.0" +lazy_static = "1.5.0" wasm-bindgen-test = "0.3.42" wasm-bindgen = "0.2.92" simple_logger = { version = "5.0.0", default-features = false } From ab82a5d49af2239a711c950118c421e8590a5480 Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Fri, 2 Aug 2024 21:12:38 +0200 Subject: [PATCH 113/162] Update MSRV (#540) * Update msrv --- Cargo.toml | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 75a25f51..0ce6e9c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/polyphony-chat/chorus" readme = "README.md" keywords = ["spacebar", "discord", "polyphony"] website = ["https://discord.com/invite/m3FpcapGDD"] -rust-version = "1.67.1" +rust-version = "1.70.0" [features] diff --git a/README.md b/README.md index bde7f652..413ec34d 100644 --- a/README.md +++ b/README.md @@ -119,11 +119,11 @@ We recommend checking out the "examples" directory, as well as the documentation ## MSRV (Minimum Supported Rust Version) -Rust **1.67.1**. This number might change at any point while Chorus is not yet at version 1.0.0. +Rust **1.70.0**. This number might change at any point while Chorus is not yet at version 1.0.0. ## Development Setup -Make sure that you have at least Rust 1.67.1 installed. You can check your Rust version by running `cargo --version` +Make sure that you have at least Rust 1.70.0 installed. You can check your Rust version by running `cargo --version` in your terminal. To compile for `wasm32-unknown-unknown`, you need to install the `wasm32-unknown-unknown` target. You can do this by running `rustup target add wasm32-unknown-unknown`. From e4dd31ef782d6fc84fe8b4647677d98ff4afb43f Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Sun, 4 Aug 2024 13:08:56 +0200 Subject: [PATCH 114/162] sqlx related improvements (#542) * Bump sqlx to 0.8.0 * Update sqlx syntax to 0.8.0, change MySql for sqlx:: Any * Update sqlx syntax to 0.8.0, change MySql for sqlx:: Any * Modify chorus_macros::SqlxBitflagDerive to use sqlx::Any over sqlx::MySql (broken!) * Fix: `cannot infer type for type parameter `DB` declared on the trait...` * Change remaining impls of sqlx traits for MySql to sqlx::Any * Alter chorus_macros to correctly derive SqlxBitFlag for sqlx::Any * rustc/clippy>=v1.80.0: Do not warn when encountering cfg(tarpaulin_include) * Port compare_* methods to sqlx v0.8.0 --- Cargo.lock | 95 ++++++++++--------- Cargo.toml | 5 +- chorus-macros/src/lib.rs | 40 ++++++-- src/types/config/types/guild_configuration.rs | 29 +++--- src/types/entities/application.rs | 5 +- src/types/entities/audit_log.rs | 10 +- src/types/entities/channel.rs | 5 +- src/types/entities/user.rs | 20 ++-- src/types/utils/snowflake.rs | 24 +++-- 9 files changed, 143 insertions(+), 90 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d3bba65..0ed48648 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,7 +34,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", "once_cell", "version_check", "zerocopy", @@ -292,6 +291,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -541,9 +549,14 @@ dependencies = [ [[package]] name = "event-listener" -version = "2.5.3" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] [[package]] name = "fastrand" @@ -773,9 +786,9 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ "hashbrown 0.14.5", ] @@ -806,12 +819,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -1141,9 +1151,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libsqlite3-sys" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" dependencies = [ "cc", "pkg-config", @@ -1367,6 +1377,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot" version = "0.12.3" @@ -2059,6 +2075,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -2107,9 +2126,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +checksum = "27144619c6e5802f1380337a209d2ac1c431002dd74c6e60aebff3c506dc4f0c" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2120,11 +2139,10 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +checksum = "a999083c1af5b5d6c071d34a708a19ba3e02106ad82ef7bbd69f5e48266b613b" dependencies = [ - "ahash", "atoi", "byteorder", "bytes", @@ -2138,6 +2156,7 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", + "hashbrown 0.14.5", "hashlink", "hex", "indexmap 2.2.6", @@ -2164,22 +2183,22 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +checksum = "a23217eb7d86c584b8cbe0337b9eacf12ab76fe7673c513141ec42565698bb88" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 1.0.109", + "syn 2.0.70", ] [[package]] name = "sqlx-macros-core" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +checksum = "1a099220ae541c5db479c6424bdf1b200987934033c2584f79a0e1693601e776" dependencies = [ "dotenvy", "either", @@ -2195,7 +2214,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 1.0.109", + "syn 2.0.70", "tempfile", "tokio", "url", @@ -2203,12 +2222,12 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" +checksum = "5afe4c38a9b417b6a9a5eeffe7235d0a106716495536e7727d1c7f4b1ff3eba6" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bitflags 2.6.0", "byteorder", "bytes", @@ -2246,12 +2265,12 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +checksum = "b1dbb157e65f10dbe01f729339c06d239120221c9ad9fa0ba8408c4cc18ecf21" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bitflags 2.6.0", "byteorder", "chrono", @@ -2286,9 +2305,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +checksum = "9b2cdd83c008a622d94499c0006d8ee5f821f36c89b7d625c900e5dc30b5c5ee" dependencies = [ "atoi", "chrono", @@ -2302,10 +2321,10 @@ dependencies = [ "log", "percent-encoding", "serde", + "serde_urlencoded", "sqlx-core", "tracing", "url", - "urlencoding", ] [[package]] @@ -2675,12 +2694,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" -[[package]] -name = "unicode-segmentation" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" - [[package]] name = "unicode_categories" version = "0.1.1" @@ -2720,12 +2733,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "utf-8" version = "0.7.6" diff --git a/Cargo.toml b/Cargo.toml index 0ce6e9c9..83b7e9d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ jsonwebtoken = "8.3.0" log = "0.4.22" async-trait = "0.1.81" chorus-macros = { path = "./chorus-macros", version = "0" } # Note: version here is used when releasing. This will use the latest release. Make sure to republish the crate when code in macros is changed! -sqlx = { version = "0.7.4", features = [ +sqlx = { version = "0.8.0", features = [ "mysql", "sqlite", "json", @@ -87,3 +87,6 @@ lazy_static = "1.5.0" wasm-bindgen-test = "0.3.42" wasm-bindgen = "0.2.92" simple_logger = { version = "5.0.0", default-features = false } + +[lints.rust] +unexpected_cfgs = { level = "allow", check-cfg = ['cfg(tarpaulin_include)'] } diff --git a/chorus-macros/src/lib.rs b/chorus-macros/src/lib.rs index aa4f1bc9..1c3a8bdc 100644 --- a/chorus-macros/src/lib.rs +++ b/chorus-macros/src/lib.rs @@ -156,7 +156,6 @@ pub fn composite_derive(input: TokenStream) -> TokenStream { } } - #[proc_macro_derive(SqlxBitFlags)] pub fn sqlx_bitflag_derive(input: TokenStream) -> TokenStream { let ast: syn::DeriveInput = syn::parse(input).unwrap(); @@ -165,24 +164,45 @@ pub fn sqlx_bitflag_derive(input: TokenStream) -> TokenStream { quote!{ #[cfg(feature = "sqlx")] - impl sqlx::Type for #name { - fn type_info() -> sqlx::mysql::MySqlTypeInfo { - u64::type_info() + impl sqlx::Type for #name { + fn type_info() -> sqlx::any::AnyTypeInfo { + as sqlx::Type>::type_info() } } #[cfg(feature = "sqlx")] - impl<'q> sqlx::Encode<'q, sqlx::MySql> for #name { - fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { - u64::encode_by_ref(&self.bits(), buf) + impl<'q> sqlx::Encode<'q, sqlx::Any> for #name { + fn encode_by_ref(&self, buf: &mut ::ArgumentBuffer<'q>) -> Result { + as sqlx::Encode>::encode_by_ref(&self.bits().to_be_bytes().into(), buf) } } #[cfg(feature = "sqlx")] - impl<'q> sqlx::Decode<'q, sqlx::MySql> for #name { - fn decode(value: >::ValueRef) -> Result { - u64::decode(value).map(|d| #name::from_bits(d).unwrap()) + impl<'q> sqlx::Decode<'q, sqlx::Any> for #name { + fn decode(value: ::ValueRef<'q>) -> Result { + let vec = as sqlx::Decode>::decode(value)?; + Ok(Self::from_bits(vec_u8_to_u64(vec)).unwrap()) + } + } + + /// Converts a [Vec] to an unsigned, 64 bit integer. The [u64] is created using [u64::from_be_bytes]. + /// + /// Empty vectors will result in an output of `0_u64`. Only the first 8 values from the vector are + /// being processed. Any additional values will be skipped. + /// + /// Vectors holding less than 8 values will be treated as a vector holding 8 values, where the + /// missing values are padded with `0_u8`. + fn vec_u8_to_u64(vec: Vec) -> u64 { + let mut buf: [u8; 8] = [0; 8]; + let mut position = 0; + for read in vec.iter() { + buf[position] = *read; + position += 1; + if position > 7 { + break; + } } + u64::from_be_bytes(buf) } } .into() diff --git a/src/types/config/types/guild_configuration.rs b/src/types/config/types/guild_configuration.rs index 53a2d452..fc07d1cf 100644 --- a/src/types/config/types/guild_configuration.rs +++ b/src/types/config/types/guild_configuration.rs @@ -162,9 +162,11 @@ impl Display for GuildFeaturesList { } #[cfg(feature = "sqlx")] -impl<'r> sqlx::Decode<'r, sqlx::MySql> for GuildFeaturesList { - fn decode(value: >::ValueRef) -> Result { - let v = >::decode(value)?; +impl<'r> sqlx::Decode<'r, sqlx::Any> for GuildFeaturesList { + fn decode( + value: ::ValueRef<'r>, + ) -> Result { + let v = >::decode(value)?; Ok(Self( v.split(',') .filter(|f| !f.is_empty()) @@ -175,10 +177,13 @@ impl<'r> sqlx::Decode<'r, sqlx::MySql> for GuildFeaturesList { } #[cfg(feature = "sqlx")] -impl<'q> sqlx::Encode<'q, sqlx::MySql> for GuildFeaturesList { - fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { +impl<'q> sqlx::Encode<'q, sqlx::Any> for GuildFeaturesList { + fn encode_by_ref( + &self, + buf: &mut ::ArgumentBuffer<'q>, + ) -> Result> { if self.is_empty() { - return sqlx::encode::IsNull::Yes; + return Ok(sqlx::encode::IsNull::Yes); } let features = self .iter() @@ -186,18 +191,18 @@ impl<'q> sqlx::Encode<'q, sqlx::MySql> for GuildFeaturesList { .collect::>() .join(","); - >::encode_by_ref(&features, buf) + >::encode_by_ref(&features, buf) } } #[cfg(feature = "sqlx")] -impl sqlx::Type for GuildFeaturesList { - fn type_info() -> sqlx::mysql::MySqlTypeInfo { - >::type_info() +impl sqlx::Type for GuildFeaturesList { + fn type_info() -> sqlx::any::AnyTypeInfo { + >::type_info() } - fn compatible(ty: &sqlx::mysql::MySqlTypeInfo) -> bool { - >::compatible(ty) + fn compatible(ty: &sqlx::any::AnyTypeInfo) -> bool { + >::compatible(ty) } } diff --git a/src/types/entities/application.rs b/src/types/entities/application.rs index f265f21a..9c81c19b 100644 --- a/src/types/entities/application.rs +++ b/src/types/entities/application.rs @@ -102,7 +102,10 @@ fn compare_install_params( b: &Option>, ) -> bool { match (a, b) { - (Some(a), Some(b)) => a.encode_to_string() == b.encode_to_string(), + (Some(a), Some(b)) => match (a.encode_to_string(), b.encode_to_string()) { + (Ok(a), Ok(b)) => a == b, + _ => false, + }, (None, None) => true, _ => false, } diff --git a/src/types/entities/audit_log.rs b/src/types/entities/audit_log.rs index 17f3275a..7c821fc2 100644 --- a/src/types/entities/audit_log.rs +++ b/src/types/entities/audit_log.rs @@ -51,7 +51,10 @@ fn compare_options( b: &Option>, ) -> bool { match (a, b) { - (Some(a), Some(b)) => a.encode_to_string() == b.encode_to_string(), + (Some(a), Some(b)) => match (a.encode_to_string(), b.encode_to_string()) { + (Ok(a), Ok(b)) => a == b, + _ => false, + }, (None, None) => true, _ => false, } @@ -69,7 +72,10 @@ fn compare_changes( a: &sqlx::types::Json>>>, b: &sqlx::types::Json>>>, ) -> bool { - a.encode_to_string() == b.encode_to_string() + match (a.encode_to_string(), b.encode_to_string()) { + (Ok(a), Ok(b)) => a == b, + _ => false, + } } #[cfg(not(tarpaulin_include))] diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 622f14d9..3d6cd3a4 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -156,7 +156,10 @@ fn compare_permission_overwrites( b: &Option>>, ) -> bool { match (a, b) { - (Some(a), Some(b)) => a.encode_to_string() == b.encode_to_string(), + (Some(a), Some(b)) => match (a.encode_to_string(), b.encode_to_string()) { + (Ok(a), Ok(b)) => a == b, + _ => false, + }, (None, None) => true, _ => false, } diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index 674c9319..15a601b3 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -109,32 +109,32 @@ impl TryFrom> for ThemeColors { #[cfg(feature = "sqlx")] // TODO: Add tests for Encode and Decode. -impl<'q> sqlx::Encode<'q, sqlx::MySql> for ThemeColors { +impl<'q> sqlx::Encode<'q, sqlx::Any> for ThemeColors { fn encode_by_ref( &self, - buf: &mut >::ArgumentBuffer, - ) -> sqlx::encode::IsNull { + buf: &mut ::ArgumentBuffer<'q>, + ) -> Result> { let mut vec_u8 = Vec::new(); vec_u8.extend_from_slice(&self.inner.0.to_be_bytes()); vec_u8.extend_from_slice(&self.inner.1.to_be_bytes()); - as sqlx::Encode<'q, sqlx::MySql>>::encode_by_ref(&vec_u8, buf) + as sqlx::Encode>::encode_by_ref(&vec_u8, buf) } } #[cfg(feature = "sqlx")] -impl<'d> sqlx::Decode<'d, sqlx::MySql> for ThemeColors { +impl<'d> sqlx::Decode<'d, sqlx::Any> for ThemeColors { fn decode( - value: >::ValueRef, + value: ::ValueRef<'d>, ) -> Result { - let value_vec = as sqlx::Decode<'d, sqlx::MySql>>::decode(value)?; + let value_vec = as sqlx::Decode<'d, sqlx::Any>>::decode(value)?; value_vec.try_into().map_err(|e: ChorusError| e.into()) } } #[cfg(feature = "sqlx")] -impl sqlx::Type for ThemeColors { - fn type_info() -> ::TypeInfo { - >::type_info() +impl sqlx::Type for ThemeColors { + fn type_info() -> ::TypeInfo { + >::type_info() } } diff --git a/src/types/utils/snowflake.rs b/src/types/utils/snowflake.rs index a021f906..7caffc72 100644 --- a/src/types/utils/snowflake.rs +++ b/src/types/utils/snowflake.rs @@ -99,23 +99,29 @@ impl<'de> serde::Deserialize<'de> for Snowflake { } #[cfg(feature = "sqlx")] -impl sqlx::Type for Snowflake { - fn type_info() -> ::TypeInfo { - >::type_info() +impl sqlx::Type for Snowflake { + fn type_info() -> ::TypeInfo { + >::type_info() } } #[cfg(feature = "sqlx")] -impl<'q> sqlx::Encode<'q, sqlx::MySql> for Snowflake { - fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { - >::encode_by_ref(&self.0.to_string(), buf) +impl<'q> sqlx::Encode<'q, sqlx::Any> for Snowflake { + fn encode_by_ref( + &self, + buf: &mut ::ArgumentBuffer<'q>, + ) -> Result { + >::encode_by_ref(&self.0.to_string(), buf) } } #[cfg(feature = "sqlx")] -impl<'d> sqlx::Decode<'d, sqlx::MySql> for Snowflake { - fn decode(value: >::ValueRef) -> Result { - >::decode(value).map(|s| s.parse::().map(Snowflake).unwrap()) +impl<'d> sqlx::Decode<'d, sqlx::Any> for Snowflake { + fn decode( + value: ::ValueRef<'d>, + ) -> Result { + >::decode(value) + .map(|s| s.parse::().map(Snowflake).unwrap()) } } From ec9541f38e74801e2b06cd0ffbd0882bf7405d55 Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Fri, 9 Aug 2024 08:53:43 +0200 Subject: [PATCH 115/162] CI/CD: add cargo-doc job (#544) * CI/CD: add cargo-doc job * fix: make it rustdoc, totally not clippy --- .github/workflows/cargo-doc.yml | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/cargo-doc.yml diff --git a/.github/workflows/cargo-doc.yml b/.github/workflows/cargo-doc.yml new file mode 100644 index 00000000..017dbe2b --- /dev/null +++ b/.github/workflows/cargo-doc.yml @@ -0,0 +1,35 @@ +name: cargo doc lints + +on: + push: + branches: [ "main", "preserve/*" ] + pull_request: + branches: [ "main", "dev" ] + +jobs: + cargo-doc-lints: + name: Run cargo doc for doc lints + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Install aditional components for sarif + run: cargo install clippy-sarif sarif-fmt + + - name: Run cargo doc + run: cargo doc --no-deps --all-features --locked --message-format=json | clippy-sarif | sed 's/rust-lang.github.io\/rust-clippy/doc.rust-lang.org\/rustdoc\/lints.html/g' | sed 's/clippy/rustdoc/g' | tee cargo-doc-results.sarif | sarif-fmt + continue-on-error: true + + - name: Upload analysis results to GitHub + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: cargo-doc-results.sarif + wait-for-processing: true From 86b022912f9547607ca67dec8738881595e553c7 Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Wed, 21 Aug 2024 23:43:42 +0200 Subject: [PATCH 116/162] Initial support for PostgreSQL (#548) * Change sqlx::Any to sqlx::Postgres * Change sqlx::Any to sqlx::Postgres * Remove JSONified overrides when sqlx feature is enabled, where it makes sense * Add num-bigint dep * Remove generic impl for From for Snowflake For some reason, this trait bound conflicts with another trait bound from the sqlx-pg-uint crate, even though I personally don't get why. * Remove num_bigint, adsd sqlx-pg-uint * swap u64 for PgU64 in some files * use v0.3.0 of sqlx-pg-uint * Lots of sqlx-postgres type changes * Lots of sqlx-postgres type changes * gwah * Change repr(i8) to repr(i16) in enums when sqlx feature is enabled, fix sqlx incompatibilities * impl sqlx::postgres::PgHasArrayType for Snowflake * Try: derive Type for FriendSourceFlags, GuildFolder * Try: Derive FromRow, Type for DefaultReaction * Try: Derive Type for CustomStatus * Try: Derive Type, FromRow for Tag * Replace conditional compiling of uNN/PgUNN with conditional compiled type alias * Fix: Conditional compiling errors and warnings * Bump: wasm-bindgen* crate versions --- .github/workflows/build_and_test.yml | 4 +- Cargo.lock | 341 ++++++++++++------ Cargo.toml | 19 +- chorus-macros/src/lib.rs | 18 +- src/api/channels/messages.rs | 3 +- src/lib.rs | 27 +- src/types/config/types/guild_configuration.rs | 22 +- src/types/entities/application.rs | 6 +- src/types/entities/attachment.rs | 11 +- src/types/entities/audit_log.rs | 12 +- src/types/entities/auto_moderation.rs | 30 +- src/types/entities/channel.rs | 22 +- src/types/entities/emoji.rs | 3 - src/types/entities/guild.rs | 30 +- src/types/entities/integration.rs | 5 +- src/types/entities/invite.rs | 12 +- src/types/entities/message.rs | 15 +- src/types/entities/relationship.rs | 3 +- src/types/entities/role.rs | 9 +- src/types/entities/security_key.rs | 6 +- src/types/entities/stage_instance.rs | 7 +- src/types/entities/sticker.rs | 6 +- src/types/entities/team.rs | 3 +- src/types/entities/template.rs | 5 +- src/types/entities/user.rs | 27 +- src/types/entities/user_settings.rs | 48 +-- src/types/entities/webhook.rs | 3 +- src/types/schema/channel.rs | 16 +- src/types/utils/snowflake.rs | 34 +- 29 files changed, 476 insertions(+), 271 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index a69aff69..547e2e83 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -101,7 +101,7 @@ jobs: run: | rustup target add wasm32-unknown-unknown curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force + cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.93" --force GECKODRIVER=$(which geckodriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" wasm-chrome: runs-on: ubuntu-latest @@ -130,5 +130,5 @@ jobs: run: | rustup target add wasm32-unknown-unknown curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash - cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.92" --force + cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.93" --force CHROMEDRIVER=$(which chromedriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt, voice_gateway" diff --git a/Cargo.lock b/Cargo.lock index 0ed48648..21d56119 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "aead" version = "0.5.2" @@ -77,7 +83,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] @@ -122,7 +128,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object", "rustc-demangle", ] @@ -151,6 +157,20 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bigdecimal" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d712318a27c7150326677b321a5fa91b55f6d9034ffd67f20319e147d40cee" +dependencies = [ + "autocfg", + "libm", + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -189,15 +209,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.0" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8" +checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -207,9 +230,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chorus" @@ -244,6 +267,7 @@ dependencies = [ "serde_with", "simple_logger", "sqlx", + "sqlx-pg-uint", "thiserror", "tokio", "tokio-tungstenite", @@ -262,7 +286,7 @@ version = "0.4.1" dependencies = [ "async-trait", "quote", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] @@ -328,15 +352,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -433,7 +457,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] @@ -444,7 +468,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] @@ -566,12 +590,12 @@ checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "9c0596c1eac1f9e04ed902702e9878208b336edc9d6fddc8a48387349bab3666" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] @@ -667,7 +691,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] @@ -742,7 +766,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.4.0", "slab", "tokio", "tokio-util", @@ -751,9 +775,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", "bytes", @@ -761,7 +785,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.2.6", + "indexmap 2.4.0", "slab", "tokio", "tokio-util", @@ -908,9 +932,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http 1.1.0", @@ -925,7 +949,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -974,9 +998,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "httparse", "httpdate", "itoa", @@ -1001,14 +1025,14 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "hyper 1.4.1", "pin-project-lite", "tokio", @@ -1066,9 +1090,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -1107,9 +1131,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -1139,9 +1163,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libm" @@ -1220,6 +1244,16 @@ dependencies = [ "unicase", ] +[[package]] +name = "minicov" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169" +dependencies = [ + "cc", + "walkdir", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1235,11 +1269,20 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "mio" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi", "libc", @@ -1267,9 +1310,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -1358,9 +1401,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.1" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] @@ -1401,7 +1444,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "smallvec", "windows-targets 0.52.6", ] @@ -1517,9 +1560,9 @@ dependencies = [ [[package]] name = "poem" -version = "3.0.1" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88b6912ed1e8833d7c22c9c986c517f4518d7d37e3c04566d917c789aaea591" +checksum = "f1ba1c27f8f89e1bccdda0c680f72790545a11a8d8555819472f5839d7a8ca9d" dependencies = [ "bytes", "futures-util", @@ -1551,14 +1594,14 @@ dependencies = [ [[package]] name = "poem-derive" -version = "3.0.0" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2b961d58a6c53380c20236394381d9292fda03577f902b158f1638932964dcf" +checksum = "a62fea1692d80a000126f9b28d865012a160b80000abb53ccf152b428222c155" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] @@ -1580,9 +1623,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro-crate" @@ -1661,18 +1707,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.10.5" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -1849,9 +1895,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" @@ -1878,6 +1924,15 @@ dependencies = [ "cipher", ] +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -1914,9 +1969,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] @@ -1934,22 +1989,23 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -1962,7 +2018,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] @@ -1987,7 +2043,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.6", + "indexmap 2.4.0", "serde", "serde_derive", "serde_json", @@ -2004,7 +2060,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] @@ -2029,6 +2085,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" version = "2.2.0" @@ -2144,6 +2206,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a999083c1af5b5d6c071d34a708a19ba3e02106ad82ef7bbd69f5e48266b613b" dependencies = [ "atoi", + "bigdecimal", "byteorder", "bytes", "chrono", @@ -2159,7 +2222,7 @@ dependencies = [ "hashbrown 0.14.5", "hashlink", "hex", - "indexmap 2.2.6", + "indexmap 2.4.0", "ipnetwork", "log", "memchr", @@ -2191,7 +2254,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] @@ -2214,7 +2277,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.70", + "syn 2.0.75", "tempfile", "tokio", "url", @@ -2228,6 +2291,7 @@ checksum = "5afe4c38a9b417b6a9a5eeffe7235d0a106716495536e7727d1c7f4b1ff3eba6" dependencies = [ "atoi", "base64 0.22.1", + "bigdecimal", "bitflags 2.6.0", "byteorder", "bytes", @@ -2263,6 +2327,27 @@ dependencies = [ "whoami", ] +[[package]] +name = "sqlx-pg-uint" +version = "0.3.0" +source = "git+https://github.com/bitfl0wer/sqlx-pg-uint#a132f4ad12f6cd1f68cc07e01edd644b4735e346" +dependencies = [ + "bigdecimal", + "serde", + "sqlx", + "sqlx-pg-uint-macros", + "thiserror", +] + +[[package]] +name = "sqlx-pg-uint-macros" +version = "0.3.0" +source = "git+https://github.com/bitfl0wer/sqlx-pg-uint#a132f4ad12f6cd1f68cc07e01edd644b4735e346" +dependencies = [ + "quote", + "syn 2.0.75", +] + [[package]] name = "sqlx-postgres" version = "0.8.0" @@ -2271,6 +2356,7 @@ checksum = "b1dbb157e65f10dbe01f729339c06d239120221c9ad9fa0ba8408c4cc18ecf21" dependencies = [ "atoi", "base64 0.22.1", + "bigdecimal", "bitflags 2.6.0", "byteorder", "chrono", @@ -2290,6 +2376,7 @@ dependencies = [ "log", "md-5", "memchr", + "num-bigint", "once_cell", "rand", "serde", @@ -2363,9 +2450,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.70" +version = "2.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" +checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" dependencies = [ "proc-macro2", "quote", @@ -2410,14 +2497,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2437,7 +2525,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] @@ -2488,9 +2576,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" dependencies = [ "backtrace", "bytes", @@ -2510,7 +2598,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] @@ -2564,9 +2652,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" @@ -2574,16 +2662,16 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.4.0", "toml_datetime", "winnow", ] [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -2605,7 +2693,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] @@ -2690,9 +2778,9 @@ dependencies = [ [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" [[package]] name = "unicode_categories" @@ -2747,9 +2835,19 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] [[package]] name = "want" @@ -2774,34 +2872,35 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.75", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -2811,9 +2910,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2821,31 +2920,32 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.75", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-bindgen-test" -version = "0.3.42" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" +checksum = "68497a05fb21143a08a7d24fc81763384a3072ee43c44e86aad1744d6adef9d9" dependencies = [ "console_error_panic_hook", "js-sys", + "minicov", "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", @@ -2854,13 +2954,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.42" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" +checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] @@ -2879,9 +2979,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -2934,6 +3034,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -2967,6 +3076,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -3132,6 +3250,7 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] @@ -3143,7 +3262,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.75", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 83b7e9d8..6529fbc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,17 +13,18 @@ rust-version = "1.70.0" [features] default = ["client", "rt-multi-thread"] -backend = ["poem", "sqlx"] +backend = ["poem", "sqlx", "sqlx-pg-uint"] rt-multi-thread = ["tokio/rt-multi-thread"] rt = ["tokio/rt"] client = ["flate2"] voice = ["voice_udp", "voice_gateway"] voice_udp = ["dep:discortp", "dep:crypto_secretbox"] voice_gateway = [] +sqlx-pg-uint = ["dep:sqlx-pg-uint", "sqlx-pg-uint/serde"] [dependencies] tokio = { version = "1.38.1", features = ["macros", "sync"] } -serde = { version = "1.0.204", features = ["derive", "rc"] } +serde = { version = "1.0.208", features = ["derive", "rc"] } serde_json = { version = "1.0.120", features = ["raw_value"] } serde-aux = "4.5.0" serde_with = "3.9.0" @@ -49,13 +50,12 @@ log = "0.4.22" async-trait = "0.1.81" chorus-macros = { path = "./chorus-macros", version = "0" } # Note: version here is used when releasing. This will use the latest release. Make sure to republish the crate when code in macros is changed! sqlx = { version = "0.8.0", features = [ - "mysql", - "sqlite", "json", "chrono", "ipnetwork", "runtime-tokio-rustls", - "any", + "postgres", + "bigdecimal", ], optional = true } discortp = { version = "0.5.0", optional = true, features = [ "rtp", @@ -67,6 +67,9 @@ rand = "0.8.5" flate2 = { version = "1.0.30", optional = true } webpki-roots = "0.26.3" pubserve = { version = "1.1.0", features = ["async", "send"] } +sqlx-pg-uint = { git = "https://github.com/bitfl0wer/sqlx-pg-uint", features = [ + "serde", +], optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] rustls = "0.21.12" @@ -79,13 +82,13 @@ getrandom = { version = "0.2.15" } [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2.15", features = ["js"] } ws_stream_wasm = "0.7.4" -wasm-bindgen-futures = "0.4.42" +wasm-bindgen-futures = "0.4.43" wasmtimer = "0.2.0" [dev-dependencies] lazy_static = "1.5.0" -wasm-bindgen-test = "0.3.42" -wasm-bindgen = "0.2.92" +wasm-bindgen-test = "0.3.43" +wasm-bindgen = "0.2.93" simple_logger = { version = "5.0.0", default-features = false } [lints.rust] diff --git a/chorus-macros/src/lib.rs b/chorus-macros/src/lib.rs index 1c3a8bdc..c2a23c5a 100644 --- a/chorus-macros/src/lib.rs +++ b/chorus-macros/src/lib.rs @@ -164,23 +164,23 @@ pub fn sqlx_bitflag_derive(input: TokenStream) -> TokenStream { quote!{ #[cfg(feature = "sqlx")] - impl sqlx::Type for #name { - fn type_info() -> sqlx::any::AnyTypeInfo { - as sqlx::Type>::type_info() + impl sqlx::Type for #name { + fn type_info() -> sqlx::postgres::PgTypeInfo { + as sqlx::Type>::type_info() } } #[cfg(feature = "sqlx")] - impl<'q> sqlx::Encode<'q, sqlx::Any> for #name { - fn encode_by_ref(&self, buf: &mut ::ArgumentBuffer<'q>) -> Result { - as sqlx::Encode>::encode_by_ref(&self.bits().to_be_bytes().into(), buf) + impl<'q> sqlx::Encode<'q, sqlx::Postgres> for #name { + fn encode_by_ref(&self, buf: &mut ::ArgumentBuffer<'q>) -> Result { + as sqlx::Encode>::encode_by_ref(&self.bits().to_be_bytes().into(), buf) } } #[cfg(feature = "sqlx")] - impl<'q> sqlx::Decode<'q, sqlx::Any> for #name { - fn decode(value: ::ValueRef<'q>) -> Result { - let vec = as sqlx::Decode>::decode(value)?; + impl<'q> sqlx::Decode<'q, sqlx::Postgres> for #name { + fn decode(value: ::ValueRef<'q>) -> Result { + let vec = as sqlx::Decode>::decode(value)?; Ok(Self::from_bits(vec_u8_to_u64(vec)).unwrap()) } } diff --git a/src/api/channels/messages.rs b/src/api/channels/messages.rs index feabc371..6387d12c 100644 --- a/src/api/channels/messages.rs +++ b/src/api/channels/messages.rs @@ -16,6 +16,7 @@ use crate::types::{ }; impl Message { + #[allow(clippy::useless_conversion)] /// Sends a message in the channel with the provided channel_id. /// Returns the sent message. /// @@ -40,7 +41,7 @@ impl Message { chorus_request.deserialize_response::(user).await } else { for (index, attachment) in message.attachments.iter_mut().enumerate() { - attachment.get_mut(index).unwrap().id = Some(index as i16); + attachment.get_mut(index).unwrap().id = Some((index as u64).into()); } let mut form = reqwest::multipart::Form::new(); let payload_json = to_string(&message).unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 7767480f..b16f12ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,8 +101,7 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read clippy::extra_unused_lifetimes, clippy::from_over_into, clippy::needless_borrow, - clippy::new_without_default, - clippy::useless_conversion + clippy::new_without_default )] #![warn( clippy::todo, @@ -111,7 +110,8 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read clippy::print_stdout, clippy::print_stderr, missing_debug_implementations, - missing_copy_implementations + missing_copy_implementations, + clippy::useless_conversion )] #[cfg(all(feature = "rt", feature = "rt_multi_thread"))] compile_error!("feature \"rt\" and feature \"rt_multi_thread\" cannot be enabled at the same time"); @@ -139,6 +139,27 @@ pub mod types; ))] pub mod voice; +#[cfg(not(feature = "sqlx"))] +pub type UInt128 = u128; +#[cfg(feature = "sqlx")] +pub type UInt128 = sqlx_pg_uint::PgU128; +#[cfg(not(feature = "sqlx"))] +pub type UInt64 = u64; +#[cfg(feature = "sqlx")] +pub type UInt64 = sqlx_pg_uint::PgU64; +#[cfg(not(feature = "sqlx"))] +pub type UInt32 = u32; +#[cfg(feature = "sqlx")] +pub type UInt32 = sqlx_pg_uint::PgU32; +#[cfg(not(feature = "sqlx"))] +pub type UInt16 = u16; +#[cfg(feature = "sqlx")] +pub type UInt16 = sqlx_pg_uint::PgU16; +#[cfg(not(feature = "sqlx"))] +pub type UInt8 = u8; +#[cfg(feature = "sqlx")] +pub type UInt8 = sqlx_pg_uint::PgU8; + #[derive(Clone, Default, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] /// A URLBundle bundles together the API-, Gateway- and CDN-URLs of a Spacebar instance. /// diff --git a/src/types/config/types/guild_configuration.rs b/src/types/config/types/guild_configuration.rs index fc07d1cf..95bf6c4f 100644 --- a/src/types/config/types/guild_configuration.rs +++ b/src/types/config/types/guild_configuration.rs @@ -162,11 +162,11 @@ impl Display for GuildFeaturesList { } #[cfg(feature = "sqlx")] -impl<'r> sqlx::Decode<'r, sqlx::Any> for GuildFeaturesList { +impl<'r> sqlx::Decode<'r, sqlx::Postgres> for GuildFeaturesList { fn decode( - value: ::ValueRef<'r>, + value: ::ValueRef<'r>, ) -> Result { - let v = >::decode(value)?; + let v = >::decode(value)?; Ok(Self( v.split(',') .filter(|f| !f.is_empty()) @@ -177,10 +177,10 @@ impl<'r> sqlx::Decode<'r, sqlx::Any> for GuildFeaturesList { } #[cfg(feature = "sqlx")] -impl<'q> sqlx::Encode<'q, sqlx::Any> for GuildFeaturesList { +impl<'q> sqlx::Encode<'q, sqlx::Postgres> for GuildFeaturesList { fn encode_by_ref( &self, - buf: &mut ::ArgumentBuffer<'q>, + buf: &mut ::ArgumentBuffer<'q>, ) -> Result> { if self.is_empty() { return Ok(sqlx::encode::IsNull::Yes); @@ -191,18 +191,18 @@ impl<'q> sqlx::Encode<'q, sqlx::Any> for GuildFeaturesList { .collect::>() .join(","); - >::encode_by_ref(&features, buf) + >::encode_by_ref(&features, buf) } } #[cfg(feature = "sqlx")] -impl sqlx::Type for GuildFeaturesList { - fn type_info() -> sqlx::any::AnyTypeInfo { - >::type_info() +impl sqlx::Type for GuildFeaturesList { + fn type_info() -> ::TypeInfo { + >::type_info() } - fn compatible(ty: &sqlx::any::AnyTypeInfo) -> bool { - >::compatible(ty) + fn compatible(ty: &::TypeInfo) -> bool { + >::compatible(ty) } } diff --git a/src/types/entities/application.rs b/src/types/entities/application.rs index 9c81c19b..512a031a 100644 --- a/src/types/entities/application.rs +++ b/src/types/entities/application.rs @@ -224,7 +224,8 @@ pub struct ApplicationCommandOptionChoice { #[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr, PartialEq, Eq, Hash)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(i32)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] /// # Reference /// See pub enum ApplicationCommandOptionType { @@ -294,7 +295,8 @@ pub struct ApplicationCommandPermission { Ord, )] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] /// See pub enum ApplicationCommandPermissionType { #[default] diff --git a/src/types/entities/attachment.rs b/src/types/entities/attachment.rs index f2e221d1..acd0d62a 100644 --- a/src/types/entities/attachment.rs +++ b/src/types/entities/attachment.rs @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::types::utils::Snowflake; +use crate::UInt64; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, PartialOrd)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -16,11 +17,11 @@ pub struct Attachment { /// Max 1024 characters pub description: Option, pub content_type: Option, - pub size: u64, + pub size: UInt64, pub url: String, pub proxy_url: String, - pub height: Option, - pub width: Option, + pub height: Option, + pub width: Option, pub ephemeral: Option, /// The duration of the audio file (only for voice messages) pub duration_secs: Option, @@ -37,12 +38,12 @@ pub struct Attachment { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] pub struct PartialDiscordFileAttachment { - pub id: Option, + pub id: Option, pub filename: String, /// Max 1024 characters pub description: Option, pub content_type: Option, - pub size: Option, + pub size: Option, pub url: Option, pub proxy_url: Option, pub height: Option, diff --git a/src/types/entities/audit_log.rs b/src/types/entities/audit_log.rs index 7c821fc2..97676d3d 100644 --- a/src/types/entities/audit_log.rs +++ b/src/types/entities/audit_log.rs @@ -12,6 +12,7 @@ use crate::types::utils::Snowflake; use crate::types::{ AutoModerationRuleTriggerType, IntegrationType, PermissionOverwriteType, Shared, }; +use crate::UInt64; #[derive(Serialize, Deserialize, Debug, Default, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -108,7 +109,8 @@ pub struct AuditLogChange { PartialOrd, Ord, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] /// # Reference: /// See @@ -251,16 +253,16 @@ pub struct AuditEntryInfo { pub auto_moderation_rule_trigger_type: Option, pub channel_id: Option, // #[serde(option_string)] - pub count: Option, + pub count: Option, // #[serde(option_string)] - pub delete_member_days: Option, + pub delete_member_days: Option, /// The ID of the overwritten entity pub id: Option, pub integration_type: Option, // #[serde(option_string)] - pub members_removed: Option, + pub members_removed: Option, // #[serde(option_string)] - pub message_id: Option, + pub message_id: Option, pub role_name: Option, #[serde(rename = "type")] pub overwrite_type: Option, diff --git a/src/types/entities/auto_moderation.rs b/src/types/entities/auto_moderation.rs index 3caa16cf..2ee65b66 100644 --- a/src/types/entities/auto_moderation.rs +++ b/src/types/entities/auto_moderation.rs @@ -5,6 +5,7 @@ #[cfg(feature = "client")] use crate::gateway::Updateable; use crate::types::Shared; +use crate::UInt8; #[cfg(feature = "client")] use chorus_macros::Updateable; @@ -32,7 +33,8 @@ pub struct AutoModerationRule { } #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default, Copy)] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum AutoModerationRuleEventType { @@ -43,7 +45,8 @@ pub enum AutoModerationRuleEventType { #[derive( Serialize_repr, Deserialize_repr, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum AutoModerationRuleTriggerType { @@ -80,18 +83,20 @@ pub struct AutoModerationRuleTriggerMetadataForKeywordPreset { pub allow_list: Vec, } -#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy)] +#[allow(missing_copy_implementations)] +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] /// See pub struct AutoModerationRuleTriggerMetadataForMentionSpam { /// Max 50 - pub mention_total_limit: u8, + pub mention_total_limit: UInt8, pub mention_raid_protection_enabled: bool, } #[derive( Serialize_repr, Deserialize_repr, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum AutoModerationRuleKeywordPresetType { @@ -110,9 +115,20 @@ pub struct AutoModerationAction { } #[derive( - Serialize_repr, Deserialize_repr, Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Copy, Hash + Serialize_repr, + Deserialize_repr, + Debug, + Clone, + Default, + PartialEq, + Eq, + PartialOrd, + Ord, + Copy, + Hash, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum AutoModerationActionType { diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 3d6cd3a4..df301533 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -22,6 +22,7 @@ use crate::gateway::GatewayHandle; #[cfg(feature = "client")] use crate::gateway::Updateable; +use crate::UInt64; #[cfg(feature = "client")] use chorus_macros::{observe_option_vec, Composite, Updateable}; @@ -41,13 +42,7 @@ use super::{option_arc_rwlock_ptr_eq, option_vec_arc_rwlock_ptr_eq}; /// See pub struct Channel { pub application_id: Option, - #[cfg(feature = "sqlx")] - pub applied_tags: Option>>, - #[cfg(not(feature = "sqlx"))] pub applied_tags: Option>, - #[cfg(feature = "sqlx")] - pub available_tags: Option>>, - #[cfg(not(feature = "sqlx"))] pub available_tags: Option>, pub bitrate: Option, #[serde(rename = "type")] @@ -55,9 +50,7 @@ pub struct Channel { pub created_at: Option>, pub default_auto_archive_duration: Option, pub default_forum_layout: Option, - #[cfg(feature = "sqlx")] - pub default_reaction_emoji: Option>, - #[cfg(not(feature = "sqlx"))] + // DefaultReaction could be stored in a separate table. However, there are a lot of default emojis. How would we handle that? pub default_reaction_emoji: Option, pub default_sort_order: Option, pub default_thread_rate_limit_per_user: Option, @@ -179,6 +172,8 @@ fn compare_permission_overwrites( /// /// # Reference /// See +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow, sqlx::Type))] +#[cfg_attr(feature = "sqlx", sqlx(type_name = "interface_type"))] pub struct Tag { pub id: Snowflake, /// The name of the tag (max 20 characters) @@ -202,7 +197,8 @@ pub struct PermissionOverwrite { } #[derive(Debug, Serialize_repr, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] /// # Reference /// /// See @@ -301,7 +297,7 @@ pub struct ThreadMember { pub id: Option, pub user_id: Option, pub join_timestamp: Option>, - pub flags: Option, + pub flags: Option, pub member: Option>, } @@ -321,6 +317,8 @@ impl PartialEq for ThreadMember { /// /// # Reference /// See +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow, sqlx::Type))] +#[cfg_attr(feature = "sqlx", sqlx(type_name = "interface_type"))] pub struct DefaultReaction { #[serde(default)] pub emoji_id: Option, @@ -342,7 +340,7 @@ pub struct DefaultReaction { )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -#[repr(u32)] +#[repr(i32)] /// # Reference /// See pub enum ChannelType { diff --git a/src/types/entities/emoji.rs b/src/types/entities/emoji.rs index 82f3e375..9a59ab03 100644 --- a/src/types/entities/emoji.rs +++ b/src/types/entities/emoji.rs @@ -32,9 +32,6 @@ use super::option_arc_rwlock_ptr_eq; pub struct Emoji { pub id: Snowflake, pub name: Option, - #[cfg(feature = "sqlx")] - pub roles: Option>>, - #[cfg(not(feature = "sqlx"))] pub roles: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub user: Option>, diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index cca9b94a..423339a1 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -17,6 +17,7 @@ use crate::types::{ interfaces::WelcomeScreenObject, utils::Snowflake, }; +use crate::UInt64; use super::{option_arc_rwlock_ptr_eq, vec_arc_rwlock_ptr_eq, PublicUser}; @@ -273,7 +274,7 @@ pub struct GuildScheduledEvent { pub entity_id: Option, pub entity_metadata: Option, pub creator: Option>, - pub user_count: Option, + pub user_count: Option, pub image: Option, } @@ -300,7 +301,8 @@ impl PartialEq for GuildScheduledEvent { } #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, PartialEq, Copy)] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] /// See pub enum GuildScheduledEventPrivacyLevel { #[default] @@ -308,7 +310,8 @@ pub enum GuildScheduledEventPrivacyLevel { } #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, PartialEq, Copy)] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] /// See pub enum GuildScheduledEventStatus { #[default] @@ -331,7 +334,8 @@ pub enum GuildScheduledEventStatus { Copy, Hash, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] /// See pub enum GuildScheduledEventEntityType { #[default] @@ -369,7 +373,8 @@ pub struct VoiceRegion { Ord, )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum MessageNotificationLevel { @@ -392,7 +397,8 @@ pub enum MessageNotificationLevel { Ord, )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum ExplicitContentFilterLevel { @@ -416,7 +422,8 @@ pub enum ExplicitContentFilterLevel { Ord, )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum VerificationLevel { @@ -442,7 +449,8 @@ pub enum VerificationLevel { Ord, )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum MFALevel { @@ -465,7 +473,8 @@ pub enum MFALevel { Ord, )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum NSFWLevel { @@ -490,7 +499,8 @@ pub enum NSFWLevel { Ord, )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum PremiumTier { diff --git a/src/types/entities/integration.rs b/src/types/entities/integration.rs index 16cd9914..50a82819 100644 --- a/src/types/entities/integration.rs +++ b/src/types/entities/integration.rs @@ -10,6 +10,7 @@ use crate::types::{ utils::Snowflake, Shared, }; +use crate::{UInt16, UInt8}; #[derive(Default, Debug, Deserialize, Serialize, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -23,8 +24,8 @@ pub struct Integration { pub syncing: Option, pub role_id: Option, pub enabled_emoticons: Option, - pub expire_behaviour: Option, - pub expire_grace_period: Option, + pub expire_behaviour: Option, + pub expire_grace_period: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub user: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] diff --git a/src/types/entities/invite.rs b/src/types/entities/invite.rs index 0160ac9e..40f5e726 100644 --- a/src/types/entities/invite.rs +++ b/src/types/entities/invite.rs @@ -5,8 +5,12 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use crate::types::{Snowflake, WelcomeScreenObject, Shared, InviteFlags, InviteType, InviteTargetType, Guild, VerificationLevel}; use crate::types::types::guild_configuration::GuildFeaturesList; +use crate::types::{ + Guild, InviteFlags, InviteTargetType, InviteType, Shared, Snowflake, VerificationLevel, + WelcomeScreenObject, +}; +use crate::{UInt32, UInt8}; use super::guild::GuildScheduledEvent; use super::{Application, Channel, GuildMember, NSFWLevel, User}; @@ -36,8 +40,8 @@ pub struct Invite { pub invite_type: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub inviter: Option, - pub max_age: Option, - pub max_uses: Option, + pub max_age: Option, + pub max_uses: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub stage_instance: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] @@ -47,7 +51,7 @@ pub struct Invite { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub target_user: Option, pub temporary: Option, - pub uses: Option, + pub uses: Option, } /// The guild an invite is for. diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index dbea3d5b..b63eb3bf 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -15,6 +15,7 @@ use crate::types::{ utils::Snowflake, Shared, }; +use crate::{UInt32, UInt8}; use super::option_arc_rwlock_ptr_eq; @@ -150,7 +151,7 @@ pub enum MessageReferenceType { pub struct MessageInteraction { pub id: Snowflake, #[serde(rename = "type")] - pub interaction_type: u8, + pub interaction_type: UInt8, pub name: String, pub user: User, pub member: Option>, @@ -282,8 +283,8 @@ pub struct EmbedField { #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct Reaction { - pub count: u32, - pub burst_count: u32, + pub count: UInt32, + pub burst_count: UInt32, #[serde(default)] pub me: bool, #[serde(default)] @@ -296,6 +297,8 @@ pub struct Reaction { } #[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, Eq, PartialOrd, Ord)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] pub enum Component { ActionRow = 1, Button = 2, @@ -320,7 +323,8 @@ pub struct MessageActivity { Debug, Default, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr, Eq, PartialOrd, Ord, )] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] /// # Reference /// See @@ -464,7 +468,8 @@ pub struct PartialEmoji { #[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, PartialOrd, Ord, Eq, Hash)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] pub enum ReactionType { Normal = 0, Burst = 1, // The dreaded super reactions diff --git a/src/types/entities/relationship.rs b/src/types/entities/relationship.rs index e3276db8..08cb41f1 100644 --- a/src/types/entities/relationship.rs +++ b/src/types/entities/relationship.rs @@ -45,7 +45,8 @@ impl PartialEq for Relationship { Copy, Hash, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] /// See pub enum RelationshipType { Suggestion = 6, diff --git a/src/types/entities/role.rs b/src/types/entities/role.rs index 20d2fcfe..8c2322c4 100644 --- a/src/types/entities/role.rs +++ b/src/types/entities/role.rs @@ -8,6 +8,7 @@ use serde_aux::prelude::deserialize_option_number_from_string; use std::fmt::Debug; use crate::types::utils::Snowflake; +use crate::{UInt16, UInt32}; #[cfg(feature = "client")] use chorus_macros::{Composite, Updateable}; @@ -32,7 +33,7 @@ pub struct RoleObject { pub hoist: bool, pub icon: Option, pub unicode_emoji: Option, - pub position: u16, + pub position: UInt16, #[serde(default)] pub permissions: PermissionFlags, pub managed: bool, @@ -47,11 +48,13 @@ pub struct RoleObject { pub struct RoleSubscriptionData { pub role_subscription_listing_id: Snowflake, pub tier_name: String, - pub total_months_subscribed: u32, + pub total_months_subscribed: UInt32, pub is_renewal: bool, } -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)] +#[derive( + Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord, +)] /// See pub struct RoleTags { #[serde(default)] diff --git a/src/types/entities/security_key.rs b/src/types/entities/security_key.rs index 7e0bb6bb..ac6be8cc 100644 --- a/src/types/entities/security_key.rs +++ b/src/types/entities/security_key.rs @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::types::utils::Snowflake; +use crate::UInt64; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] @@ -13,7 +14,7 @@ pub struct SecurityKey { pub user_id: String, pub key_id: String, pub public_key: String, - pub counter: u64, + pub counter: UInt64, pub name: String, } @@ -24,7 +25,8 @@ impl Default for SecurityKey { user_id: String::new(), key_id: String::new(), public_key: String::new(), - counter: 0, + #[allow(clippy::useless_conversion)] + counter: 0u64.into(), name: String::new(), } } diff --git a/src/types/entities/stage_instance.rs b/src/types/entities/stage_instance.rs index 38e28170..cf473fa4 100644 --- a/src/types/entities/stage_instance.rs +++ b/src/types/entities/stage_instance.rs @@ -21,8 +21,11 @@ pub struct StageInstance { pub guild_scheduled_event_id: Option, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(u8)] +#[derive( + Serialize_repr, Deserialize_repr, Debug, Clone, Default, Copy, PartialEq, Eq, PartialOrd, Ord, +)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// See pub enum StageInstancePrivacyLevel { diff --git a/src/types/entities/sticker.rs b/src/types/entities/sticker.rs index 6fcc708b..73505a77 100644 --- a/src/types/entities/sticker.rs +++ b/src/types/entities/sticker.rs @@ -77,7 +77,8 @@ pub struct StickerItem { #[derive( Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Serialize_repr, Deserialize_repr, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename = "SCREAMING_SNAKE_CASE")] /// # Reference @@ -93,7 +94,8 @@ pub enum StickerType { #[derive( Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Hash, Serialize_repr, Deserialize_repr, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] /// # Reference /// See diff --git a/src/types/entities/team.rs b/src/types/entities/team.rs index 4748fad3..8c36e0ea 100644 --- a/src/types/entities/team.rs +++ b/src/types/entities/team.rs @@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::types::entities::User; use crate::types::Shared; use crate::types::Snowflake; +use crate::UInt8; use super::arc_rwlock_ptr_eq; @@ -34,7 +35,7 @@ impl PartialEq for Team { #[derive(Debug, Deserialize, Serialize, Clone)] pub struct TeamMember { - pub membership_state: u8, + pub membership_state: UInt8, pub permissions: Vec, pub team_id: Snowflake, pub user: Shared, diff --git a/src/types/entities/template.rs b/src/types/entities/template.rs index e82ec172..29e53689 100644 --- a/src/types/entities/template.rs +++ b/src/types/entities/template.rs @@ -6,10 +6,11 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::types::{ - Shared, entities::{Guild, User}, utils::Snowflake, + Shared, }; +use crate::UInt64; /// See #[derive(Serialize, Deserialize, Debug, Default, Clone)] @@ -18,7 +19,7 @@ pub struct GuildTemplate { pub code: String, pub name: String, pub description: Option, - pub usage_count: Option, + pub usage_count: Option, pub creator_id: Snowflake, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub creator: Shared, diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index 15a601b3..866d66cf 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -4,6 +4,7 @@ use crate::errors::ChorusError; use crate::types::utils::Snowflake; +use crate::{UInt32, UInt8}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_aux::prelude::deserialize_option_number_from_string; @@ -47,7 +48,7 @@ pub struct User { pub bot: Option, pub system: Option, pub mfa_enabled: Option, - pub accent_color: Option, + pub accent_color: Option, #[cfg_attr(feature = "sqlx", sqlx(default))] pub locale: Option, pub verified: Option, @@ -58,7 +59,7 @@ pub struct User { #[serde(deserialize_with = "deserialize_option_number_from_string")] pub flags: Option, pub premium_since: Option>, - pub premium_type: Option, + pub premium_type: Option, pub pronouns: Option, pub public_flags: Option, pub banner: Option, @@ -109,32 +110,32 @@ impl TryFrom> for ThemeColors { #[cfg(feature = "sqlx")] // TODO: Add tests for Encode and Decode. -impl<'q> sqlx::Encode<'q, sqlx::Any> for ThemeColors { +impl<'q> sqlx::Encode<'q, sqlx::Postgres> for ThemeColors { fn encode_by_ref( &self, - buf: &mut ::ArgumentBuffer<'q>, + buf: &mut ::ArgumentBuffer<'q>, ) -> Result> { let mut vec_u8 = Vec::new(); vec_u8.extend_from_slice(&self.inner.0.to_be_bytes()); vec_u8.extend_from_slice(&self.inner.1.to_be_bytes()); - as sqlx::Encode>::encode_by_ref(&vec_u8, buf) + as sqlx::Encode>::encode_by_ref(&vec_u8, buf) } } #[cfg(feature = "sqlx")] -impl<'d> sqlx::Decode<'d, sqlx::Any> for ThemeColors { +impl<'d> sqlx::Decode<'d, sqlx::Postgres> for ThemeColors { fn decode( - value: ::ValueRef<'d>, + value: ::ValueRef<'d>, ) -> Result { - let value_vec = as sqlx::Decode<'d, sqlx::Any>>::decode(value)?; + let value_vec = as sqlx::Decode<'d, sqlx::Postgres>>::decode(value)?; value_vec.try_into().map_err(|e: ChorusError| e.into()) } } #[cfg(feature = "sqlx")] -impl sqlx::Type for ThemeColors { - fn type_info() -> ::TypeInfo { - >::type_info() +impl sqlx::Type for ThemeColors { + fn type_info() -> ::TypeInfo { + >::type_info() } } @@ -144,13 +145,13 @@ pub struct PublicUser { pub username: Option, pub discriminator: Option, pub avatar: Option, - pub accent_color: Option, + pub accent_color: Option, pub banner: Option, pub theme_colors: Option, pub pronouns: Option, pub bot: Option, pub bio: Option, - pub premium_type: Option, + pub premium_type: Option, pub premium_since: Option>, pub public_flags: Option, } diff --git a/src/types/entities/user_settings.rs b/src/types/entities/user_settings.rs index 395db2d9..1f4c1769 100644 --- a/src/types/entities/user_settings.rs +++ b/src/types/entities/user_settings.rs @@ -6,9 +6,12 @@ use chrono::{serde::ts_milliseconds_option, Utc}; use serde::{Deserialize, Serialize}; use crate::types::Shared; +use crate::{UInt16, UInt32, UInt8}; use serde_aux::field_attributes::deserialize_option_number_from_string; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Copy, PartialOrd, Ord, Hash)] +#[derive( + Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Copy, PartialOrd, Ord, Hash, +)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "lowercase")] pub enum UserStatus { @@ -26,7 +29,9 @@ impl std::fmt::Display for UserStatus { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Copy, PartialOrd, Ord, Hash)] +#[derive( + Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Copy, PartialOrd, Ord, Hash, +)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "lowercase")] pub enum UserTheme { @@ -38,36 +43,23 @@ pub enum UserTheme { #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct UserSettings { - pub afk_timeout: Option, + pub afk_timeout: Option, pub allow_accessibility_detection: bool, pub animate_emoji: bool, - pub animate_stickers: u8, + pub animate_stickers: UInt8, pub contact_sync_enabled: bool, pub convert_emoticons: bool, - #[cfg(feature = "sqlx")] - pub custom_status: Option>, - #[cfg(not(feature = "sqlx"))] pub custom_status: Option, pub default_guilds_restricted: bool, pub detect_platform_accounts: bool, pub developer_mode: bool, pub disable_games_tab: bool, pub enable_tts_command: bool, - pub explicit_content_filter: u8, - #[cfg(feature = "sqlx")] - pub friend_source_flags: sqlx::types::Json, - #[cfg(not(feature = "sqlx"))] + pub explicit_content_filter: UInt8, pub friend_source_flags: FriendSourceFlags, pub gateway_connected: Option, pub gif_auto_play: bool, - #[cfg(feature = "sqlx")] - pub guild_folders: sqlx::types::Json>, - #[cfg(not(feature = "sqlx"))] pub guild_folders: Vec, - #[cfg(feature = "sqlx")] - #[serde(default)] - pub guild_positions: sqlx::types::Json>, - #[cfg(not(feature = "sqlx"))] #[serde(default)] pub guild_positions: Vec, pub inline_attachment_media: bool, @@ -77,9 +69,6 @@ pub struct UserSettings { pub native_phone_integration_enabled: bool, pub render_embeds: bool, pub render_reactions: bool, - #[cfg(feature = "sqlx")] - pub restricted_guilds: sqlx::types::Json>, - #[cfg(not(feature = "sqlx"))] pub restricted_guilds: Vec, pub show_current_game: bool, pub status: Shared, @@ -91,10 +80,14 @@ pub struct UserSettings { impl Default for UserSettings { fn default() -> Self { Self { - afk_timeout: Some(3600), + #[allow(clippy::useless_conversion)] + afk_timeout: Some(3600u16.into()), allow_accessibility_detection: true, animate_emoji: true, + #[cfg(not(feature = "sqlx"))] animate_stickers: 0, + #[cfg(feature = "sqlx")] + animate_stickers: 0.into(), contact_sync_enabled: false, convert_emoticons: false, custom_status: None, @@ -103,7 +96,10 @@ impl Default for UserSettings { developer_mode: true, disable_games_tab: true, enable_tts_command: false, + #[cfg(not(feature = "sqlx"))] explicit_content_filter: 0, + #[cfg(feature = "sqlx")] + explicit_content_filter: 0.into(), friend_source_flags: Default::default(), gateway_connected: Some(false), gif_auto_play: false, @@ -127,7 +123,8 @@ impl Default for UserSettings { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow, sqlx::Type))] +#[cfg_attr(feature = "sqlx", sqlx(type_name = "interface_type"))] pub struct CustomStatus { pub emoji_id: Option, pub emoji_name: Option, @@ -137,6 +134,7 @@ pub struct CustomStatus { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow, sqlx::Type))] pub struct FriendSourceFlags { pub all: bool, } @@ -148,8 +146,10 @@ impl Default for FriendSourceFlags { } #[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow, sqlx::Type))] +#[cfg_attr(feature = "sqlx", sqlx(type_name = "interface_type"))] pub struct GuildFolder { - pub color: Option, + pub color: Option, pub guild_ids: Vec, // FIXME: What is this thing? // It's not a snowflake, and it's sometimes a string and sometimes an integer. diff --git a/src/types/entities/webhook.rs b/src/types/entities/webhook.rs index 19f6203f..278ff0d5 100644 --- a/src/types/entities/webhook.rs +++ b/src/types/entities/webhook.rs @@ -71,7 +71,8 @@ impl PartialEq for Webhook { #[derive( Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, )] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] pub enum WebhookType { #[default] diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 0a3d4684..62b3b53a 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -5,7 +5,7 @@ use bitflags::bitflags; use serde::{Deserialize, Serialize}; -use crate::types::{ChannelType, DefaultReaction, entities::PermissionOverwrite, Snowflake}; +use crate::types::{entities::PermissionOverwrite, ChannelType, DefaultReaction, Snowflake}; #[derive(Debug, Deserialize, Serialize, Default, PartialEq, PartialOrd)] #[serde(rename_all = "snake_case")] @@ -141,7 +141,8 @@ bitflags! { #[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] pub enum InviteType { #[default] Guild = 0, @@ -152,7 +153,8 @@ pub enum InviteType { #[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] pub enum InviteTargetType { #[default] Stream = 1, @@ -169,7 +171,9 @@ pub struct AddChannelRecipientSchema { } /// See -#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Copy, Hash)] +#[derive( + Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Copy, Hash, +)] pub struct ModifyChannelPositionsSchema { pub id: Snowflake, pub position: Option, @@ -178,7 +182,9 @@ pub struct ModifyChannelPositionsSchema { } /// See -#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Copy, Hash)] +#[derive( + Debug, Deserialize, Serialize, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Copy, Hash, +)] pub struct AddFollowingChannelSchema { pub webhook_channel_id: Snowflake, } diff --git a/src/types/utils/snowflake.rs b/src/types/utils/snowflake.rs index 7caffc72..296cc85a 100644 --- a/src/types/utils/snowflake.rs +++ b/src/types/utils/snowflake.rs @@ -53,12 +53,9 @@ impl Display for Snowflake { } } -impl From for Snowflake -where - T: Into, -{ - fn from(item: T) -> Self { - Self(item.into()) +impl From for Snowflake { + fn from(item: u64) -> Self { + Self(item) } } @@ -99,28 +96,35 @@ impl<'de> serde::Deserialize<'de> for Snowflake { } #[cfg(feature = "sqlx")] -impl sqlx::Type for Snowflake { - fn type_info() -> ::TypeInfo { - >::type_info() +impl sqlx::Type for Snowflake { + fn type_info() -> ::TypeInfo { + >::type_info() } } #[cfg(feature = "sqlx")] -impl<'q> sqlx::Encode<'q, sqlx::Any> for Snowflake { +impl sqlx::postgres::PgHasArrayType for Snowflake { + fn array_type_info() -> sqlx::postgres::PgTypeInfo { + as sqlx::Type>::type_info() + } +} + +#[cfg(feature = "sqlx")] +impl<'q> sqlx::Encode<'q, sqlx::Postgres> for Snowflake { fn encode_by_ref( &self, - buf: &mut ::ArgumentBuffer<'q>, + buf: &mut ::ArgumentBuffer<'q>, ) -> Result { - >::encode_by_ref(&self.0.to_string(), buf) + >::encode_by_ref(&self.0.to_string(), buf) } } #[cfg(feature = "sqlx")] -impl<'d> sqlx::Decode<'d, sqlx::Any> for Snowflake { +impl<'d> sqlx::Decode<'d, sqlx::Postgres> for Snowflake { fn decode( - value: ::ValueRef<'d>, + value: ::ValueRef<'d>, ) -> Result { - >::decode(value) + >::decode(value) .map(|s| s.parse::().map(Snowflake).unwrap()) } } From cfccae806086ad579fa693b562f641953c0b253f Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 22 Aug 2024 00:23:40 +0200 Subject: [PATCH 117/162] Bump sqlx-pg-uint --- Cargo.lock | 10 ++++++---- Cargo.toml | 4 +--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 21d56119..a15480ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2329,8 +2329,9 @@ dependencies = [ [[package]] name = "sqlx-pg-uint" -version = "0.3.0" -source = "git+https://github.com/bitfl0wer/sqlx-pg-uint#a132f4ad12f6cd1f68cc07e01edd644b4735e346" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af20ea8395f424f24b88912691c5414283d9d8b4a206ad81b86af78c70cc9700" dependencies = [ "bigdecimal", "serde", @@ -2341,8 +2342,9 @@ dependencies = [ [[package]] name = "sqlx-pg-uint-macros" -version = "0.3.0" -source = "git+https://github.com/bitfl0wer/sqlx-pg-uint#a132f4ad12f6cd1f68cc07e01edd644b4735e346" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28fad222fbde71f48f78b38888fe76d0fbc0eeb03015f9cba71dada45acd2abd" dependencies = [ "quote", "syn 2.0.75", diff --git a/Cargo.toml b/Cargo.toml index 6529fbc0..7e6052ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,9 +67,7 @@ rand = "0.8.5" flate2 = { version = "1.0.30", optional = true } webpki-roots = "0.26.3" pubserve = { version = "1.1.0", features = ["async", "send"] } -sqlx-pg-uint = { git = "https://github.com/bitfl0wer/sqlx-pg-uint", features = [ - "serde", -], optional = true } +sqlx-pg-uint = { version = "0.4.1", features = ["serde"], optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] rustls = "0.21.12" From e9b3de23424e1c7d3e7b1c4777e9c1a4024a0d13 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 22 Aug 2024 21:52:29 +0200 Subject: [PATCH 118/162] Uncomment and update decode_token() --- src/types/utils/jwt.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/types/utils/jwt.rs b/src/types/utils/jwt.rs index 0919a5a9..ba6f8872 100644 --- a/src/types/utils/jwt.rs +++ b/src/types/utils/jwt.rs @@ -3,7 +3,10 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use crate::types::utils::Snowflake; -use jsonwebtoken::{encode, EncodingKey, Header}; +use jsonwebtoken::errors::Error; +use jsonwebtoken::{ + decode, encode, Algorithm, DecodingKey, EncodingKey, Header, TokenData, Validation, +}; use serde::{Deserialize, Serialize}; pub fn generate_token(id: &Snowflake, email: String, jwt_key: &str) -> String { @@ -42,8 +45,13 @@ pub fn build_token(claims: &Claims, jwt_key: &str) -> Result Result, Error> { +pub fn decode_token(token: &str, jwt_secret: &str) -> Result, Error> { let mut validation = Validation::new(Algorithm::HS256); - validation.sub = Some("quartzauth".to_string()); - decode(token, &DecodingKey::from_secret(JWT_SECRET), &validation) -}*/ + //TODO: What is this? + //validation.sub = Some("quartzauth".to_string()); + decode( + token, + &DecodingKey::from_secret(jwt_secret.as_bytes()), + &validation, + ) +} From ebea18c99144f43084cbbd931abd244926b81ced Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Sun, 25 Aug 2024 21:27:33 +0200 Subject: [PATCH 119/162] Snowflake: PgU64 as base for sqlx (#551) * Bump sqlx-pg-uint, sqlx * Use PgU64 as base for implementations of sqlx traits for Snowflake --- Cargo.lock | 97 ++++++++++++++++++++++++------------ Cargo.toml | 4 +- src/types/utils/snowflake.rs | 13 +++-- 3 files changed, 76 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a15480ce..244e0e68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -259,7 +259,7 @@ dependencies = [ "rand", "regex", "reqwest", - "rustls", + "rustls 0.21.12", "serde", "serde-aux", "serde_json", @@ -1018,7 +1018,7 @@ dependencies = [ "futures-util", "http 0.2.12", "hyper 0.14.30", - "rustls", + "rustls 0.21.12", "tokio", "tokio-rustls", ] @@ -1175,9 +1175,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libsqlite3-sys" -version = "0.28.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -1767,8 +1767,8 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", @@ -1880,10 +1880,24 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring 0.17.8", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +dependencies = [ + "once_cell", + "ring 0.17.8", + "rustls-pki-types", + "rustls-webpki 0.102.6", + "subtle", + "zeroize", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -1893,6 +1907,16 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.8.0" @@ -1909,6 +1933,17 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustls-webpki" +version = "0.102.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "ryu" version = "1.0.18" @@ -2188,9 +2223,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27144619c6e5802f1380337a209d2ac1c431002dd74c6e60aebff3c506dc4f0c" +checksum = "fcfa89bea9500db4a0d038513d7a060566bfc51d46d1c014847049a45cce85e8" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2201,9 +2236,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a999083c1af5b5d6c071d34a708a19ba3e02106ad82ef7bbd69f5e48266b613b" +checksum = "d06e2f2bd861719b1f3f0c7dbe1d80c30bf59e76cf019f07d9014ed7eefb8e08" dependencies = [ "atoi", "bigdecimal", @@ -2229,8 +2264,8 @@ dependencies = [ "once_cell", "paste", "percent-encoding", - "rustls", - "rustls-pemfile", + "rustls 0.23.12", + "rustls-pemfile 2.1.3", "serde", "serde_json", "sha2", @@ -2241,14 +2276,14 @@ dependencies = [ "tokio-stream", "tracing", "url", - "webpki-roots 0.25.4", + "webpki-roots 0.26.3", ] [[package]] name = "sqlx-macros" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23217eb7d86c584b8cbe0337b9eacf12ab76fe7673c513141ec42565698bb88" +checksum = "2f998a9defdbd48ed005a89362bd40dd2117502f15294f61c8d47034107dbbdc" dependencies = [ "proc-macro2", "quote", @@ -2259,9 +2294,9 @@ dependencies = [ [[package]] name = "sqlx-macros-core" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a099220ae541c5db479c6424bdf1b200987934033c2584f79a0e1693601e776" +checksum = "3d100558134176a2629d46cec0c8891ba0be8910f7896abfdb75ef4ab6f4e7ce" dependencies = [ "dotenvy", "either", @@ -2285,9 +2320,9 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5afe4c38a9b417b6a9a5eeffe7235d0a106716495536e7727d1c7f4b1ff3eba6" +checksum = "936cac0ab331b14cb3921c62156d913e4c15b74fb6ec0f3146bd4ef6e4fb3c12" dependencies = [ "atoi", "base64 0.22.1", @@ -2329,9 +2364,9 @@ dependencies = [ [[package]] name = "sqlx-pg-uint" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af20ea8395f424f24b88912691c5414283d9d8b4a206ad81b86af78c70cc9700" +checksum = "ae1cfe6c40c1cd0053b9029a41729a533ceb32093052df626aa8bfbba45e45f6" dependencies = [ "bigdecimal", "serde", @@ -2342,9 +2377,9 @@ dependencies = [ [[package]] name = "sqlx-pg-uint-macros" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28fad222fbde71f48f78b38888fe76d0fbc0eeb03015f9cba71dada45acd2abd" +checksum = "0ae3447aced07f8bc71d73dc8dd1c6d25c2f4d10ea62a22ceabc12af8410d7e2" dependencies = [ "quote", "syn 2.0.75", @@ -2352,9 +2387,9 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1dbb157e65f10dbe01f729339c06d239120221c9ad9fa0ba8408c4cc18ecf21" +checksum = "9734dbce698c67ecf67c442f768a5e90a49b2a4d61a9f1d59f73874bd4cf0710" dependencies = [ "atoi", "base64 0.22.1", @@ -2394,9 +2429,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2cdd83c008a622d94499c0006d8ee5f821f36c89b7d625c900e5dc30b5c5ee" +checksum = "a75b419c3c1b1697833dd927bdc4c6545a620bc1bbafabd44e1efbe9afcd337e" dependencies = [ "atoi", "chrono", @@ -2609,7 +2644,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", "tokio", ] @@ -2632,7 +2667,7 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls", + "rustls 0.21.12", "tokio", "tokio-rustls", "tungstenite", @@ -2726,7 +2761,7 @@ dependencies = [ "httparse", "log", "rand", - "rustls", + "rustls 0.21.12", "sha1", "thiserror", "url", diff --git a/Cargo.toml b/Cargo.toml index 7e6052ba..cb054765 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ jsonwebtoken = "8.3.0" log = "0.4.22" async-trait = "0.1.81" chorus-macros = { path = "./chorus-macros", version = "0" } # Note: version here is used when releasing. This will use the latest release. Make sure to republish the crate when code in macros is changed! -sqlx = { version = "0.8.0", features = [ +sqlx = { version = "0.8.1", features = [ "json", "chrono", "ipnetwork", @@ -67,7 +67,7 @@ rand = "0.8.5" flate2 = { version = "1.0.30", optional = true } webpki-roots = "0.26.3" pubserve = { version = "1.1.0", features = ["async", "send"] } -sqlx-pg-uint = { version = "0.4.1", features = ["serde"], optional = true } +sqlx-pg-uint = { version = "0.5.0", features = ["serde"], optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] rustls = "0.21.12" diff --git a/src/types/utils/snowflake.rs b/src/types/utils/snowflake.rs index 296cc85a..fe2969d4 100644 --- a/src/types/utils/snowflake.rs +++ b/src/types/utils/snowflake.rs @@ -98,14 +98,14 @@ impl<'de> serde::Deserialize<'de> for Snowflake { #[cfg(feature = "sqlx")] impl sqlx::Type for Snowflake { fn type_info() -> ::TypeInfo { - >::type_info() + >::type_info() } } #[cfg(feature = "sqlx")] impl sqlx::postgres::PgHasArrayType for Snowflake { fn array_type_info() -> sqlx::postgres::PgTypeInfo { - as sqlx::Type>::type_info() + as sqlx::Type>::type_info() } } @@ -115,7 +115,10 @@ impl<'q> sqlx::Encode<'q, sqlx::Postgres> for Snowflake { &self, buf: &mut ::ArgumentBuffer<'q>, ) -> Result { - >::encode_by_ref(&self.0.to_string(), buf) + >::encode_by_ref( + &sqlx_pg_uint::PgU64::from(self.0), + buf, + ) } } @@ -124,8 +127,8 @@ impl<'d> sqlx::Decode<'d, sqlx::Postgres> for Snowflake { fn decode( value: ::ValueRef<'d>, ) -> Result { - >::decode(value) - .map(|s| s.parse::().map(Snowflake).unwrap()) + >::decode(value) + .map(|s| s.to_uint().into()) } } From f0dbd3410f9c55fcf7470ee158d423d1bcd12353 Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Sun, 25 Aug 2024 21:51:12 +0200 Subject: [PATCH 120/162] sqlx_bitflag_derive: Use PgU64 as translation base (#552) * sqlx_bitflag_derive: Use PgU64 as translation base * Bump version of chorus-macros --- Cargo.lock | 2 +- chorus-macros/Cargo.toml | 2 +- chorus-macros/src/lib.rs | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 244e0e68..2ad41745 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -282,7 +282,7 @@ dependencies = [ [[package]] name = "chorus-macros" -version = "0.4.1" +version = "0.5.0" dependencies = [ "async-trait", "quote", diff --git a/chorus-macros/Cargo.toml b/chorus-macros/Cargo.toml index 6aa416a1..4efc3720 100644 --- a/chorus-macros/Cargo.toml +++ b/chorus-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chorus-macros" -version = "0.4.1" +version = "0.5.0" edition = "2021" license = "MPL-2.0" description = "Macros for the chorus crate." diff --git a/chorus-macros/src/lib.rs b/chorus-macros/src/lib.rs index c2a23c5a..d2797e75 100644 --- a/chorus-macros/src/lib.rs +++ b/chorus-macros/src/lib.rs @@ -166,22 +166,21 @@ pub fn sqlx_bitflag_derive(input: TokenStream) -> TokenStream { #[cfg(feature = "sqlx")] impl sqlx::Type for #name { fn type_info() -> sqlx::postgres::PgTypeInfo { - as sqlx::Type>::type_info() + >::type_info() } } #[cfg(feature = "sqlx")] impl<'q> sqlx::Encode<'q, sqlx::Postgres> for #name { fn encode_by_ref(&self, buf: &mut ::ArgumentBuffer<'q>) -> Result { - as sqlx::Encode>::encode_by_ref(&self.bits().to_be_bytes().into(), buf) + >::encode_by_ref(&self.bits().into(), buf) } } #[cfg(feature = "sqlx")] impl<'q> sqlx::Decode<'q, sqlx::Postgres> for #name { fn decode(value: ::ValueRef<'q>) -> Result { - let vec = as sqlx::Decode>::decode(value)?; - Ok(Self::from_bits(vec_u8_to_u64(vec)).unwrap()) + >::decode(value).map(|v| Self::from_bits_truncate(v.to_uint())) } } From 5bee907733de79a1560cb6b84609cdca65b60e99 Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Mon, 26 Aug 2024 12:44:58 +0200 Subject: [PATCH 121/162] Prefer `&str` over `String` when possible (#553) Prefer &str over String where possible. --- examples/gateway_observers.rs | 2 +- examples/gateway_simple.rs | 8 +++++--- src/api/auth/login.rs | 7 +++---- src/api/auth/mod.rs | 5 ++--- src/api/auth/register.rs | 7 +++---- src/api/channels/messages.rs | 6 +++--- src/gateway/gateway.rs | 2 +- src/gateway/options.rs | 4 ++-- src/instance.rs | 12 ++++++------ src/lib.rs | 34 +++++++++++++++++----------------- src/types/utils/jwt.rs | 4 ++-- src/voice/gateway/gateway.rs | 4 ++-- src/voice/gateway/handle.rs | 2 +- tests/auth.rs | 10 +++------- tests/common/mod.rs | 19 +++++++++++-------- tests/gateway.rs | 4 ++-- 16 files changed, 64 insertions(+), 66 deletions(-) diff --git a/examples/gateway_observers.rs b/examples/gateway_observers.rs index a43d17cd..81371796 100644 --- a/examples/gateway_observers.rs +++ b/examples/gateway_observers.rs @@ -52,7 +52,7 @@ impl Subscriber for ExampleObserver { #[tokio::main(flavor = "current_thread")] async fn main() { - let gateway_websocket_url = GATEWAY_URL.to_string(); + let gateway_websocket_url = GATEWAY_URL; // These options specify the encoding format, compression, etc // diff --git a/examples/gateway_simple.rs b/examples/gateway_simple.rs index 7f662874..aa6e0e0f 100644 --- a/examples/gateway_simple.rs +++ b/examples/gateway_simple.rs @@ -25,8 +25,8 @@ use wasmtimer::tokio::sleep; /// This example creates a simple gateway connection and a session with an Identify event #[tokio::main(flavor = "current_thread")] async fn main() { - let gateway_websocket_url = GATEWAY_URL.to_string(); - + let gateway_websocket_url = GATEWAY_URL; + // These options specify the encoding format, compression, etc // // For most cases the defaults should work, though some implementations @@ -34,7 +34,9 @@ async fn main() { let options = GatewayOptions::default(); // Initiate the gateway connection, starting a listener in one thread and a heartbeat handler in another - let gateway = Gateway::spawn(gateway_websocket_url, options).await.unwrap(); + let gateway = Gateway::spawn(gateway_websocket_url, options) + .await + .unwrap(); // At this point, we are connected to the server and are sending heartbeats, however we still haven't authenticated diff --git a/src/api/auth/login.rs b/src/api/auth/login.rs index 7c58e0e7..3a9a9eeb 100644 --- a/src/api/auth/login.rs +++ b/src/api/auth/login.rs @@ -30,13 +30,12 @@ impl Instance { // We do not have a user yet, and the UserRateLimits will not be affected by a login // request (since login is an instance wide limit), which is why we are just cloning the // instances' limits to pass them on as user_rate_limits later. - let mut user = - ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None".to_string()).await; - + let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None").await; + let login_result = chorus_request .deserialize_response::(&mut user) .await?; - user.set_token(login_result.token); + user.set_token(&login_result.token); user.settings = login_result.settings; let object = User::get(&mut user, None).await?; diff --git a/src/api/auth/mod.rs b/src/api/auth/mod.rs index 498080e8..b9050e14 100644 --- a/src/api/auth/mod.rs +++ b/src/api/auth/mod.rs @@ -22,9 +22,8 @@ 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 { - let mut user = - ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await; + pub async fn login_with_token(&mut self, token: &str) -> ChorusResult { + let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await; let object = User::get(&mut user, None).await?; let settings = User::get_settings(&mut user).await?; diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs index 6b94a4d7..821a52ff 100644 --- a/src/api/auth/register.rs +++ b/src/api/auth/register.rs @@ -37,14 +37,13 @@ impl Instance { // We do not have a user yet, and the UserRateLimits will not be affected by a login // request (since register is an instance wide limit), which is why we are just cloning // the instances' limits to pass them on as user_rate_limits later. - let mut user = - ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None".to_string()).await; - + let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None").await; + let token = chorus_request .deserialize_response::(&mut user) .await? .token; - user.set_token(token); + user.set_token(&token); let object = User::get(&mut user, None).await?; let settings = User::get_settings(&mut user).await?; diff --git a/src/api/channels/messages.rs b/src/api/channels/messages.rs index 6387d12c..a682c21c 100644 --- a/src/api/channels/messages.rs +++ b/src/api/channels/messages.rs @@ -112,7 +112,7 @@ impl Message { let result = request.send_request(user).await?; let result_json = result.json::().await.unwrap(); if !result_json.is_object() { - return Err(search_error(result_json.to_string())); + return Err(search_error(result_json.to_string().as_str())); } let value_map = result_json.as_object().unwrap(); if let Some(messages) = value_map.get("messages") { @@ -123,7 +123,7 @@ impl Message { } // The code below might be incorrect. We'll cross that bridge when we come to it if !value_map.contains_key("code") || !value_map.contains_key("retry_after") { - return Err(search_error(result_json.to_string())); + return Err(search_error(result_json.to_string().as_str())); } let code = value_map.get("code").unwrap().as_u64().unwrap(); let retry_after = value_map.get("retry_after").unwrap().as_u64().unwrap(); @@ -482,7 +482,7 @@ impl Message { } } -fn search_error(result_text: String) -> ChorusError { +fn search_error(result_text: &str) -> ChorusError { ChorusError::InvalidResponse { error: format!( "Got unexpected Response, or Response which is not valid JSON. Response: \n{}", diff --git a/src/gateway/gateway.rs b/src/gateway/gateway.rs index f1fc03cc..976769d2 100644 --- a/src/gateway/gateway.rs +++ b/src/gateway/gateway.rs @@ -48,7 +48,7 @@ impl Gateway { /// # Note /// The websocket url should begin with the prefix wss:// or ws:// (for unsecure connections) pub async fn spawn( - websocket_url: String, + websocket_url: &str, options: GatewayOptions, ) -> Result { let url = options.add_to_url(websocket_url); diff --git a/src/gateway/options.rs b/src/gateway/options.rs index 23942b23..4ff6178b 100644 --- a/src/gateway/options.rs +++ b/src/gateway/options.rs @@ -25,8 +25,8 @@ impl GatewayOptions { /// Adds the options to an existing gateway url /// /// Returns the new url - pub(crate) fn add_to_url(&self, url: String) -> String { - let mut url = url; + pub(crate) fn add_to_url(&self, url: &str) -> String { + let mut url = url.to_string(); let mut parameters = Vec::with_capacity(2); diff --git a/src/instance.rs b/src/instance.rs index f826ab58..455b3eff 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -110,7 +110,7 @@ impl Instance { } pub async fn is_limited(api_url: &str) -> ChorusResult> { - let api_url = UrlBundle::parse_url(api_url.to_string()); + let api_url = UrlBundle::parse_url(api_url); let client = Client::new(); let request = client .get(format!("{}/policies/instance/limits", &api_url)) @@ -163,8 +163,8 @@ impl ChorusUser { self.token.clone() } - pub fn set_token(&mut self, token: String) { - self.token = token; + pub fn set_token(&mut self, token: &str) { + self.token = token.to_string(); } /// Creates a new [ChorusUser] from existing data. @@ -195,16 +195,16 @@ impl ChorusUser { /// registering or logging in to the Instance, where you do not yet have a User object, but still /// need to make a RateLimited request. To use the [`GatewayHandle`], you will have to identify /// first. - pub(crate) async fn shell(instance: Shared, token: String) -> ChorusUser { + pub(crate) async fn shell(instance: Shared, token: &str) -> ChorusUser { let settings = Arc::new(RwLock::new(UserSettings::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 let gateway = Gateway::spawn(wss_url, GatewayOptions::default()) .await .unwrap(); ChorusUser { - token, + token: token.to_string(), belongs_to: instance.clone(), limits: instance .read() diff --git a/src/lib.rs b/src/lib.rs index b16f12ba..5744e1d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -186,7 +186,7 @@ pub struct UrlBundle { impl UrlBundle { /// Creates a new UrlBundle from the relevant urls. - pub fn new(root: String, api: String, wss: String, cdn: String) -> Self { + pub fn new(root: &str, api: &str, wss: &str, cdn: &str) -> Self { Self { root: UrlBundle::parse_url(root), api: UrlBundle::parse_url(api), @@ -203,17 +203,17 @@ impl UrlBundle { /// let url = parse_url("localhost:3000"); /// ``` /// `-> Outputs "http://localhost:3000".` - pub fn parse_url(url: String) -> String { - let url = match Url::parse(&url) { + pub fn parse_url(url: &str) -> String { + let url = match Url::parse(url) { Ok(url) => { if url.scheme() == "localhost" { - return UrlBundle::parse_url(format!("http://{}", url)); + return UrlBundle::parse_url(&format!("http://{}", url)); } url } Err(ParseError::RelativeUrlWithoutBase) => { let url_fmt = format!("http://{}", url); - return UrlBundle::parse_url(url_fmt); + return UrlBundle::parse_url(&url_fmt); } Err(_) => panic!("Invalid URL"), // TODO: should not panic here }; @@ -236,7 +236,7 @@ impl UrlBundle { /// of the above approaches fail, it is very likely that the instance is misconfigured, unreachable, or that /// a wrong URL was provided. pub async fn from_root_url(url: &str) -> ChorusResult { - let parsed = UrlBundle::parse_url(url.to_string()); + let parsed = UrlBundle::parse_url(url); let client = reqwest::Client::new(); let request_wellknown = client .get(format!("{}/.well-known/spacebar", &parsed)) @@ -274,10 +274,10 @@ impl UrlBundle { .await { Ok(UrlBundle::new( - url.to_string(), - body.api_endpoint, - body.gateway, - body.cdn, + url, + &body.api_endpoint, + &body.gateway, + &body.cdn, )) } else { Err(ChorusError::RequestFailed { @@ -294,13 +294,13 @@ mod lib { #[test] fn test_parse_url() { - let mut result = UrlBundle::parse_url(String::from("localhost:3000/")); - assert_eq!(result, String::from("http://localhost:3000")); - result = UrlBundle::parse_url(String::from("https://some.url.com/")); - assert_eq!(result, String::from("https://some.url.com")); - result = UrlBundle::parse_url(String::from("https://some.url.com/")); - assert_eq!(result, String::from("https://some.url.com")); - result = UrlBundle::parse_url(String::from("https://some.url.com")); + let mut result = UrlBundle::parse_url("localhost:3000/"); + assert_eq!(result, "http://localhost:3000"); + result = UrlBundle::parse_url("https://some.url.com/"); assert_eq!(result, String::from("https://some.url.com")); + result = UrlBundle::parse_url("https://some.url.com/"); + assert_eq!(result, "https://some.url.com"); + result = UrlBundle::parse_url("https://some.url.com"); + assert_eq!(result, "https://some.url.com"); } } diff --git a/src/types/utils/jwt.rs b/src/types/utils/jwt.rs index ba6f8872..09397234 100644 --- a/src/types/utils/jwt.rs +++ b/src/types/utils/jwt.rs @@ -9,8 +9,8 @@ use jsonwebtoken::{ }; use serde::{Deserialize, Serialize}; -pub fn generate_token(id: &Snowflake, email: String, jwt_key: &str) -> String { - let claims = Claims::new(&email, id); +pub fn generate_token(id: &Snowflake, email: &str, jwt_key: &str) -> String { + let claims = Claims::new(email, id); build_token(&claims, jwt_key).unwrap() } diff --git a/src/voice/gateway/gateway.rs b/src/voice/gateway/gateway.rs index ba4df806..1b5981cb 100644 --- a/src/voice/gateway/gateway.rs +++ b/src/voice/gateway/gateway.rs @@ -41,7 +41,7 @@ pub struct VoiceGateway { impl VoiceGateway { #[allow(clippy::new_ret_no_self)] - pub async fn spawn(websocket_url: String) -> Result { + pub async fn spawn(websocket_url: &str) -> Result { // Append the needed things to the websocket url let processed_url = format!("wss://{}/?v=7", websocket_url); trace!("VGW: Connecting to {}", processed_url.clone()); @@ -110,7 +110,7 @@ impl VoiceGateway { }); Ok(VoiceGatewayHandle { - url: websocket_url.clone(), + url: websocket_url.to_string(), events: shared_events, websocket_send: shared_websocket_send.clone(), kill_send: kill_send.clone(), diff --git a/src/voice/gateway/handle.rs b/src/voice/gateway/handle.rs index 8750f12f..b265b71e 100644 --- a/src/voice/gateway/handle.rs +++ b/src/voice/gateway/handle.rs @@ -72,7 +72,7 @@ impl VoiceGatewayHandle { /// Sends a speaking event to the gateway pub async fn send_speaking(&self, to_send: Speaking) { - let to_send_value = serde_json::to_value(&to_send).unwrap(); + let to_send_value = serde_json::to_value(to_send).unwrap(); trace!("VGW: Sending Speaking"); diff --git a/tests/auth.rs b/tests/auth.rs index 705328ae..9f0cbfdb 100644 --- a/tests/auth.rs +++ b/tests/auth.rs @@ -79,11 +79,7 @@ async fn test_login_with_token() { let mut bundle = common::setup().await; let token = &bundle.user.token; - let other_user = bundle - .instance - .login_with_token(token.clone()) - .await - .unwrap(); + let other_user = bundle.instance.login_with_token(token).await.unwrap(); assert_eq!( bundle.user.object.read().unwrap().id, other_user.object.read().unwrap().id @@ -98,8 +94,8 @@ async fn test_login_with_token() { async fn test_login_with_invalid_token() { let mut bundle = common::setup().await; - let token = "invalid token lalalalala".to_string(); - let other_user = bundle.instance.login_with_token(token.clone()).await; + let token = "invalid token lalalalala"; + let other_user = bundle.instance.login_with_token(token).await; assert!(other_user.is_err()); diff --git a/tests/common/mod.rs b/tests/common/mod.rs index f2f0663e..94c51ed2 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -10,7 +10,7 @@ use chorus::{ instance::{ChorusUser, Instance}, types::{ Channel, ChannelCreateSchema, Guild, GuildCreateSchema, RegisterSchema, - RoleCreateModifySchema, RoleObject, Shared + RoleCreateModifySchema, RoleObject, Shared, }, UrlBundle, }; @@ -50,7 +50,7 @@ impl TestBundle { limits: self.user.limits.clone(), settings: self.user.settings.clone(), object: self.user.object.clone(), - gateway: Gateway::spawn(self.instance.urls.wss.clone(), GatewayOptions::default()) + gateway: Gateway::spawn(&self.instance.urls.wss, GatewayOptions::default()) .await .unwrap(), } @@ -59,9 +59,12 @@ impl TestBundle { // Set up a test by creating an Instance and a User. Reduces Test boilerplate. pub(crate) async fn setup() -> TestBundle { - // So we can get logs when tests fail - let _ = simple_logger::SimpleLogger::with_level(simple_logger::SimpleLogger::new(), log::LevelFilter::Debug).init(); + let _ = simple_logger::SimpleLogger::with_level( + simple_logger::SimpleLogger::new(), + log::LevelFilter::Debug, + ) + .init(); let instance = Instance::new("http://localhost:3001/api").await.unwrap(); // Requires the existence of the below user. @@ -121,10 +124,10 @@ pub(crate) async fn setup() -> TestBundle { .unwrap(); let urls = UrlBundle::new( - "http://localhost:3001/api".to_string(), - "http://localhost:3001/api".to_string(), - "ws://localhost:3001/".to_string(), - "http://localhost:3001".to_string(), + "http://localhost:3001/api", + "http://localhost:3001/api", + "ws://localhost:3001/", + "http://localhost:3001", ); TestBundle { urls, diff --git a/tests/gateway.rs b/tests/gateway.rs index 1c8f56a8..ccd96eff 100644 --- a/tests/gateway.rs +++ b/tests/gateway.rs @@ -31,7 +31,7 @@ use wasmtimer::tokio::sleep; async fn test_gateway_establish() { let bundle = common::setup().await; - let _: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone(), GatewayOptions::default()) + let _: GatewayHandle = Gateway::spawn(&bundle.urls.wss, GatewayOptions::default()) .await .unwrap(); common::teardown(bundle).await @@ -55,7 +55,7 @@ impl Subscriber for GatewayReadyObserver { async fn test_gateway_authenticate() { let bundle = common::setup().await; - let gateway: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone(), GatewayOptions::default()) + let gateway: GatewayHandle = Gateway::spawn(&bundle.urls.wss, GatewayOptions::default()) .await .unwrap(); From 9926f8ab94a322a5ab1cfd73ebac965b363f13c9 Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Mon, 26 Aug 2024 13:32:37 +0200 Subject: [PATCH 122/162] Tungstenite: Match scheme for "ws" or "wss" (#554) Match scheme for "ws" or "wss" and choose whether to connect with TLS connector for tungstenite --- src/gateway/backends/tungstenite.rs | 88 ++++++++++++++++++----------- 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/src/gateway/backends/tungstenite.rs b/src/gateway/backends/tungstenite.rs index 34dc8255..4464f8dd 100644 --- a/src/gateway/backends/tungstenite.rs +++ b/src/gateway/backends/tungstenite.rs @@ -9,8 +9,10 @@ use futures_util::{ }; use tokio::net::TcpStream; use tokio_tungstenite::{ - connect_async_tls_with_config, tungstenite, Connector, MaybeTlsStream, WebSocketStream, + connect_async_tls_with_config, connect_async_with_config, tungstenite, Connector, + MaybeTlsStream, WebSocketStream, }; +use url::Url; use crate::gateway::{GatewayMessage, RawGatewayMessage}; @@ -32,38 +34,60 @@ impl TungsteniteBackend { pub async fn connect( websocket_url: &str, ) -> Result<(TungsteniteSink, TungsteniteStream), TungsteniteBackendError> { - let certs = webpki_roots::TLS_SERVER_ROOTS; - let roots = rustls::RootCertStore { - roots: certs - .iter() - .map(|cert| { - rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( - cert.subject.to_vec(), - cert.subject_public_key_info.to_vec(), - cert.name_constraints.as_ref().map(|der| der.to_vec()), - ) - }) - .collect(), - }; - let (websocket_stream, _) = match connect_async_tls_with_config( - websocket_url, - None, - false, - Some(Connector::Rustls( - rustls::ClientConfig::builder() - .with_safe_defaults() - .with_root_certificates(roots) - .with_no_client_auth() - .into(), - )), - ) - .await - { - Ok(websocket_stream) => websocket_stream, - Err(e) => return Err(TungsteniteBackendError::TungsteniteError { error: e }), - }; + let websocket_url_parsed = + Url::parse(websocket_url).map_err(|_| TungsteniteBackendError::TungsteniteError { + error: tungstenite::error::Error::Url( + tungstenite::error::UrlError::UnsupportedUrlScheme, + ), + })?; + if websocket_url_parsed.scheme() == "ws" { + let (websocket_stream, _) = + match connect_async_with_config(websocket_url, None, false).await { + Ok(websocket_stream) => websocket_stream, + Err(e) => return Err(TungsteniteBackendError::TungsteniteError { error: e }), + }; - Ok(websocket_stream.split()) + Ok(websocket_stream.split()) + } else if websocket_url_parsed.scheme() == "wss" { + let certs = webpki_roots::TLS_SERVER_ROOTS; + let roots = rustls::RootCertStore { + roots: certs + .iter() + .map(|cert| { + rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( + cert.subject.to_vec(), + cert.subject_public_key_info.to_vec(), + cert.name_constraints.as_ref().map(|der| der.to_vec()), + ) + }) + .collect(), + }; + let (websocket_stream, _) = match connect_async_tls_with_config( + websocket_url, + None, + false, + Some(Connector::Rustls( + rustls::ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(roots) + .with_no_client_auth() + .into(), + )), + ) + .await + { + Ok(websocket_stream) => websocket_stream, + Err(e) => return Err(TungsteniteBackendError::TungsteniteError { error: e }), + }; + + Ok(websocket_stream.split()) + } else { + Err(TungsteniteBackendError::TungsteniteError { + error: tungstenite::error::Error::Url( + tungstenite::error::UrlError::UnsupportedUrlScheme, + ), + }) + } } } From 05b9f1c80184fd1622530e38422f3d3b579b44a5 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 26 Aug 2024 13:38:33 +0200 Subject: [PATCH 123/162] Add missing `impl From for u64`, closes `From for u64` missing #550 --- src/types/utils/snowflake.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/types/utils/snowflake.rs b/src/types/utils/snowflake.rs index fe2969d4..27e44dc8 100644 --- a/src/types/utils/snowflake.rs +++ b/src/types/utils/snowflake.rs @@ -59,6 +59,12 @@ impl From for Snowflake { } } +impl From for u64 { + fn from(item: Snowflake) -> Self { + item.0 + } +} + impl serde::Serialize for Snowflake { fn serialize(&self, serializer: S) -> Result where From 72c5d13eaf009a0e51b329f691a06996edec364d Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 26 Aug 2024 13:56:11 +0200 Subject: [PATCH 124/162] Update README.md --- README.md | 128 +++++++++++------------------------------------------ src/lib.rs | 54 +++++++++++++++------- 2 files changed, 66 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index 413ec34d..e6a5155a 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,15 @@ -Chorus is a Rust library which poses as an API wrapper for [Spacebar Chat](https://github.com/spacebarchat/) -and Discord. It is designed to be easy to use, and to be compatible with both Discord and Spacebar Chat. +Chorus is a Rust library which poses as an API wrapper for [Spacebar Chat](https://github.com/spacebarchat/), +Discord and our own Polyphony. Its high-level API is designed to be easy to use, while still providing the +flexibility one would expect from a library like this. You can establish as many connections to as many servers as you want, and you can use them all at the same time. ## A Tour of Chorus -Chorus combines all the required functionalities of a user-centric Spacebar library into one package. +Chorus combines all the required functionalities of an API wrapper for chat services into one modular library. The library handles various aspects on your behalf, such as rate limiting, authentication and maintaining a WebSocket connection to the Gateway. This means that you can focus on building your application, instead of worrying about the underlying implementation details. @@ -44,12 +45,12 @@ To get started with Chorus, import it into your project by adding the following ```toml [dependencies] -chorus = "0.15.0" +chorus = "0.16.0" ``` ### Establishing a Connection -To connect to a Spacebar compatible server, you need to create an [`Instance`](https://docs.rs/chorus/latest/chorus/instance/struct.Instance.html) like this: +To connect to a Polyphony/Spacebar compatible server, you'll need to create an [`Instance`](https://docs.rs/chorus/latest/chorus/instance/struct.Instance.html) like this: ```rs use chorus::instance::Instance; @@ -81,7 +82,7 @@ let login_schema = LoginSchema { password: "Correct-Horse-Battery-Staple".to_string(), ..Default::default() }; -// Each user connects to the Gateway. The Gateway connection lives on a separate thread. Depending on +// Each user connects to the Gateway. Each users' Gateway connection lives on a separate thread. Depending on // the runtime feature you choose, this can potentially take advantage of all of your computers' threads. let user = instance .login_account(login_schema) @@ -148,98 +149,23 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read See [CONTRIBUTING.md](./CONTRIBUTING.md). -
- Progress Tracker/Roadmap - - ### Core Functionality - - [x] Rate Limiter (hint: couldn't be fully tested due to [an Issue with the Spacebar Server](https://github.com/spacebarchat/server/issues/1022)) - - [x] [Login (the conventional way)](https://github.com/polyphony-chat/chorus/issues/1) - - [ ] [2FA](https://github.com/polyphony-chat/chorus/issues/40) - - [x] [Registration](https://github.com/polyphony-chat/chorus/issues/1) - - ### Messaging - - [x] [Sending messages](https://github.com/polyphony-chat/chorus/issues/23) - - [x] [Events (Message, User, Channel, etc.)](https://github.com/polyphony-chat/chorus/issues/51) - - [x] Channel creation - - [x] Channel deletion - - [x] [Channel management (name, description, icon, etc.)](https://github.com/polyphony-chat/chorus/issues/48) - - [x] [Join and Leave Guilds](https://github.com/polyphony-chat/chorus/issues/45) - - [x] [Start DMs](https://github.com/polyphony-chat/chorus/issues/45) - - [x] [Group DM creation, deletion and member management](https://github.com/polyphony-chat/chorus/issues/89) - - [ ] [Deleting messages](https://github.com/polyphony-chat/chorus/issues/91) - - [ ] [Message threads](https://github.com/polyphony-chat/chorus/issues/90) - - [x] [Reactions](https://github.com/polyphony-chat/chorus/issues/85) - - [ ] Message Search - - [ ] Message history - - [ ] Emoji - - [ ] Stickers - - [ ] [Forum channels](https://github.com/polyphony-chat/chorus/issues/90) - - ### User Management - - [ ] [User profile customization](https://github.com/polyphony-chat/chorus/issues/41) - - [x] Gettings users and user profiles - - [x] [Friend requests](https://github.com/polyphony-chat/chorus/issues/92) - - [x] [Blocking users](https://github.com/polyphony-chat/chorus/issues/92) - - [ ] User presence (online, offline, idle, etc.) - - [ ] User status (custom status, etc.) - - [x] Account deletion - - ### Additional Features - - [ ] Server discovery - - [ ] Server templates - - ### Voice and Video - - [ ] [Voice chat support](https://github.com/polyphony-chat/chorus/issues/49) - - [ ] [Video chat support](https://github.com/polyphony-chat/chorus/issues/49) - - ### Permissions and Roles - - [x] [Role management](https://github.com/polyphony-chat/chorus/issues/46) (creation, deletion, modification) - - [x] [Permission management](https://github.com/polyphony-chat/chorus/issues/46) (assigning and revoking permissions) - - [x] [Channel-specific permissions](https://github.com/polyphony-chat/chorus/issues/88) - - [x] Role-based access control - - ### Guild Management - - [x] Guild creation - - [x] Guild deletion - - [ ] [Guild settings (name, description, icon, etc.)](https://github.com/polyphony-chat/chorus/issues/43) - - [ ] Guild invites - - ### Moderation - - [ ] Channel moderation (slow mode, etc.) - - [ ] User sanctions (mute, kick, ban) - - [ ] Audit logs - - ### Embeds and Rich Content - - [x] Sending rich content in messages (links, images, videos) - - [ ] Customizing embed appearance (title, description, color, fields) - - ### Webhooks - - [ ] Webhook creation and management - - [ ] Handling incoming webhook events - - ### Documentation and Examples - - [ ] Comprehensive documentation - - [ ] Example usage and code snippets - - [ ] Tutorials and guides - - [Rust]: https://img.shields.io/badge/Rust-orange?style=plastic&logo=rust - [Rust-url]: https://www.rust-lang.org/ - [build-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/build_and_test.yml?style=flat - [build-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/build_and_test.yml - [clippy-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/clippy.yml?style=flat - [clippy-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/clippy.yml - [contributors-shield]: https://img.shields.io/github/contributors/polyphony-chat/chorus.svg?style=flat - [contributors-url]: https://github.com/polyphony-chat/chorus/graphs/contributors - [coverage-shield]: https://coveralls.io/repos/github/polyphony-chat/chorus/badge.svg?branch=main - [coverage-url]: https://coveralls.io/github/polyphony-chat/chorus?branch=main - [forks-shield]: https://img.shields.io/github/forks/polyphony-chat/chorus.svg?style=flat - [forks-url]: https://github.com/polyphony-chat/chorus/network/members - [stars-shield]: https://img.shields.io/github/stars/polyphony-chat/chorus.svg?style=flat - [stars-url]: https://github.com/polyphony-chat/chorus/stargazers - [issues-shield]: https://img.shields.io/github/issues/polyphony-chat/chorus.svg?style=flat - [issues-url]: https://github.com/polyphony-chat/chorus/issues - [license-shield]: https://img.shields.io/github/license/polyphony-chat/chorus.svg?style=f;at - [license-url]: https://github.com/polyphony-chat/chorus/blob/master/LICENSE - [Discord]: https://dcbadge.vercel.app/api/server/m3FpcapGDD?style=flat - [Discord-invite]: https://discord.com/invite/m3FpcapGDD -
+[Rust]: https://img.shields.io/badge/Rust-orange?style=plastic&logo=rust +[Rust-url]: https://www.rust-lang.org/ +[build-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/build_and_test.yml?style=flat +[build-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/build_and_test.yml +[clippy-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/clippy.yml?style=flat +[clippy-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/clippy.yml +[contributors-shield]: https://img.shields.io/github/contributors/polyphony-chat/chorus.svg?style=flat +[contributors-url]: https://github.com/polyphony-chat/chorus/graphs/contributors +[coverage-shield]: https://coveralls.io/repos/github/polyphony-chat/chorus/badge.svg?branch=main +[coverage-url]: https://coveralls.io/github/polyphony-chat/chorus?branch=main +[forks-shield]: https://img.shields.io/github/forks/polyphony-chat/chorus.svg?style=flat +[forks-url]: https://github.com/polyphony-chat/chorus/network/members +[stars-shield]: https://img.shields.io/github/stars/polyphony-chat/chorus.svg?style=flat +[stars-url]: https://github.com/polyphony-chat/chorus/stargazers +[issues-shield]: https://img.shields.io/github/issues/polyphony-chat/chorus.svg?style=flat +[issues-url]: https://github.com/polyphony-chat/chorus/issues +[license-shield]: https://img.shields.io/github/license/polyphony-chat/chorus.svg?style=f;at +[license-url]: https://github.com/polyphony-chat/chorus/blob/master/LICENSE +[Discord]: https://dcbadge.vercel.app/api/server/m3FpcapGDD?style=flat +[Discord-invite]: https://discord.com/invite/m3FpcapGDD diff --git a/src/lib.rs b/src/lib.rs index 5744e1d8..c4aa3aca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,27 +3,29 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. /*! -Chorus combines all the required functionalities of a user-centric Spacebar library into one package. +Chorus is a Rust library which poses as an API wrapper for [Spacebar Chat](https://github.com/spacebarchat/), +Discord and our own Polyphony. Its high-level API is designed to be easy to use, while still providing the +flexibility one would expect from a library like this. + +You can establish as many connections to as many servers as you want, and you can use them all at the same time. + +## A Tour of Chorus + +Chorus combines all the required functionalities of an API wrapper for chat services into one modular library. The library handles various aspects on your behalf, such as rate limiting, authentication and maintaining a WebSocket connection to the Gateway. This means that you can focus on building your application, instead of worrying about the underlying implementation details. ### Establishing a Connection -To connect to a Spacebar compatible server, you need to create an [`Instance`](https://docs.rs/chorus/latest/chorus/instance/struct.Instance.html) like this: +To connect to a Polyphony/Spacebar compatible server, you'll need to create an [`Instance`](https://docs.rs/chorus/latest/chorus/instance/struct.Instance.html) like this: ```rs use chorus::instance::Instance; -use chorus::UrlBundle; #[tokio::main] async fn main() { - let bundle = UrlBundle::new( - "https://example.com/api".to_string(), - "wss://example.com/".to_string(), - "https://example.com/cdn".to_string(), - ); - let instance = Instance::new(bundle) + let instance = Instance::new("https://example.com") .await .expect("Failed to connect to the Spacebar server"); // You can create as many instances of `Instance` as you want, but each `Instance` should likely be unique. @@ -36,7 +38,7 @@ This Instance can now be used to log in, register and from there on, interact wi ### Logging In -Logging in correctly provides you with an instance of [`ChorusUser`](https://docs.rs/chorus/latest/chorus/instance/struct.ChorusUser.html), with which you can interact with the server and +Logging in correctly provides you with an instance of `ChorusUser`, with which you can interact with the server and manipulate the account. Assuming you already have an account on the server, you can log in like this: ```rs @@ -48,7 +50,7 @@ let login_schema = LoginSchema { password: "Correct-Horse-Battery-Staple".to_string(), ..Default::default() }; -// Each user connects to the Gateway. The Gateway connection lives on a separate thread. Depending on +// Each user connects to the Gateway. Each users' Gateway connection lives on a separate thread. Depending on // the runtime feature you choose, this can potentially take advantage of all of your computers' threads. let user = instance .login_account(login_schema) @@ -64,15 +66,33 @@ All major desktop operating systems (Windows, macOS (aarch64/x86_64), Linux (aar `wasm32-unknown-unknown` is a supported compilation target on versions `0.12.0` and up. This allows you to use Chorus in your browser, or in any other environment that supports WebAssembly. -We recommend checking out the examples directory, as well as the documentation for more information. +To compile for `wasm32-unknown-unknown`, execute the following command: + +```sh +cargo build --target=wasm32-unknown-unknown --no-default-features +``` + +The following features are supported on `wasm32-unknown-unknown`: + +| Feature | WASM Support | +| ----------------- | ------------ | +| `client` | ✅ | +| `rt` | ✅ | +| `rt-multi-thread` | ❌ | +| `backend` | ❌ | +| `voice` | ❌ | +| `voice_udp` | ❌ | +| `voice_gateway` | ✅ | + +We recommend checking out the "examples" directory, as well as the documentation for more information. ## MSRV (Minimum Supported Rust Version) -Rust **1.67.1**. This number might change at any point while Chorus is not yet at version 1.0.0. +Rust **1.70.0**. This number might change at any point while Chorus is not yet at version 1.0.0. ## Development Setup -Make sure that you have at least Rust 1.67.1 installed. You can check your Rust version by running `cargo --version` +Make sure that you have at least Rust 1.70.0 installed. You can check your Rust version by running `cargo --version` in your terminal. To compile for `wasm32-unknown-unknown`, you need to install the `wasm32-unknown-unknown` target. You can do this by running `rustup target add wasm32-unknown-unknown`. @@ -86,12 +106,16 @@ like "proxy connection checking" are already disabled on this version, which oth ### wasm To test for wasm, you will need to `cargo install wasm-pack`. You can then run -`wasm-pack test -- --headless -- --target wasm32-unknown-unknown --features="rt, client" --no-default-features` +`wasm-pack test -- --headless -- --target wasm32-unknown-unknown --features="rt, client, voice_gateway" --no-default-features` to run the tests for wasm. ## Versioning This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read the specification [here](https://semver.org/spec/v2.0.0.html). + +## Contributing + +See [CONTRIBUTING.md](./CONTRIBUTING.md). !*/ #![doc( html_logo_url = "https://raw.githubusercontent.com/polyphony-chat/design/main/branding/polyphony-chorus-round-8bit.png" From e316372631f959b40630061d279ee4f1cb3f7a32 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 26 Aug 2024 13:56:28 +0200 Subject: [PATCH 125/162] Bump package versions --- Cargo.lock | 70 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 10 ++++---- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2ad41745..e2fb0d2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,7 +83,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] @@ -215,9 +215,9 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.13" +version = "1.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932" dependencies = [ "shlex", ] @@ -286,7 +286,7 @@ version = "0.5.0" dependencies = [ "async-trait", "quote", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] @@ -457,7 +457,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] @@ -468,7 +468,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] @@ -584,15 +584,15 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "flate2" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c0596c1eac1f9e04ed902702e9878208b336edc9d6fddc8a48387349bab3666" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", "miniz_oxide 0.8.0", @@ -691,7 +691,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] @@ -1601,7 +1601,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] @@ -1659,9 +1659,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -2004,9 +2004,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.208" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] @@ -2024,20 +2024,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" dependencies = [ "itoa", "memchr", @@ -2053,7 +2053,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] @@ -2095,7 +2095,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] @@ -2289,7 +2289,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] @@ -2312,7 +2312,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.75", + "syn 2.0.76", "tempfile", "tokio", "url", @@ -2382,7 +2382,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ae3447aced07f8bc71d73dc8dd1c6d25c2f4d10ea62a22ceabc12af8410d7e2" dependencies = [ "quote", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] @@ -2487,9 +2487,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.75" +version = "2.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" dependencies = [ "proc-macro2", "quote", @@ -2562,7 +2562,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] @@ -2635,7 +2635,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] @@ -2730,7 +2730,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] @@ -2929,7 +2929,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.76", "wasm-bindgen-shared", ] @@ -2963,7 +2963,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.76", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2997,7 +2997,7 @@ checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] @@ -3299,7 +3299,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.76", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index cb054765..f9a70474 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,9 @@ voice_gateway = [] sqlx-pg-uint = ["dep:sqlx-pg-uint", "sqlx-pg-uint/serde"] [dependencies] -tokio = { version = "1.38.1", features = ["macros", "sync"] } -serde = { version = "1.0.208", features = ["derive", "rc"] } -serde_json = { version = "1.0.120", features = ["raw_value"] } +tokio = { version = "1.39.3", features = ["macros", "sync"] } +serde = { version = "1.0.209", features = ["derive", "rc"] } +serde_json = { version = "1.0.127", features = ["raw_value"] } serde-aux = "4.5.0" serde_with = "3.9.0" serde_repr = "0.1.19" @@ -36,7 +36,7 @@ reqwest = { features = [ ], version = "=0.11.26", default-features = false } url = "2.5.2" chrono = { version = "0.4.38", features = ["serde"] } -regex = "1.10.5" +regex = "1.10.6" custom_error = "1.9.2" futures-util = "0.3.30" http = "0.2.12" @@ -64,7 +64,7 @@ discortp = { version = "0.5.0", optional = true, features = [ ] } crypto_secretbox = { version = "0.1.1", optional = true } rand = "0.8.5" -flate2 = { version = "1.0.30", optional = true } +flate2 = { version = "1.0.33", optional = true } webpki-roots = "0.26.3" pubserve = { version = "1.1.0", features = ["async", "send"] } sqlx-pg-uint = { version = "0.5.0", features = ["serde"], optional = true } From d846ce9948ebb07988428250d6a02d2ea920a451 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 26 Aug 2024 18:19:02 +0200 Subject: [PATCH 126/162] move up sending identify --- src/api/auth/register.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs index 821a52ff..1c25e606 100644 --- a/src/api/auth/register.rs +++ b/src/api/auth/register.rs @@ -45,16 +45,16 @@ impl Instance { .token; user.set_token(&token); + let mut identify = GatewayIdentifyPayload::common(); + identify.token = user.token(); + user.gateway.send_identify(identify).await; + let object = User::get(&mut user, None).await?; let settings = User::get_settings(&mut user).await?; *user.object.write().unwrap() = object; *user.settings.write().unwrap() = settings; - let mut identify = GatewayIdentifyPayload::common(); - identify.token = user.token(); - user.gateway.send_identify(identify).await; - Ok(user) } } From 76186a08f0be668c3aec36c0382d054c7d5f4486 Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Mon, 26 Aug 2024 19:36:42 +0200 Subject: [PATCH 127/162] Make instance GatewayOptions configurable for library consumers (#555) * Make instance GatewayOptions configurable for library consumers * Update example in README --- README.md | 2 +- examples/instance.rs | 2 +- examples/login.rs | 2 +- src/instance.rs | 20 +++++++++++++------- tests/common/mod.rs | 4 +++- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e6a5155a..afed9b2c 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ use chorus::instance::Instance; #[tokio::main] async fn main() { - let instance = Instance::new("https://example.com") + let instance = Instance::new("https://example.com", None) .await .expect("Failed to connect to the Spacebar server"); // You can create as many instances of `Instance` as you want, but each `Instance` should likely be unique. diff --git a/examples/instance.rs b/examples/instance.rs index 0bbdc17c..5f685f9f 100644 --- a/examples/instance.rs +++ b/examples/instance.rs @@ -6,7 +6,7 @@ use chorus::instance::Instance; #[tokio::main(flavor = "current_thread")] async fn main() { - let instance = Instance::new("https://example.com/") + let instance = Instance::new("https://example.com/", None) .await .expect("Failed to connect to the Spacebar server"); dbg!(instance.instance_info); diff --git a/examples/login.rs b/examples/login.rs index e89d8d20..f9ebcf09 100644 --- a/examples/login.rs +++ b/examples/login.rs @@ -7,7 +7,7 @@ use chorus::types::LoginSchema; #[tokio::main(flavor = "current_thread")] async fn main() { - let mut instance = Instance::new("https://example.com/") + let mut instance = Instance::new("https://example.com/", None) .await .expect("Failed to connect to the Spacebar server"); // Assume, you already have an account created on this instance. Registering an account works diff --git a/src/instance.rs b/src/instance.rs index 455b3eff..a8671e0a 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -69,8 +69,13 @@ impl Instance { /// Creates a new [`Instance`] from the [relevant instance urls](UrlBundle). /// + /// If `options` is `None`, the default [`GatewayOptions`] will be used. + /// /// To create an Instance from one singular url, use [`Instance::new()`]. - pub async fn from_url_bundle(urls: UrlBundle) -> ChorusResult { + pub async fn from_url_bundle( + urls: UrlBundle, + options: Option, + ) -> ChorusResult { let is_limited: Option = Instance::is_limited(&urls.api).await?; let limit_information; @@ -89,7 +94,7 @@ impl Instance { instance_info: GeneralConfiguration::default(), limits_information: limit_information, client: Client::new(), - gateway_options: GatewayOptions::default(), + gateway_options: options.unwrap_or_default(), }; instance.instance_info = match instance.general_configuration_schema().await { Ok(schema) => schema, @@ -103,10 +108,12 @@ impl Instance { /// Creates a new [`Instance`] by trying to get the [relevant instance urls](UrlBundle) from a root url. /// + /// If `options` is `None`, the default [`GatewayOptions`] will be used. + /// /// Shorthand for `Instance::from_url_bundle(UrlBundle::from_root_domain(root_domain).await?)`. - pub async fn new(root_url: &str) -> ChorusResult { + pub async fn new(root_url: &str, options: Option) -> ChorusResult { let urls = UrlBundle::from_root_url(root_url).await?; - Instance::from_url_bundle(urls).await + Instance::from_url_bundle(urls, options).await } pub async fn is_limited(api_url: &str) -> ChorusResult> { @@ -199,10 +206,9 @@ impl ChorusUser { let settings = Arc::new(RwLock::new(UserSettings::default())); let object = Arc::new(RwLock::new(User::default())); let wss_url = &instance.read().unwrap().urls.wss.clone(); + let gateway_options = instance.read().unwrap().gateway_options; // Dummy gateway object - let gateway = Gateway::spawn(wss_url, GatewayOptions::default()) - .await - .unwrap(); + let gateway = Gateway::spawn(wss_url, gateway_options).await.unwrap(); ChorusUser { token: token.to_string(), belongs_to: instance.clone(), diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 94c51ed2..4b4f9c14 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -66,7 +66,9 @@ pub(crate) async fn setup() -> TestBundle { ) .init(); - let instance = Instance::new("http://localhost:3001/api").await.unwrap(); + let instance = Instance::new("http://localhost:3001/api", None) + .await + .unwrap(); // Requires the existence of the below user. let reg = RegisterSchema { username: "integrationtestuser".into(), From 411db01786d6c0776c0093ce0aa638bd9e83b2ec Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 26 Aug 2024 20:05:00 +0200 Subject: [PATCH 128/162] Revert d846ce9948ebb07988428250d6a02d2ea920a451 --- src/api/auth/register.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs index 1c25e606..821a52ff 100644 --- a/src/api/auth/register.rs +++ b/src/api/auth/register.rs @@ -45,16 +45,16 @@ impl Instance { .token; user.set_token(&token); - let mut identify = GatewayIdentifyPayload::common(); - identify.token = user.token(); - user.gateway.send_identify(identify).await; - let object = User::get(&mut user, None).await?; let settings = User::get_settings(&mut user).await?; *user.object.write().unwrap() = object; *user.settings.write().unwrap() = settings; + let mut identify = GatewayIdentifyPayload::common(); + identify.token = user.token(); + user.gateway.send_identify(identify).await; + Ok(user) } } From 1c90c8e32b98ced21ced26320eb62bd5e38903fc Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Wed, 28 Aug 2024 19:42:13 +0200 Subject: [PATCH 129/162] 0.16.0: fix lints (#558) * chore: fix doc lints * fix: use different chrono function due to deprecation * chore: format --- src/gateway/handle.rs | 7 ++++--- src/types/entities/mod.rs | 4 ++-- src/types/schema/user.rs | 7 ++++++- src/types/utils/snowflake.rs | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/gateway/handle.rs b/src/gateway/handle.rs index 6bcdba85..98a77314 100644 --- a/src/gateway/handle.rs +++ b/src/gateway/handle.rs @@ -10,9 +10,10 @@ use std::fmt::Debug; use super::{events::Events, *}; use crate::types::{self, Composite, Shared}; -/// Represents a handle to a Gateway connection. A Gateway connection will create observable -/// [`GatewayEvents`](GatewayEvent), which you can subscribe to. Gateway events include all currently -/// implemented types with the trait [`WebSocketEvent`] +/// Represents a handle to a Gateway connection. +/// +/// A Gateway connection will create observable [`Events`], which you can subscribe to. +/// /// Using this handle you can also send Gateway Events directly. #[derive(Debug, Clone)] pub struct GatewayHandle { diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index 2fec4cae..545614cd 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -128,10 +128,10 @@ pub trait Composite { pub trait IntoShared { /// Uses [`Shared`] to provide an ergonomic alternative to `Arc::new(RwLock::new(obj))`. /// - /// [`Shared`] can then be observed using the [`Gateway`], turning the underlying + /// [`Shared`] can then be observed using the gateway, turning the underlying /// `dyn Composite` into a self-updating struct, which is a tracked variant of a chorus /// entity struct, updating its' held information when new information concerning itself arrives - /// over the [`Gateway`] connection, reducing the need for expensive network-API calls. + /// over the gateway connection, reducing the need for expensive network-API calls. fn into_shared(self) -> Shared; } diff --git a/src/types/schema/user.rs b/src/types/schema/user.rs index e2600a49..9e25093f 100644 --- a/src/types/schema/user.rs +++ b/src/types/schema/user.rs @@ -31,7 +31,7 @@ pub struct UserModifySchema { // TODO: Add a CDN data type pub avatar: Option, /// Note: This is not yet implemented on Spacebar - pub avatar_decoration_id: Option, + pub avatar_decoration_id: Option, /// Note: This is not yet implemented on Spacebar pub avatar_decoration_sku_id: Option, /// The user's email address; if changing from a verified email, email_token must be provided @@ -70,6 +70,11 @@ pub struct UserModifySchema { /// # Note /// /// This is not yet implemented on Spacebar + /// + /// [UserFlags]: crate::types::UserFlags + /// [UserFlags::PREMIUM_PROMO_DISMISSED]: crate::types::UserFlags::PREMIUM_PROMO_DISMISSED + /// [UserFlags::HAS_UNREAD_URGENT_MESSAGES]: + /// crate::types::UserFlags::HAS_UNREAD_URGENT_MESSAGES pub flags: Option, /// The user's date of birth, can only be set once /// diff --git a/src/types/utils/snowflake.rs b/src/types/utils/snowflake.rs index 27e44dc8..e19f7667 100644 --- a/src/types/utils/snowflake.rs +++ b/src/types/utils/snowflake.rs @@ -26,7 +26,7 @@ impl Snowflake { const PROCESS_ID: u64 = 1; static INCREMENT: AtomicUsize = AtomicUsize::new(0); - let time = (Utc::now().naive_utc().timestamp_millis() - EPOCH) << 22; + let time = (Utc::now().naive_utc().and_utc().timestamp_millis() - EPOCH) << 22; let worker = WORKER_ID << 17; let process = PROCESS_ID << 12; let increment = INCREMENT.fetch_add(1, Ordering::Relaxed) as u64 % 32; From 261fe452c16e434b0e8af3209dcf065e8f72c564 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 28 Aug 2024 20:10:15 +0200 Subject: [PATCH 130/162] Bump version to v0.16.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2fb0d2d..2d79f4a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -236,7 +236,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chorus" -version = "0.15.0" +version = "0.16.0" dependencies = [ "async-trait", "base64 0.21.7", diff --git a/Cargo.toml b/Cargo.toml index f9a70474..6d4830ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "chorus" description = "A library for interacting with multiple Spacebar-compatible Instances at once." -version = "0.15.0" +version = "0.16.0" license = "MPL-2.0" edition = "2021" repository = "https://github.com/polyphony-chat/chorus" From 9f618f2882439e373a4fed4992169c077d8fbb90 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 24 Sep 2024 15:29:02 +0200 Subject: [PATCH 131/162] Bump sqlx-pg-uint --- Cargo.lock | 114 ++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d79f4a4..974a8dc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,13 +77,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -215,9 +215,9 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.14" +version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932" +checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" dependencies = [ "shlex", ] @@ -276,7 +276,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-bindgen-test", "wasmtimer", - "webpki-roots 0.26.3", + "webpki-roots 0.26.5", "ws_stream_wasm", ] @@ -286,7 +286,7 @@ version = "0.5.0" dependencies = [ "async-trait", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -457,7 +457,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -468,7 +468,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -691,7 +691,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -766,7 +766,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.4.0", + "indexmap 2.5.0", "slab", "tokio", "tokio-util", @@ -785,7 +785,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.4.0", + "indexmap 2.5.0", "slab", "tokio", "tokio-util", @@ -1090,9 +1090,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -1401,9 +1401,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] @@ -1601,7 +1601,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -1632,9 +1632,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ "toml_edit", ] @@ -1852,18 +1852,18 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" dependencies = [ "bitflags 2.6.0", "errno", @@ -1893,7 +1893,7 @@ dependencies = [ "once_cell", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.7", "subtle", "zeroize", ] @@ -1935,9 +1935,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -2030,7 +2030,7 @@ checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2053,7 +2053,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2078,7 +2078,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.4.0", + "indexmap 2.5.0", "serde", "serde_derive", "serde_json", @@ -2095,7 +2095,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2257,7 +2257,7 @@ dependencies = [ "hashbrown 0.14.5", "hashlink", "hex", - "indexmap 2.4.0", + "indexmap 2.5.0", "ipnetwork", "log", "memchr", @@ -2276,7 +2276,7 @@ dependencies = [ "tokio-stream", "tracing", "url", - "webpki-roots 0.26.3", + "webpki-roots 0.26.5", ] [[package]] @@ -2289,7 +2289,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2312,7 +2312,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.76", + "syn 2.0.77", "tempfile", "tokio", "url", @@ -2364,9 +2364,9 @@ dependencies = [ [[package]] name = "sqlx-pg-uint" -version = "0.5.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1cfe6c40c1cd0053b9029a41729a533ceb32093052df626aa8bfbba45e45f6" +checksum = "d1c03c61ff481e8dfca7e5fef11245378c2b27cd7f0d45096d360a7adbb07391" dependencies = [ "bigdecimal", "serde", @@ -2377,12 +2377,12 @@ dependencies = [ [[package]] name = "sqlx-pg-uint-macros" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ae3447aced07f8bc71d73dc8dd1c6d25c2f4d10ea62a22ceabc12af8410d7e2" +checksum = "0e527060e9f43479e5b386e4237ab320a36fce39394f6ed73c8870f4637f2e5f" dependencies = [ "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2487,9 +2487,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.76" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -2562,7 +2562,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2613,9 +2613,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.3" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -2635,7 +2635,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2695,11 +2695,11 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.5.0", "toml_datetime", "winnow", ] @@ -2730,7 +2730,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2929,7 +2929,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", "wasm-bindgen-shared", ] @@ -2963,7 +2963,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2997,7 +2997,7 @@ checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -3032,9 +3032,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a" dependencies = [ "rustls-pki-types", ] @@ -3245,9 +3245,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.40" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] @@ -3299,7 +3299,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 6d4830ed..359d20fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ rand = "0.8.5" flate2 = { version = "1.0.33", optional = true } webpki-roots = "0.26.3" pubserve = { version = "1.1.0", features = ["async", "send"] } -sqlx-pg-uint = { version = "0.5.0", features = ["serde"], optional = true } +sqlx-pg-uint = { version = "0.7.1", features = ["serde"], optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] rustls = "0.21.12" From 8fc9f4c603de99fa97ea5549481021886590b7c9 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 26 Sep 2024 21:26:19 +0200 Subject: [PATCH 132/162] Add Clone derive to GatewayRequestGuildMembers --- src/types/events/request_members.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/types/events/request_members.rs b/src/types/events/request_members.rs index a6cffdf6..5228170d 100644 --- a/src/types/events/request_members.rs +++ b/src/types/events/request_members.rs @@ -5,7 +5,7 @@ use crate::types::{events::WebSocketEvent, Snowflake}; use serde::{Deserialize, Serialize}; -#[derive(Debug, Deserialize, Serialize, Default, WebSocketEvent)] +#[derive(Debug, Deserialize, Serialize, Default, WebSocketEvent, Clone)] /// See pub struct GatewayRequestGuildMembers { pub guild_id: Snowflake, @@ -16,4 +16,3 @@ pub struct GatewayRequestGuildMembers { pub user_ids: Option, pub nonce: Option, } - From e7e3cb6f82e4ee271b6d1082d6aaa0aabd33ccbc Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Fri, 27 Sep 2024 17:39:04 +0200 Subject: [PATCH 133/162] User routes update (#537) * feat: Add UserProfile and other types * api: re-do a large part of the users api * feat: add modify user profile * feat: delete and disable user endpoints * feat: modify email and verify email endpoints * feat!: add discriminator parameter to get_user_by_username * feat!: add get_user_profile query string schema * chore: add integration expire behavior * feat: add get_pomelo_suggestions and get_pomelo_eligibility * feat: add create_pomelo_migration * fix: rustdoc lints * feat: recent_mentions endpoints Adds GET /users/@me/mentions and DELETE /users/@me/mentions/{message.id} * feat: add get_user_harvest & create_user_harvest Also adds /types/entities/harvest.rs, types for Harvest * feat: user notes endpoints Adds: get_user_notes, get_user_note, set_user_note * feat: add #545 and #546 Adds the RECENT_MENTION_DELETE and USER_NOTE_UPDATE gateway events. The events can be accessed at: message.recent_mention_delete & user.note_update * feat: add authorize_connection Also adds: src/types/entities/connection.rs, Connection and PublicConnection, src/api/users/connections.rs * feat: add rest* of Connections api * The only thing not added yet is create_domain_connection, because it uses errors in a funky way adds: - create_connection_callback - create_contact_sync_connection - get_connections - refresh_connection - modify_connection - delete_connection - get_connection_access_token - get_connection_subreddits + related schema for all those routes, and some supporting types * feat: add connected_accounts to UserProfile * feat: add affinities * feat: add get_premium_usage endpoint note: not fully tested; I do not have an account with premium * cliipy my arch nemesis strikes again * aa * feat: add create_domain_connection * feat: add get_burst_credits * grumble grumble * clippy * fix READY deserialization error on spacebar * fix a deserialization error on Spacebar See spacebarchat/server#1188 A deserialization error was happening with get_user_profile, where pronouns should have been serialized as an empty string, but were instead serialized as null. * skip serializing None query parameters * add test for get_user_profile * apparently Sb does not implement users/@me/notes * add some tests, minor connection updates - Document that create_domain_connection is unimplemented on Spacebar - Add Discord connection type - Change ConnectionType::array() into ConnectionType::vector() - returning a fixed size array is dubious, since it'll likely be expanded. Returning a vector is easier keep up to variable length - Add ConnectionType::discord_vector() and ConnectionType::spacebar_vector() to return a vector ConnectionTypes available on the respective server backends - add tests test_modify_user_profile, test_disable_user, test_get_user_note, test_set_user_note, test_get_user_affinities, test_get_guild_affinities, test_get_connections Note: connections are hard to test, since they require secrets / an external service's account * minor pre merge changes - add some extra doc comments - and into_public() for connection - remove a todo that is no longer valid --- src/api/auth/login.rs | 2 +- src/api/auth/mod.rs | 2 +- src/api/auth/register.rs | 3 +- src/api/users/connections.rs | 391 +++++++++++++++ src/api/users/mod.rs | 2 + src/api/users/users.rs | 806 ++++++++++++++++++++++++++++-- src/gateway/events.rs | 3 + src/gateway/gateway.rs | 3 + src/types/entities/connection.rs | 300 +++++++++++ src/types/entities/guild.rs | 13 +- src/types/entities/harvest.rs | 97 ++++ src/types/entities/integration.rs | 33 +- src/types/entities/mod.rs | 4 + src/types/entities/user.rs | 650 +++++++++++++++++++++++- src/types/events/message.rs | 9 + src/types/events/session.rs | 2 +- src/types/events/user.rs | 22 + src/types/schema/user.rs | 358 ++++++++++++- tests/common/mod.rs | 8 +- tests/user.rs | 192 ++++++- 20 files changed, 2848 insertions(+), 52 deletions(-) create mode 100644 src/api/users/connections.rs create mode 100644 src/types/entities/connection.rs create mode 100644 src/types/entities/harvest.rs diff --git a/src/api/auth/login.rs b/src/api/auth/login.rs index 3a9a9eeb..ab78a995 100644 --- a/src/api/auth/login.rs +++ b/src/api/auth/login.rs @@ -38,7 +38,7 @@ impl Instance { user.set_token(&login_result.token); user.settings = login_result.settings; - let object = User::get(&mut user, None).await?; + let object = User::get_current(&mut user).await?; *user.object.write().unwrap() = object; let mut identify = GatewayIdentifyPayload::common(); diff --git a/src/api/auth/mod.rs b/src/api/auth/mod.rs index b9050e14..96491351 100644 --- a/src/api/auth/mod.rs +++ b/src/api/auth/mod.rs @@ -25,7 +25,7 @@ impl Instance { pub async fn login_with_token(&mut self, token: &str) -> ChorusResult { let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await; - let object = User::get(&mut user, None).await?; + let object = User::get_current(&mut user).await?; let settings = User::get_settings(&mut user).await?; *user.object.write().unwrap() = object; diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs index 821a52ff..d978e0ff 100644 --- a/src/api/auth/register.rs +++ b/src/api/auth/register.rs @@ -43,9 +43,10 @@ impl Instance { .deserialize_response::(&mut user) .await? .token; + user.set_token(&token); - let object = User::get(&mut user, None).await?; + let object = User::get_current(&mut user).await?; let settings = User::get_settings(&mut user).await?; *user.object.write().unwrap() = object; diff --git a/src/api/users/connections.rs b/src/api/users/connections.rs new file mode 100644 index 00000000..29c40df1 --- /dev/null +++ b/src/api/users/connections.rs @@ -0,0 +1,391 @@ +use futures_util::FutureExt; +use reqwest::Client; + +use crate::{ + errors::{ChorusError, ChorusResult}, + instance::ChorusUser, + ratelimiter::ChorusRequest, + types::{ + AuthorizeConnectionReturn, AuthorizeConnectionSchema, Connection, ConnectionSubreddit, + ConnectionType, CreateConnectionCallbackSchema, CreateContactSyncConnectionSchema, + CreateDomainConnectionError, CreateDomainConnectionReturn, GetConnectionAccessTokenReturn, + LimitType, ModifyConnectionSchema, + }, +}; + +impl ChorusUser { + /// Fetches a url that can be used for authorizing a new connection. + /// + /// The user should then visit the url and authenticate to create the connection. + /// + /// # Notes + /// This route seems to be preferred by the official infrastructure (client) to + /// [Self::create_connection_callback]. + /// + /// # Reference + /// See + /// + /// Note: it doesn't seem to be actually unauthenticated + pub async fn authorize_connection( + &mut self, + connection_type: ConnectionType, + query_parameters: AuthorizeConnectionSchema, + ) -> ChorusResult { + let connection_type_string = serde_json::to_string(&connection_type) + .expect("Failed to serialize connection type!") + .replace('"', ""); + + let request = Client::new() + .get(format!( + "{}/connections/{}/authorize", + self.belongs_to.read().unwrap().urls.api, + connection_type_string + )) + // Note: ommiting this header causes a 401 Unauthorized, + // even though discord.sex mentions it as unauthenticated + .header("Authorization", self.token()) + .query(&query_parameters); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request + .deserialize_response::(self) + .await + .map(|response| response.url) + } + + /// Creates a new connection for the current user. + /// + /// # Notes + /// The official infrastructure (client) prefers the route + /// [Self::authorize_connection] to this one. + /// + /// # Reference + /// See + // TODO: When is this called? When should it be used over authorize_connection? + pub async fn create_connection_callback( + &mut self, + connection_type: ConnectionType, + json_schema: CreateConnectionCallbackSchema, + ) -> ChorusResult { + let connection_type_string = serde_json::to_string(&connection_type) + .expect("Failed to serialize connection type!") + .replace('"', ""); + + let request = Client::new() + .post(format!( + "{}/connections/{}/callback", + self.belongs_to.read().unwrap().urls.api, + connection_type_string + )) + .header("Authorization", self.token()) + .json(&json_schema); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Creates a new contact sync connection for the current user. + /// + /// # Notes + /// To create normal connection types, see [Self::authorize_connection] and + /// [Self::create_connection_callback] + /// + /// # Reference + /// See + pub async fn create_contact_sync_connection( + &mut self, + connection_account_id: &String, + json_schema: CreateContactSyncConnectionSchema, + ) -> ChorusResult { + let request = Client::new() + .put(format!( + "{}/users/@me/connections/contacts/{}", + self.belongs_to.read().unwrap().urls.api, + connection_account_id + )) + .header("Authorization", self.token()) + .json(&json_schema); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Creates a new domain connection for the current user. + /// + /// This route has two possible successful return values: + /// [CreateDomainConnectionReturn::Ok] and [CreateDomainConnectionReturn::ProofNeeded] + /// + /// To properly handle both, please see their respective documentation pages. + /// + /// # Notes + /// To create normal connection types, see [Self::authorize_connection] and + /// [Self::create_connection_callback] + /// + /// As of 2024/08/21, Spacebar does not yet implement this endpoint. + /// + /// # Examples + /// ```no_run + /// let domain = "example.com".to_string(); + /// + /// let user: ChorusUser; // Get this by registering / logging in + /// + /// let result = user.create_domain_connection(&domain).await; + /// + /// if let Ok(returned) = result { + /// match returned { + /// CreateDomainConnectionReturn::ProofNeeded(proof) => { + /// println!("Additional proof needed!"); + /// println!("Either:"); + /// println!(""); + /// println!("- create a DNS TXT record with the name _discord.{domain} and content {proof}"); + /// println!("or"); + /// println!("- create a file at https://{domain}/.well-known/discord with the content {proof}"); + /// // Once the user has added the proof, retry calling the endpoint + /// } + /// CreateDomainConnectionReturn::Ok(connection) => { + /// println!("Successfulyl created connection! {:?}", connection); + /// } + /// } + /// } else { + /// println!("Failed to create connection: {:?}", result); + /// } + /// ``` + /// + /// # Reference + /// See + pub async fn create_domain_connection( + &mut self, + domain: &String, + ) -> ChorusResult { + let request = Client::new() + .post(format!( + "{}/users/@me/connections/domain/{}", + self.belongs_to.read().unwrap().urls.api, + domain + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + let result = chorus_request + .deserialize_response::(self) + .await; + + if let Ok(connection) = result { + return Ok(CreateDomainConnectionReturn::Ok(connection)); + } + + let error = result.err().unwrap(); + + if let ChorusError::ReceivedErrorCode { + error_code, + error: ref error_string, + } = error + { + if error_code == 400 { + let try_deserialize: Result = + serde_json::from_str(error_string); + + if let Ok(deserialized_error) = try_deserialize { + return Ok(CreateDomainConnectionReturn::ProofNeeded( + deserialized_error.proof, + )); + } + } + } + + Err(error) + } + + /// Fetches the current user's [Connection]s + /// + /// # Reference + /// See + pub async fn get_connections(&mut self) -> ChorusResult> { + let request = Client::new() + .get(format!( + "{}/users/@me/connections", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Refreshes a local user's [Connection]. + /// + /// # Reference + /// See + pub async fn refresh_connection( + &mut self, + connection_type: ConnectionType, + connection_account_id: &String, + ) -> ChorusResult<()> { + let connection_type_string = serde_json::to_string(&connection_type) + .expect("Failed to serialize connection type!") + .replace('"', ""); + + let request = Client::new() + .post(format!( + "{}/users/@me/connections/{}/{}/refresh", + self.belongs_to.read().unwrap().urls.api, + connection_type_string, + connection_account_id + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.handle_request_as_result(self).await + } + + /// Changes settings on a local user's [Connection]. + /// + /// # Notes + /// Not all connection types support all parameters. + /// + /// # Reference + /// See + pub async fn modify_connection( + &mut self, + connection_type: ConnectionType, + connection_account_id: &String, + json_schema: ModifyConnectionSchema, + ) -> ChorusResult { + let connection_type_string = serde_json::to_string(&connection_type) + .expect("Failed to serialize connection type!") + .replace('"', ""); + + let request = Client::new() + .patch(format!( + "{}/users/@me/connections/{}/{}", + self.belongs_to.read().unwrap().urls.api, + connection_type_string, + connection_account_id + )) + .header("Authorization", self.token()) + .json(&json_schema); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Deletes a local user's [Connection]. + /// + /// # Reference + /// See + pub async fn delete_connection( + &mut self, + connection_type: ConnectionType, + connection_account_id: &String, + ) -> ChorusResult<()> { + let connection_type_string = serde_json::to_string(&connection_type) + .expect("Failed to serialize connection type!") + .replace('"', ""); + + let request = Client::new() + .delete(format!( + "{}/users/@me/connections/{}/{}", + self.belongs_to.read().unwrap().urls.api, + connection_type_string, + connection_account_id + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.handle_request_as_result(self).await + } + + /// Returns a new access token for the given connection. + /// + /// Only available for [ConnectionType::Twitch], [ConnectionType::YouTube] and [ConnectionType::Spotify] connections. + /// + /// # Reference + /// See + pub async fn get_connection_access_token( + &mut self, + connection_type: ConnectionType, + connection_account_id: &String, + ) -> ChorusResult { + let connection_type_string = serde_json::to_string(&connection_type) + .expect("Failed to serialize connection type!") + .replace('"', ""); + + let request = Client::new() + .get(format!( + "{}/users/@me/connections/{}/{}/access-token", + self.belongs_to.read().unwrap().urls.api, + connection_type_string, + connection_account_id + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request + .deserialize_response::(self) + .await + .map(|res| res.access_token) + } + + /// Fetches a list of [subreddits](crate::types::ConnectionSubreddit) + /// the connected account moderates. + /// + /// Only available for [ConnectionType::Reddit] connections. + /// + /// # Reference + /// See + pub async fn get_connection_subreddits( + &mut self, + connection_account_id: &String, + ) -> ChorusResult> { + let request = Client::new() + .get(format!( + "{}/users/@me/connections/reddit/{}/subreddits", + self.belongs_to.read().unwrap().urls.api, + connection_account_id + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } +} diff --git a/src/api/users/mod.rs b/src/api/users/mod.rs index b11772ab..702233cb 100644 --- a/src/api/users/mod.rs +++ b/src/api/users/mod.rs @@ -4,11 +4,13 @@ #![allow(unused_imports)] pub use channels::*; +pub use connections::*; pub use guilds::*; pub use relationships::*; pub use users::*; pub mod channels; +pub mod connections; pub mod guilds; pub mod relationships; pub mod users; diff --git a/src/api/users/users.rs b/src/api/users/users.rs index 4f6ef579..483a85c1 100644 --- a/src/api/users/users.rs +++ b/src/api/users/users.rs @@ -2,7 +2,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::sync::{Arc, RwLock}; +use std::{ + collections::HashMap, + sync::{Arc, RwLock}, +}; use reqwest::Client; use serde_json::to_string; @@ -11,22 +14,69 @@ use crate::{ errors::{ChorusError, ChorusResult}, instance::{ChorusUser, Instance}, ratelimiter::ChorusRequest, - types::{LimitType, User, UserModifySchema, UserSettings}, + types::{ + AuthorizeConnectionSchema, BurstCreditsInfo, ConnectionType, CreateUserHarvestSchema, + DeleteDisableUserSchema, GetPomeloEligibilityReturn, GetPomeloSuggestionsReturn, + GetRecentMentionsSchema, GetUserProfileSchema, GuildAffinities, Harvest, + HarvestBackendType, LimitType, ModifyUserNoteSchema, PremiumUsage, PublicUser, Snowflake, + User, UserAffinities, UserModifyProfileSchema, UserModifySchema, UserNote, UserProfile, + UserProfileMetadata, UserSettings, VerifyUserEmailChangeResponse, + VerifyUserEmailChangeSchema, + }, }; impl ChorusUser { - /// Gets a user by id, or if the id is None, gets the current user. + /// Gets the local / current user. + /// + /// # Notes + /// This function is a wrapper around [`User::get_current`]. + /// + /// # Reference + /// See + pub async fn get_current_user(&mut self) -> ChorusResult { + User::get_current(self).await + } + + /// Gets a non-local user by their id /// /// # Notes /// This function is a wrapper around [`User::get`]. /// /// # Reference - /// See and - /// - pub async fn get_user(&mut self, id: Option<&String>) -> ChorusResult { + /// See + pub async fn get_user(&mut self, id: Snowflake) -> ChorusResult { User::get(self, id).await } + /// Gets a non-local user by their unique username. + /// + /// As of 2024/07/28, Spacebar does not yet implement this endpoint. + /// + /// If fetching with a pomelo username, discriminator should be set to None. + /// + /// This route also permits fetching users with their old pre-pomelo username#discriminator + /// combo. + /// + /// Note: + /// + /// "Unless the target user is a bot, you must be able to add + /// the user as a friend to resolve them by username. + /// + /// Due to this restriction, you are not able to resolve your own username." + /// + /// # Notes + /// This function is a wrapper around [`User::get_by_username`]. + /// + /// # Reference + /// See + pub async fn get_user_by_username( + &mut self, + username: &String, + discriminator: Option<&String>, + ) -> ChorusResult { + User::get_by_username(self, username, discriminator).await + } + /// Gets the user's settings. /// /// # Notes @@ -40,7 +90,6 @@ impl ChorusUser { /// # Reference /// See pub async fn modify(&mut self, modify_schema: UserModifySchema) -> ChorusResult { - // See , note 1 let requires_current_password = modify_schema.username.is_some() || modify_schema.discriminator.is_some() @@ -67,39 +116,583 @@ impl ChorusUser { chorus_request.deserialize_response::(self).await } - /// Deletes the user from the Instance. + /// Disables the current user's account. + /// + /// Invalidates all active tokens. + /// + /// Requires the user's current password (if any) + /// + /// # Notes + /// Requires MFA /// /// # Reference - /// See - pub async fn delete(mut self) -> ChorusResult<()> { + /// See + pub async fn disable(&mut self, schema: DeleteDisableUserSchema) -> ChorusResult<()> { + let request = Client::new() + .post(format!( + "{}/users/@me/disable", + self.belongs_to.read().unwrap().urls.api + )) + .header("Authorization", self.token()) + .json(&schema); + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + chorus_request.handle_request_as_result(self).await + } + + /// Deletes the current user from the Instance. + /// + /// Requires the user's current password (if any) + /// + /// # Notes + /// Requires MFA + /// + /// # Reference + /// See + pub async fn delete(&mut self, schema: DeleteDisableUserSchema) -> ChorusResult<()> { let request = Client::new() .post(format!( "{}/users/@me/delete", self.belongs_to.read().unwrap().urls.api )) .header("Authorization", self.token()) + .json(&schema); + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + chorus_request.handle_request_as_result(self).await + } + + /// Gets a user's profile object by their id. + /// + /// This endpoint requires one of the following: + /// + /// - The other user is a bot + /// - The other user shares a mutual guild with the current user + /// - The other user is a friend of the current user + /// - The other user is a friend suggestion of the current user + /// - The other user has an outgoing friend request to the current user + /// + /// # Notes + /// This function is a wrapper around [`User::get_profile`]. + /// + /// # Reference + /// See + pub async fn get_user_profile( + &mut self, + id: Snowflake, + query_parameters: GetUserProfileSchema, + ) -> ChorusResult { + User::get_profile(self, id, query_parameters).await + } + + /// Modifies the current user's profile. + /// + /// Returns the updated [UserProfileMetadata]. + /// + /// # Notes + /// This function is a wrapper around [`User::modify_profile`]. + /// + /// # Reference + /// See + pub async fn modify_profile( + &mut self, + schema: UserModifyProfileSchema, + ) -> ChorusResult { + User::modify_profile(self, schema).await + } + + /// Initiates the email change process. + /// + /// Sends a verification code to the current user's email. + /// + /// Should be followed up with [Self::verify_email_change] + /// + /// # Reference + /// See + pub async fn initiate_email_change(&mut self) -> ChorusResult<()> { + let request = Client::new() + .put(format!( + "{}/users/@me/email", + self.belongs_to.read().unwrap().urls.api + )) + .header("Authorization", self.token()); + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + chorus_request.handle_request_as_result(self).await + } + + /// Verifies a code sent to change the current user's email. + /// + /// This endpoint returns a token which can be used with [Self::modify] + /// to set a new email address (email_token). + /// + /// # Notes + /// Should be the follow-up to [Self::initiate_email_change] + /// + /// As of 2024/08/08, Spacebar does not yet implement this endpoint. + // FIXME: Does this mean PUT users/@me/email is different? + /// + /// # Reference + /// See + pub async fn verify_email_change( + &mut self, + schema: VerifyUserEmailChangeSchema, + ) -> ChorusResult { + let request = Client::new() + .post(format!( + "{}/users/@me/email/verify-code", + self.belongs_to.read().unwrap().urls.api + )) + .header("Authorization", self.token()) + .json(&schema); + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + chorus_request + .deserialize_response::(self) + .await + } + + /// Returns a suggested unique username based on the current user's username. + /// + /// # Notes: + /// "This endpoint is used during the pomelo migration flow. + /// + /// The user must be in the rollout to use this endpoint." + /// + /// If a user has already migrated, this endpoint will likely return a 401 Unauthorized + /// ([ChorusError::NoPermission]) + /// + /// As of 2024/08/08, Spacebar does not yet implement this endpoint. + /// + /// # Reference + /// See + pub async fn get_pomelo_suggestions(&mut self) -> ChorusResult { + let request = Client::new() + .get(format!( + "{}/users/@me/pomelo-suggestions", + self.belongs_to.read().unwrap().urls.api + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + chorus_request + .deserialize_response::(self) + .await + .map(|returned| returned.username) + } + + /// Checks whether a unique username is available. + /// + /// Returns whether the username is not taken yet. + /// + /// # Notes + /// As of 2024/08/08, Spacebar does not yet implement this endpoint. + /// + /// # Reference + /// See + pub async fn get_pomelo_eligibility(&mut self, username: &String) -> ChorusResult { + let request = Client::new() + .post(format!( + "{}/users/@me/pomelo-attempt", + self.belongs_to.read().unwrap().urls.api + )) + .header("Authorization", self.token()) + // FIXME: should we create a type for this? + .body(format!(r#"{{ "username": {:?} }}"#, username)) + .header("Content-Type", "application/json"); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + chorus_request + .deserialize_response::(self) + .await + .map(|returned| !returned.taken) + } + + /// Migrates the user from the username#discriminator to the unique username system. + /// + /// Fires a [UserUpdate](crate::types::UserUpdate) gateway event. + /// + /// Updates [Self::object] to an updated representation returned by the server. + // FIXME: Is this appropriate behaviour? + /// + /// # Notes + /// "This endpoint is used during the pomelo migration flow. + /// + /// The user must be in the rollout to use this endpoint." + /// + /// If a user has already migrated, this endpoint will likely return a 401 Unauthorized + /// ([ChorusError::NoPermission]) + // + /// As of 2024/08/08, Spacebar does not yet implement this endpoint. + /// + /// # Reference + /// See + pub async fn create_pomelo_migration(&mut self, username: &String) -> ChorusResult<()> { + let request = Client::new() + .post(format!( + "{}/users/@me/pomelo", + self.belongs_to.read().unwrap().urls.api + )) + .header("Authorization", self.token()) + // FIXME: should we create a type for this? + .body(format!(r#"{{ "username": {:?} }}"#, username)) .header("Content-Type", "application/json"); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + let result = chorus_request.deserialize_response::(self).await; + + // FIXME: Does UserUpdate do this automatically? or would a user need to manually observe ChorusUser::object + if let Ok(new_object) = result { + *self.object.write().unwrap() = new_object; + return ChorusResult::Ok(()); + } + + ChorusResult::Err(result.err().unwrap()) + } + + /// Fetches a list of [Message](crate::types::Message)s that the current user has been + /// mentioned in during the last 7 days. + /// + /// # Notes + /// As of 2024/08/09, Spacebar does not yet implement this endpoint. + /// + /// # Reference + /// See + pub async fn get_recent_mentions( + &mut self, + query_parameters: GetRecentMentionsSchema, + ) -> ChorusResult> { + let request = Client::new() + .get(format!( + "{}/users/@me/mentions", + self.belongs_to.read().unwrap().urls.api + )) + .header("Authorization", self.token()) + .query(&query_parameters); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request + .deserialize_response::>(self) + .await + } + + /// Acknowledges a message the current user has been mentioned in. + /// + /// Fires a `RecentMentionDelete` gateway event. (Note: yet to be implemented in chorus, see [#545](https://github.com/polyphony-chat/chorus/issues/545)) + /// + /// # Notes + /// As of 2024/08/09, Spacebar does not yet implement this endpoint. + /// + /// # Reference + /// See + pub async fn delete_recent_mention(&mut self, message_id: Snowflake) -> ChorusResult<()> { + let request = Client::new() + .delete(format!( + "{}/users/@me/mentions/{}", + self.belongs_to.read().unwrap().urls.api, + message_id + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.handle_request_as_result(self).await + } + + /// If it exists, returns the most recent [Harvest] (personal data harvest request). + /// + /// To create a new [Harvest], see [Self::create_harvest]. + /// + /// # Notes + /// As of 2024/08/09, Spacebar does not yet implement this endpoint. (Or data harvesting) + /// + /// # Reference + /// See + pub async fn get_harvest(&mut self) -> ChorusResult> { + let request = Client::new() + .get(format!( + "{}/users/@me/harvest", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + // Manual handling, because a 204 with no harvest is a success state + // TODO: Maybe make this a method on ChorusRequest if we need it a lot + let response = chorus_request.send_request(self).await?; + log::trace!("Got response: {:?}", response); + + if response.status() == http::StatusCode::NO_CONTENT { + return Ok(None); + } + + let response_text = match response.text().await { + Ok(string) => string, + Err(e) => { + return Err(ChorusError::InvalidResponse { + error: format!( + "Error while trying to process the HTTP response into a String: {}", + e + ), + }); + } + }; + + let object = match serde_json::from_str::(&response_text) { + Ok(object) => object, + Err(e) => { + return Err(ChorusError::InvalidResponse { + error: format!( + "Error while trying to deserialize the JSON response into requested type T: {}. JSON Response: {}", + e, response_text + ), + }) + } + }; + Ok(Some(object)) + } + + /// Creates a personal data harvest request ([Harvest]) for the current user. + /// + /// # Notes + /// To fetch the latest existing harvest, see [Self::get_harvest]. + /// + /// Invalid options in the backends array are ignored. + /// + /// If the array is empty (after ignoring), it requests all [HarvestBackendType]s. + /// + /// As of 2024/08/09, Spacebar does not yet implement this endpoint. (Or data harvesting) + /// + /// # Reference + /// See + pub async fn create_harvest( + &mut self, + backends: Vec, + ) -> ChorusResult { + let schema = if backends.is_empty() { + CreateUserHarvestSchema { backends: None } + } else { + CreateUserHarvestSchema { + backends: Some(backends), + } + }; + + let request = Client::new() + .post(format!( + "{}/users/@me/harvest", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()) + .json(&schema); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Returns a mapping of user IDs ([Snowflake]s) to notes ([String]s) for the current user. + /// + /// # Notes + /// As of 2024/08/21, Spacebar does not yet implement this endpoint. + /// + /// # Reference + /// See + pub async fn get_user_notes(&mut self) -> ChorusResult> { + let request = Client::new() + .get(format!( + "{}/users/@me/notes", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + let chorus_request = ChorusRequest { request, limit_type: LimitType::default(), }; - chorus_request.handle_request_as_result(&mut self).await + + chorus_request.deserialize_response(self).await + } + + /// Fetches the note ([UserNote]) for the given user. + /// + /// If the current user has no note for the target, this endpoint + /// returns `Err(NotFound { error: "{\"message\": \"Unknown User\", \"code\": 10013}" })` + /// + /// # Notes + /// This function is a wrapper around [`User::get_note`]. + /// + /// # Reference + /// See + pub async fn get_user_note(&mut self, target_user_id: Snowflake) -> ChorusResult { + User::get_note(self, target_user_id).await + } + + /// Sets the note for the given user. + /// + /// Fires a `UserNoteUpdate` gateway event. (Note: yet to be implemented in chorus, see [#546](https://github.com/polyphony-chat/chorus/issues/546)) + /// + /// # Notes + /// This function is a wrapper around [`User::set_note`]. + /// + /// # Reference + /// See + pub async fn set_user_note( + &mut self, + target_user_id: Snowflake, + note: Option, + ) -> ChorusResult<()> { + User::set_note(self, target_user_id, note).await + } + + /// Fetches the current user's affinity scores for other users. + /// + /// (Affinity scores are a measure of how likely a user is to be friends with another user.) + /// + /// # Reference + /// See + pub async fn get_user_affinities(&mut self) -> ChorusResult { + let request = Client::new() + .get(format!( + "{}/users/@me/affinities/users", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Fetches the current user's affinity scores for their joined guilds. + /// + /// # Reference + /// See + pub async fn get_guild_affinities(&mut self) -> ChorusResult { + let request = Client::new() + .get(format!( + "{}/users/@me/affinities/guilds", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Fetches the current user's usage of various premium perks ([PremiumUsage] object). + /// + /// The local user must have premium (nitro), otherwise the request will fail + /// with a 404 NotFound error and the message {"message": "Premium usage not available", "code": 10084}. + /// + /// # Notes + /// As of 2024/08/16, Spacebar does not yet implement this endpoint. + /// + /// # Reference + /// See + pub async fn get_premium_usage(&mut self) -> ChorusResult { + let request = Client::new() + .get(format!( + "{}/users/@me/premium-usage", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Fetches info about the current user's burst credits + /// (how many are remaining, when they will replenish). + /// + /// Burst credits are used to create burst reactions. + /// + /// # Notes + /// As of 2024/08/18, Spacebar does not yet implement this endpoint. + pub async fn get_burst_credits(&mut self) -> ChorusResult { + let request = Client::new() + .get(format!( + "{}/users/@me/burst-credits", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await } } impl User { - /// Gets a user by id, or if the id is None, gets the current user. + /// Gets the local / current user. /// /// # Reference - /// See and - /// - pub async fn get(user: &mut ChorusUser, id: Option<&String>) -> ChorusResult { + /// See + pub async fn get_current(user: &mut ChorusUser) -> ChorusResult { let url_api = user.belongs_to.read().unwrap().urls.api.clone(); - let url = if id.is_none() { - format!("{}/users/@me", url_api) - } else { - format!("{}/users/{}", url_api, id.unwrap()) + let url = format!("{}/users/@me", url_api); + let request = reqwest::Client::new() + .get(url) + .header("Authorization", user.token()); + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::Global, }; + chorus_request.deserialize_response::(user).await + } + + /// Gets a non-local user by their id + /// + /// # Reference + /// See + pub async fn get(user: &mut ChorusUser, id: Snowflake) -> ChorusResult { + let url_api = user.belongs_to.read().unwrap().urls.api.clone(); + let url = format!("{}/users/{}", url_api, id); let request = reqwest::Client::new() .get(url) .header("Authorization", user.token()); @@ -107,16 +700,54 @@ impl User { request, limit_type: LimitType::Global, }; - match chorus_request.send_request(user).await { - Ok(result) => { - let result_text = result.text().await.unwrap(); - Ok(serde_json::from_str::(&result_text).unwrap()) - } - Err(e) => Err(e), + chorus_request + .deserialize_response::(user) + .await + } + + /// Gets a user by their unique username. + /// + /// As of 2024/07/28, Spacebar does not yet implement this endpoint. + /// + /// If fetching with a pomelo username, discriminator should be set to None. + /// + /// This route also permits fetching users with their old pre-pomelo username#discriminator + /// combo. + /// + /// Note: + /// + /// "Unless the target user is a bot, you must be able to add + /// the user as a friend to resolve them by username. + /// + /// Due to this restriction, you are not able to resolve your own username." + /// + /// # Reference + /// See + pub async fn get_by_username( + user: &mut ChorusUser, + username: &String, + discriminator: Option<&String>, + ) -> ChorusResult { + let url_api = user.belongs_to.read().unwrap().urls.api.clone(); + let url = format!("{}/users/username/{username}", url_api); + let mut request = reqwest::Client::new() + .get(url) + .header("Authorization", user.token()); + + if let Some(some_discriminator) = discriminator { + request = request.query(&[("discriminator", some_discriminator)]); } + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::Global, + }; + chorus_request + .deserialize_response::(user) + .await } - /// Gets the user's settings. + /// Gets the current user's settings. /// /// # Reference /// See @@ -129,12 +760,121 @@ impl User { request, limit_type: LimitType::Global, }; - match chorus_request.send_request(user).await { - Ok(result) => { - let result_text = result.text().await.unwrap(); - Ok(serde_json::from_str(&result_text).unwrap()) - } - Err(e) => Err(e), - } + chorus_request + .deserialize_response::(user) + .await + } + + /// Gets a user's profile object by their id. + /// + /// This endpoint requires one of the following: + /// + /// - The other user is a bot + /// - The other user shares a mutual guild with the current user + /// - The other user is a friend of the current user + /// - The other user is a friend suggestion of the current user + /// - The other user has an outgoing friend request to the current user + /// + /// # Reference + /// See + pub async fn get_profile( + user: &mut ChorusUser, + id: Snowflake, + query_parameters: GetUserProfileSchema, + ) -> ChorusResult { + let url_api = user.belongs_to.read().unwrap().urls.api.clone(); + let request: reqwest::RequestBuilder = Client::new() + .get(format!("{}/users/{}/profile", url_api, id)) + .header("Authorization", user.token()) + .query(&query_parameters); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::Global, + }; + chorus_request + .deserialize_response::(user) + .await + } + + /// Modifies the current user's profile. + /// + /// Returns the updated [UserProfileMetadata]. + /// + /// # Reference + /// See + pub async fn modify_profile( + user: &mut ChorusUser, + schema: UserModifyProfileSchema, + ) -> ChorusResult { + let url_api = user.belongs_to.read().unwrap().urls.api.clone(); + let request: reqwest::RequestBuilder = Client::new() + .patch(format!("{}/users/@me/profile", url_api)) + .header("Authorization", user.token()) + .json(&schema); + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::Global, + }; + chorus_request + .deserialize_response::(user) + .await + } + + /// Fetches the note ([UserNote]) for the given user. + /// + /// If the current user has no note for the target, this endpoint + /// returns `Err(NotFound { error: "{\"message\": \"Unknown User\", \"code\": 10013}" })` + /// + /// # Reference + /// See + pub async fn get_note( + user: &mut ChorusUser, + target_user_id: Snowflake, + ) -> ChorusResult { + let request = Client::new() + .get(format!( + "{}/users/@me/notes/{}", + user.belongs_to.read().unwrap().urls.api, + target_user_id + )) + .header("Authorization", user.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(user).await + } + + /// Sets the note for the given user. + /// + /// Fires a `UserNoteUpdate` gateway event. (Note: yet to be implemented in chorus, see [#546](https://github.com/polyphony-chat/chorus/issues/546)) + /// + /// # Reference + /// See + pub async fn set_note( + user: &mut ChorusUser, + target_user_id: Snowflake, + note: Option, + ) -> ChorusResult<()> { + let schema = ModifyUserNoteSchema { note }; + + let request = Client::new() + .put(format!( + "{}/users/@me/notes/{}", + user.belongs_to.read().unwrap().urls.api, + target_user_id + )) + .header("Authorization", user.token()) + .json(&schema); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.handle_request_as_result(user).await } } diff --git a/src/gateway/events.rs b/src/gateway/events.rs index 049434be..4663fe1a 100644 --- a/src/gateway/events.rs +++ b/src/gateway/events.rs @@ -69,12 +69,15 @@ pub struct Message { pub reaction_remove: Publisher, pub reaction_remove_all: Publisher, pub reaction_remove_emoji: Publisher, + pub recent_mention_delete: Publisher, pub ack: Publisher, } #[derive(Default, Debug)] pub struct User { pub update: Publisher, + pub connections_update: Publisher, + pub note_update: Publisher, pub guild_settings_update: Publisher, pub presence_update: Publisher, pub typing_start: Publisher, diff --git a/src/gateway/gateway.rs b/src/gateway/gateway.rs index 976769d2..20f86407 100644 --- a/src/gateway/gateway.rs +++ b/src/gateway/gateway.rs @@ -404,6 +404,7 @@ impl Gateway { "MESSAGE_REACTION_REMOVE" => message.reaction_remove, // TODO "MESSAGE_REACTION_REMOVE_ALL" => message.reaction_remove_all, // TODO "MESSAGE_REACTION_REMOVE_EMOJI" => message.reaction_remove_emoji, // TODO + "RECENT_MENTION_DELETE" => message.recent_mention_delete, "MESSAGE_ACK" => message.ack, "PRESENCE_UPDATE" => user.presence_update, // TODO "RELATIONSHIP_ADD" => relationship.add, @@ -413,6 +414,8 @@ impl Gateway { "STAGE_INSTANCE_DELETE" => stage_instance.delete, "TYPING_START" => user.typing_start, "USER_UPDATE" => user.update, // TODO + "USER_CONNECTIONS_UPDATE" => user.connections_update, // TODO + "USER_NOTE_UPDATE" => user.note_update, "USER_GUILD_SETTINGS_UPDATE" => user.guild_settings_update, "VOICE_STATE_UPDATE" => voice.state_update, // TODO "VOICE_SERVER_UPDATE" => voice.server_update, diff --git a/src/types/entities/connection.rs b/src/types/entities/connection.rs new file mode 100644 index 00000000..e6421b07 --- /dev/null +++ b/src/types/entities/connection.rs @@ -0,0 +1,300 @@ +use std::{collections::HashMap, fmt::Display}; + +use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; + +/// A 3rd party service connection to a user's account. +/// +/// # Reference +/// See +// TODO: Should (could) this type be Updateable and Composite? +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +pub struct Connection { + /// The id of the account on the 3rd party service + #[serde(rename = "id")] + pub connected_account_id: String, + + /// The service of the connected account + #[serde(rename = "type")] + pub connection_type: ConnectionType, + + /// The username of the connection account + pub name: String, + + /// If the connection is verified + pub verified: bool, + + /// Service specific metadata about the connection / connected account + // FIXME: Is there a better type? As far as I see the value is always encoded as a string + pub metadata: Option>, + pub metadata_visibility: ConnectionVisibilityType, + + /// If the connection if revoked + pub revoked: bool, + + // TODO: Add integrations + pub friend_sync: bool, + + /// Whether activities related to this connection will be shown in presence + pub show_activity: bool, + + /// Whether this connection has a corresponding 3rd party OAuth2 token + pub two_way_link: bool, + + /// Who can see this connection + pub visibility: ConnectionVisibilityType, + + /// The access token for the connection account + /// + /// Note: not included when fetching a user's connections via OAuth2 + pub access_token: Option, +} + +impl Connection { + /// Converts self info a [PublicConnection], forgetting private data + pub fn into_public(self: Connection) -> PublicConnection { + PublicConnection { + name: self.name, + verified: self.verified, + connection_type: self.connection_type, + connected_account_id: self.connected_account_id, + metadata: self.metadata, + } + } +} + +/// A partial / public [Connection] type. +/// +/// # Reference +/// See +// FIXME: Should (could) this type also be Updateable and Composite? +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +pub struct PublicConnection { + /// The id of the account on the 3rd party service + #[serde(rename = "id")] + pub connected_account_id: String, + + #[serde(rename = "type")] + pub connection_type: ConnectionType, + + /// The username of the connection account + pub name: String, + + /// If the connection is verified + pub verified: bool, + + /// Service specific metadata about the connection / connected account + // FIXME: Is there a better type? As far as I see the value is always encoded as a string + pub metadata: Option>, +} + +impl From for PublicConnection { + fn from(value: Connection) -> Self { + value.into_public() + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, Copy, PartialOrd, Ord)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[serde(rename_all = "lowercase")] +/// A type of connection; the service the connection is for +/// +/// Note: this is subject to change, and the enum is likely non-exhaustive +/// +/// # Reference +/// See +pub enum ConnectionType { + #[serde(rename = "amazon-music")] + AmazonMusic, + /// Battle.net + BattleNet, + /// Bungie.net + Bungie, + /// Discord?'s contact sync + /// + /// (Not returned in Get User Profile or when fetching connections) + Contacts, + Crunchyroll, + /// Note: spacebar only + Discord, + Domain, + Ebay, + EpicGames, + Facebook, + GitHub, + Instagram, + LeagueOfLegends, + PayPal, + /// Playstation network + Playstation, + Reddit, + Roblox, + RiotGames, + /// Samsung Galaxy + /// + /// Users can no longer add this service + Samsung, + Spotify, + /// Users can no longer add this service + Skype, + Steam, + TikTok, + Twitch, + Twitter, + Xbox, + YouTube, +} + +impl Display for ConnectionType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + Self::AmazonMusic => f.write_str("Amazon Music"), + Self::BattleNet => f.write_str("Battle.net"), + Self::Bungie => f.write_str("Bungie.net"), + Self::Ebay => f.write_str("eBay"), + Self::EpicGames => f.write_str("Epic Games"), + Self::LeagueOfLegends => f.write_str("League of Legends"), + Self::Playstation => f.write_str("PlayStation Network"), + Self::RiotGames => f.write_str("Riot Games"), + Self::Samsung => f.write_str("Samsung Galaxy"), + _ => f.write_str(format!("{:?}", self).as_str()), + } + } +} + +impl ConnectionType { + /// Returns an vector of all the connection types + // API note: this could be an array, but it is subject to change. + pub fn vector() -> Vec { + vec![ + ConnectionType::AmazonMusic, + ConnectionType::BattleNet, + ConnectionType::Bungie, + ConnectionType::Contacts, + ConnectionType::Crunchyroll, + ConnectionType::Discord, + ConnectionType::Domain, + ConnectionType::Ebay, + ConnectionType::EpicGames, + ConnectionType::Facebook, + ConnectionType::GitHub, + ConnectionType::Instagram, + ConnectionType::LeagueOfLegends, + ConnectionType::PayPal, + ConnectionType::Playstation, + ConnectionType::Reddit, + ConnectionType::RiotGames, + ConnectionType::Samsung, + ConnectionType::Spotify, + ConnectionType::Skype, + ConnectionType::Steam, + ConnectionType::TikTok, + ConnectionType::Twitch, + ConnectionType::Twitter, + ConnectionType::Xbox, + ConnectionType::YouTube, + ] + } + + /// Returns an vector of all the connection types available on discord + pub fn discord_vector() -> Vec { + vec![ + ConnectionType::AmazonMusic, + ConnectionType::BattleNet, + ConnectionType::Bungie, + ConnectionType::Contacts, + ConnectionType::Crunchyroll, + ConnectionType::Domain, + ConnectionType::Ebay, + ConnectionType::EpicGames, + ConnectionType::Facebook, + ConnectionType::GitHub, + ConnectionType::Instagram, + ConnectionType::LeagueOfLegends, + ConnectionType::PayPal, + ConnectionType::Playstation, + ConnectionType::Reddit, + ConnectionType::RiotGames, + ConnectionType::Samsung, + ConnectionType::Spotify, + ConnectionType::Skype, + ConnectionType::Steam, + ConnectionType::TikTok, + ConnectionType::Twitch, + ConnectionType::Twitter, + ConnectionType::Xbox, + ConnectionType::YouTube, + ] + } + + /// Returns an vector of all the connection types available on spacebar + pub fn spacebar_vector() -> Vec { + vec![ + ConnectionType::BattleNet, + ConnectionType::Discord, + ConnectionType::EpicGames, + ConnectionType::Facebook, + ConnectionType::GitHub, + ConnectionType::Reddit, + ConnectionType::Spotify, + ConnectionType::Twitch, + ConnectionType::Twitter, + ConnectionType::Xbox, + ConnectionType::YouTube, + ] + } +} + +#[derive( + Serialize_repr, Deserialize_repr, Debug, Clone, Eq, PartialEq, Hash, Copy, PartialOrd, Ord, +)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[repr(u8)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +/// # Reference +/// See +pub enum ConnectionVisibilityType { + /// Invisible to everyone except the user themselves + None = 0, + /// Visible to everyone + Everyone = 1, +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, Copy, PartialOrd, Ord)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[serde(rename_all = "lowercase")] +/// A type of two-way connection link +/// +/// # Reference +/// See +pub enum TwoWayLinkType { + /// The connection is linked via web + Web, + /// The connection is linked via mobile + Mobile, + /// The connection is linked via desktop + Desktop, +} + +impl Display for TwoWayLinkType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(format!("{:?}", self).as_str()) + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +/// Defines a subreddit as fetched through a Reddit connection ([[ConnectionType::Reddit]]). +/// +/// # Reference +/// See +pub struct ConnectionSubreddit { + /// The subreddit's internal id, e.g. "t5_388p4" + pub id: String, + + /// How many reddit users follow the subreddit + pub subscribers: usize, + + /// The subreddit's relative url, e.g. "/r/discordapp/" + pub url: String, +} diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 423339a1..91850ac2 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -452,7 +452,7 @@ pub enum VerificationLevel { #[cfg_attr(not(feature = "sqlx"), repr(u8))] #[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -/// See +/// See pub enum MFALevel { #[default] None = 0, @@ -476,7 +476,7 @@ pub enum MFALevel { #[cfg_attr(not(feature = "sqlx"), repr(u8))] #[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -/// See +/// See pub enum NSFWLevel { #[default] Default = 0, @@ -502,12 +502,19 @@ pub enum NSFWLevel { #[cfg_attr(not(feature = "sqlx"), repr(u8))] #[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -/// See +// Note: Maybe rename this to GuildPremiumTier? +/// **Guild** premium (Boosting) tier +/// +/// See pub enum PremiumTier { #[default] + /// No server boost perks None = 0, + /// Level 1 server boost perks Tier1 = 1, + /// Level 2 server boost perks Tier2 = 2, + /// Level 3 server boost perks Tier3 = 3, } diff --git a/src/types/entities/harvest.rs b/src/types/entities/harvest.rs new file mode 100644 index 00000000..b747641a --- /dev/null +++ b/src/types/entities/harvest.rs @@ -0,0 +1,97 @@ +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; + +use crate::types::Snowflake; + +#[cfg(feature = "client")] +use crate::gateway::Updateable; + +// FIXME: Should this type be Composite? +#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +/// A user's data harvest. +/// +/// # Reference +/// +/// See +pub struct Harvest { + pub harvest_id: Snowflake, + /// The id of the user being harvested + pub user_id: Snowflake, + /// How much the harvest has been processed + pub status: HarvestStatus, + /// The time the harvest was created + pub created_at: DateTime, + /// The time the harvest was last polled + pub polled_at: Option>, + /// The time the harvest was completed + pub completed_at: Option>, +} + +#[cfg(feature = "client")] +impl Updateable for Harvest { + #[cfg(not(tarpaulin_include))] + fn id(&self) -> Snowflake { + self.harvest_id + } +} + +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Default, + Clone, + Eq, + PartialEq, + Hash, + Copy, + PartialOrd, + Ord, +)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[repr(u8)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +/// Current status of a [Harvest] +/// +/// See and +pub enum HarvestStatus { + /// The harvest is queued and has not been started + Queued = 0, + /// The harvest is currently running / being processed + Running = 1, + /// The harvest has failed + Failed = 2, + /// The harvest has been completed successfully + Completed = 3, + #[default] + Unknown = 4, +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, Copy, PartialOrd, Ord)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +/// A type of backend / service a harvest can be requested for. +/// +/// See and +pub enum HarvestBackendType { + /// All account information; + Accounts, + /// Actions the user has taken; + /// + /// Represented as "Your Activity" in the discord client + Analytics, + /// First-party embedded activity information; + /// + /// e.g.: Chess in the Park, Checkers in the Park, Poker Night 2.0; + /// Sketch Heads, Watch Together, Letter League, Land-io, Know What I Meme + Activities, + /// The user's messages + Messages, + /// Official Discord programes; + /// + /// e.g.: Partner, HypeSquad, Verified Server + Programs, + /// Guilds the user is a member of; + Servers, +} diff --git a/src/types/entities/integration.rs b/src/types/entities/integration.rs index 50a82819..8afec21f 100644 --- a/src/types/entities/integration.rs +++ b/src/types/entities/integration.rs @@ -4,6 +4,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; use crate::types::{ entities::{Application, User}, @@ -24,7 +25,7 @@ pub struct Integration { pub syncing: Option, pub role_id: Option, pub enabled_emoticons: Option, - pub expire_behaviour: Option, + pub expire_behaviour: Option, pub expire_grace_period: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub user: Option>, @@ -51,6 +52,7 @@ pub struct IntegrationAccount { #[serde(rename_all = "snake_case")] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", sqlx(rename_all = "snake_case"))] +/// See pub enum IntegrationType { #[default] Twitch, @@ -58,3 +60,32 @@ pub enum IntegrationType { Discord, GuildSubscription, } + +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Default, + Clone, + Eq, + PartialEq, + Hash, + Copy, + PartialOrd, + Ord, +)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[repr(u8)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +/// Defines the behaviour that is executed when a user's subscription to the integration expires. +/// +/// See +pub enum IntegrationExpireBehaviour { + #[default] + /// Remove the subscriber role from the user + RemoveRole = 0, + /// Kick the user from the guild + Kick = 1, +} + + diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index 545614cd..969d731a 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -8,9 +8,11 @@ pub use audit_log::*; pub use auto_moderation::*; pub use channel::*; pub use config::*; +pub use connection::*; pub use emoji::*; pub use guild::*; pub use guild_member::*; +pub use harvest::*; pub use integration::*; pub use invite::*; pub use message::*; @@ -49,9 +51,11 @@ mod audit_log; mod auto_moderation; mod channel; mod config; +mod connection; mod emoji; mod guild; mod guild_member; +mod harvest; mod integration; mod invite; mod message; diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index 866d66cf..9c7c3b9d 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -7,7 +7,8 @@ use crate::types::utils::Snowflake; use crate::{UInt32, UInt8}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use serde_aux::prelude::deserialize_option_number_from_string; +use serde_aux::prelude::{deserialize_option_number_from_string, deserialize_default_from_null}; +use serde_repr::{Deserialize_repr, Serialize_repr}; use std::array::TryFromSliceError; use std::fmt::Debug; @@ -23,7 +24,7 @@ use crate::gateway::GatewayHandle; #[cfg(feature = "client")] use chorus_macros::{Composite, Updateable}; -use super::Emoji; +use super::{Emoji, GuildMember, PublicConnection}; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] @@ -40,6 +41,8 @@ impl User { #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "client", derive(Updateable, Composite))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +/// # Reference +/// See pub struct User { pub id: Snowflake, pub username: String, @@ -58,8 +61,10 @@ pub struct User { #[serde(default)] #[serde(deserialize_with = "deserialize_option_number_from_string")] pub flags: Option, + pub premium: Option, + /// The type of premium (Nitro) a user has + pub premium_type: Option, pub premium_since: Option>, - pub premium_type: Option, pub pronouns: Option, pub public_flags: Option, pub banner: Option, @@ -67,13 +72,15 @@ pub struct User { pub theme_colors: Option, pub phone: Option, pub nsfw_allowed: Option, - pub premium: Option, pub purchased_flags: Option, pub premium_usage_flags: Option, pub disabled: Option, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Copy)] +/// A user's theme colors, as u32s representing hex color codes +/// +/// found in [UserProfileMetadata] pub struct ThemeColors { #[serde(flatten)] inner: (u32, u32), @@ -140,6 +147,8 @@ impl sqlx::Type for ThemeColors { } #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +/// # Reference +/// See pub struct PublicUser { pub id: Snowflake, pub username: Option, @@ -151,7 +160,9 @@ pub struct PublicUser { pub pronouns: Option, pub bot: Option, pub bio: Option, - pub premium_type: Option, + /// The type of premium (Nitro) a user has + pub premium_type: Option, + /// The date the user's premium (Nitro) subscribtion started pub premium_since: Option>, pub public_flags: Option, } @@ -182,6 +193,8 @@ const CUSTOM_USER_FLAG_OFFSET: u64 = 1 << 32; bitflags::bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, chorus_macros::SerdeBitFlags)] #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] + /// # Reference + /// See pub struct UserFlags: u64 { const DISCORD_EMPLOYEE = 1 << 0; const PARTNERED_SERVER_OWNER = 1 << 1; @@ -195,6 +208,7 @@ bitflags::bitflags! { const EARLY_SUPPORTER = 1 << 9; const TEAM_USER = 1 << 10; const TRUST_AND_SAFETY = 1 << 11; + /// Note: deprecated by Discord const SYSTEM = 1 << 12; const HAS_UNREAD_URGENT_MESSAGES = 1 << 13; const BUGHUNTER_LEVEL_2 = 1 << 14; @@ -206,14 +220,640 @@ bitflags::bitflags! { } } +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Default, + Clone, + Eq, + PartialEq, + Hash, + Copy, + PartialOrd, + Ord, +)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[repr(u8)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +/// **User** premium (Nitro) type +/// +/// See +pub enum PremiumType { + #[default] + /// No Nitro + None = 0, + /// Nitro Classic + Tier1 = 1, + /// Nitro + Tier2 = 2, + /// Nitro Basic + Tier3 = 3, +} + #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +/// # Reference +/// See pub struct UserProfileMetadata { + /// The guild ID this profile applies to, if it is a guild profile. pub guild_id: Option, + /// The user's pronouns, up to 40 characters + #[serde(deserialize_with = "deserialize_default_from_null")] + // Note: spacebar will send this is as null, while it should be "" + // See issue 1188 pub pronouns: String, + /// The user's bio / description, up to 190 characters pub bio: Option, + /// The hash used to retrieve the user's banned from the CDN pub banner: Option, + /// Banner color encoded as an i32 representation of a hex color code pub accent_color: Option, + /// See [ThemeColors] pub theme_colors: Option, pub popout_animation_particle_type: Option, pub emoji: Option, } + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +/// A user's publically facing profile +/// +/// # Reference +/// See +pub struct UserProfile { + // TODO: add profile application object + pub user: PublicUser, + + #[serde(rename = "user_profile")] + pub profile_metadata: UserProfileMetadata, + + #[serde(default)] + pub badges: Vec, + + pub guild_member: Option, + + #[serde(rename = "guild_member_profile")] + pub guild_member_profile_metadata: Option, + + #[serde(default)] + pub guild_badges: Vec, + + /// The user's legacy username#discriminator, if existing and shown + pub legacy_username: Option, + + #[serde(default)] + pub mutual_guilds: Vec, + + #[serde(default)] + pub mutual_friends: Vec, + + pub mutual_friends_count: Option, + + pub connected_accounts: Vec, + + // TODO: Add application role connections! + /// The type of premium (Nitro) a user has + pub premium_type: Option, + /// The date the user's premium (Nitro) subscribtion started + pub premium_since: Option>, + /// The date the user's premium guild (Boosting) subscribtion started + pub premium_guild_since: Option>, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +/// Info about a badge on a user's profile ([UserProfile]) +/// +/// # Reference +/// See +/// +/// For a list of know badges, see +pub struct ProfileBadge { + /// The badge's unique id, e.g. "staff", "partner", "premium", ... + pub id: String, + /// Description of what the badge represents, e.g. "Discord Staff" + pub description: String, + /// An icon hash, to get the badge's icon from the CDN + pub icon: String, + /// A link (potentially used for href) for the badge. + /// + /// e.g.: + /// `"staff"` badge links to `"https://discord.com/company"` + /// `"certified_moderator"` links to `"https://discord.com/safety"` + pub link: Option, +} + +impl PartialEq for ProfileBadge { + fn eq(&self, other: &Self) -> bool { + // Note: does not include description, since it changes for some badges + // + // Think nitro "Subscriber since ...", "Server boosting since ..." + self.id.eq(&other.id) && self.icon.eq(&other.icon) && self.link.eq(&other.link) + } +} + +impl ProfileBadge { + /// Returns a badge representing the "staff" badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_staff() -> Self { + Self { + id: "staff".to_string(), + description: "Discord Staff".to_string(), + icon: "5e74e9b61934fc1f67c65515d1f7e60d".to_string(), + link: Some("https://discord.com/company".to_string()), + } + } + + /// Returns a badge representing the partnered server owner badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_partner() -> Self { + Self { + id: "partner".to_string(), + description: "Partnered Server Owner".to_string(), + icon: "3f9748e53446a137a052f3454e2de41e".to_string(), + link: Some("https://discord.com/partners".to_string()), + } + } + + /// Returns a badge representing the certified moderator badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_certified_moderator() -> Self { + Self { + id: "certified_moderator".to_string(), + description: "Moderator Programs Alumni".to_string(), + icon: "fee1624003e2fee35cb398e125dc479b".to_string(), + link: Some("https://discord.com/safety".to_string()), + } + } + + /// Returns a badge representing the hypesquad events badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_hypesquad() -> Self { + Self { + id: "hypesquad".to_string(), + description: "HypeSquad Events".to_string(), + icon: "bf01d1073931f921909045f3a39fd264".to_string(), + link: Some("https://support.discord.com/hc/en-us/articles/360035962891-Profile-Badges-101#h_01GM67K5EJ16ZHYZQ5MPRW3JT3".to_string()), + } + } + + /// Returns a badge representing the hypesquad bravery badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_hypesquad_bravery() -> Self { + Self { + id: "hypesquad_house_1".to_string(), + description: "HypeSquad Bravery".to_string(), + icon: "8a88d63823d8a71cd5e390baa45efa02".to_string(), + link: Some("https://discord.com/settings/hypesquad-online".to_string()), + } + } + + /// Returns a badge representing the hypesquad brilliance badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_hypesquad_brilliance() -> Self { + Self { + id: "hypesquad_house_2".to_string(), + description: "HypeSquad Brilliance".to_string(), + icon: "011940fd013da3f7fb926e4a1cd2e618".to_string(), + link: Some("https://discord.com/settings/hypesquad-online".to_string()), + } + } + + /// Returns a badge representing the hypesquad balance badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_hypesquad_balance() -> Self { + Self { + id: "hypesquad_house_3".to_string(), + description: "HypeSquad Balance".to_string(), + icon: "3aa41de486fa12454c3761e8e223442e".to_string(), + link: Some("https://discord.com/settings/hypesquad-online".to_string()), + } + } + + /// Returns a badge representing the bug hunter level 1 badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_bug_hunter_1() -> Self { + Self { + id: "bug_hunter_level_1".to_string(), + description: "Discord Bug Hunter".to_string(), + icon: "2717692c7dca7289b35297368a940dd0".to_string(), + link: Some( + "https://support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs" + .to_string(), + ), + } + } + + /// Returns a badge representing the bug hunter level 2 badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_bug_hunter_2() -> Self { + Self { + id: "bug_hunter_level_2".to_string(), + description: "Discord Bug Hunter".to_string(), + icon: "848f79194d4be5ff5f81505cbd0ce1e6".to_string(), + link: Some( + "https://support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs" + .to_string(), + ), + } + } + + /// Returns a badge representing the active developer badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_active_developer() -> Self { + Self { + id: "active_developer".to_string(), + description: "Active Developer".to_string(), + icon: "6bdc42827a38498929a4920da12695d9".to_string(), + link: Some( + "https://support-dev.discord.com/hc/en-us/articles/10113997751447?ref=badge" + .to_string(), + ), + } + } + + /// Returns a badge representing the early verified bot developer badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_early_verified_developer() -> Self { + Self { + id: "verified_developer".to_string(), + description: "Early Verified Bot Developer".to_string(), + icon: "6df5892e0f35b051f8b61eace34f4967".to_string(), + link: None, + } + } + + /// Returns a badge representing the early supporter badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_early_supporter() -> Self { + Self { + id: "early_supporter".to_string(), + description: "Early Supporter".to_string(), + icon: "7060786766c9c840eb3019e725d2b358".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the nitro subscriber badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_nitro() -> Self { + Self { + id: "premium".to_string(), + description: "Subscriber since 1 Jan 2015".to_string(), + icon: "2ba85e8026a8614b640c2837bcdfe21b".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 1 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_1() -> Self { + Self { + id: "guild_booster_lvl1".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "51040c70d4f20a921ad6674ff86fc95c".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 2 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_2() -> Self { + Self { + id: "guild_booster_lvl2".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "0e4080d1d333bc7ad29ef6528b6f2fb7".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 3 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_3() -> Self { + Self { + id: "guild_booster_lvl3".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "72bed924410c304dbe3d00a6e593ff59".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 4 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_4() -> Self { + Self { + id: "guild_booster_lvl4".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "df199d2050d3ed4ebf84d64ae83989f8".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 5 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_5() -> Self { + Self { + id: "guild_booster_lvl5".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "996b3e870e8a22ce519b3a50e6bdd52f".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 6 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_6() -> Self { + Self { + id: "guild_booster_lvl6".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "991c9f39ee33d7537d9f408c3e53141e".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 7 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_7() -> Self { + Self { + id: "guild_booster_lvl7".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "cb3ae83c15e970e8f3d410bc62cb8b99".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 8 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_8() -> Self { + Self { + id: "guild_booster_lvl8".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "7142225d31238f6387d9f09efaa02759".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 9 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_9() -> Self { + Self { + id: "guild_booster_lvl9".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "ec92202290b48d0879b7413d2dde3bab".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the legacy username badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_legacy_username() -> Self { + Self { + id: "legacy_username".to_string(), + description: "Originally known as USERNAME".to_string(), + icon: "6de6d34650760ba5551a79732e98ed60".to_string(), + link: None, + } + } + + /// Returns a badge representing the legacy username badge on Discord.com, + /// with the provided username (which should already contain the #DISCRIM part) + /// + /// # Reference + /// See + pub fn discord_legacy_username_with_username(username: String) -> Self { + Self { + id: "legacy_username".to_string(), + description: format!("Originally known as {username}"), + icon: "6de6d34650760ba5551a79732e98ed60".to_string(), + link: None, + } + } + + /// Returns a badge representing the legacy username badge on Discord.com, + /// with the provided username and discriminator + /// + /// # Reference + /// See + pub fn discord_legacy_username_with_username_and_discriminator( + username: String, + discriminator: String, + ) -> Self { + Self { + id: "legacy_username".to_string(), + description: format!("Originally known as {username}#{discriminator}"), + icon: "6de6d34650760ba5551a79732e98ed60".to_string(), + link: None, + } + } + + /// Returns a badge representing the bot commands badge on Discord.com + /// + /// Note: This badge is only for bot accounts + /// + /// # Reference + /// See + pub fn discord_bot_commands() -> Self { + Self { + id: "bot_commands".to_string(), + description: "Supports Commands".to_string(), + icon: "6f9e37f9029ff57aef81db857890005e".to_string(), + link: Some( + "https://discord.com/blog/welcome-to-the-new-era-of-discord-apps?ref=badge" + .to_string(), + ), + } + } + + /// Returns a badge representing the bot automod badge on Discord.com + /// + /// Note: This badge is only for bot accounts + /// + /// # Reference + /// See + pub fn discord_bot_automod() -> Self { + Self { + id: "automod".to_string(), + description: "Uses AutoMod".to_string(), + icon: "f2459b691ac7453ed6039bbcfaccbfcd".to_string(), + link: None, + } + } + + /// Returns a badge representing the application guild subscription badge on Discord.com + /// + /// No idea where this badge could show up, but apparently it means a guild has an + /// application's premium + /// + /// # Reference + /// See + pub fn discord_application_guild_subscription() -> Self { + Self { + id: "application_guild_subscription".to_string(), + description: "This server has APPLICATION Premium".to_string(), + icon: "d2010c413a8da2208b7e4f35bd8cd4ac".to_string(), + link: None, + } + } +} + +/// Structure which shows a mutual guild with a user +/// +/// # Reference +/// See +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct MutualGuild { + pub id: Snowflake, + /// The user's nickname in the guild, if any + pub nick: Option, +} + +/// Structure which is returned by the [crate::instance::ChorusUser::get_user_note] endpoint. +/// +/// Note that [crate::instance::ChorusUser::get_user_notes] endpoint +/// returns a completely different structure; +// Specualation: this is probably how Discord stores notes internally +/// +/// # Reference +/// See +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +pub struct UserNote { + /// Actual note contents; max 256 characters + pub note: String, + /// The ID of the user the note is on + pub note_user_id: Snowflake, + /// The ID of the user who created the note (always the current user) + pub user_id: Snowflake, +} + +/// Structure which defines an affinity the local user has with another user. +/// +/// # Reference +/// See +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, PartialOrd)] +pub struct UserAffinity { + /// The other user's id + pub user_id: Snowflake, + /// The affinity score + pub affinity: f32, +} + +/// Structure which defines an affinity the local user has with a guild. +/// +/// # Reference +/// See +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, PartialOrd)] +pub struct GuildAffinity { + /// The guild's id + pub guild_id: Snowflake, + /// The affinity score + pub affinity: f32, +} + +/// Structure which defines the local user's premium perk usage. +/// +/// # Reference +/// See +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct PremiumUsage { + /// Number of Nitro stickers the user has sent + pub nitro_sticker_sends: PremiumUsageData, + /// Number of animated emojis the user has sent + pub total_animated_emojis: PremiumUsageData, + /// Number of global emojis the user has sent + pub total_global_emojis: PremiumUsageData, + /// Number of large uploads the user has made + pub total_large_uploads: PremiumUsageData, + /// Number of times the user has streamed in HD + pub total_hd_streams: PremiumUsageData, + /// Number of hours the user has streamed in HD + pub hd_hours_streamed: PremiumUsageData, +} + +/// Structure for the data in [PremiumUsage]. +/// +/// Currently only contains the number of uses of a premium perk. +/// +/// # Reference +/// See +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct PremiumUsageData { + /// Total number of uses for this perk + pub value: usize, +} + +impl From for usize { + fn from(value: PremiumUsageData) -> Self { + value.value + } +} + +impl From for PremiumUsageData { + fn from(value: usize) -> Self { + PremiumUsageData { value } + } +} diff --git a/src/types/events/message.rs b/src/types/events/message.rs index 1b855dfc..d2ca3082 100644 --- a/src/types/events/message.rs +++ b/src/types/events/message.rs @@ -149,6 +149,15 @@ pub struct MessageReactionRemoveEmoji { pub emoji: Emoji, } +#[derive(Debug, Serialize, Deserialize, Default, Clone, Copy, WebSocketEvent)] +/// Sent when a message that mentioned the current user in the last week is acknowledged and deleted. +/// +/// # Reference +/// See +pub struct RecentMentionDelete { + pub message_id: Snowflake, +} + #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// Officially Undocumented /// diff --git a/src/types/events/session.rs b/src/types/events/session.rs index a76ebc3c..8adaa336 100644 --- a/src/types/events/session.rs +++ b/src/types/events/session.rs @@ -30,7 +30,7 @@ pub struct Session { // Note: I don't think this one exists yet? Though I might've made a mistake and this might be a duplicate pub struct ClientInfo { pub client: Option, - pub os: String, + pub os: Option, pub version: u8, } diff --git a/src/types/events/user.rs b/src/types/events/user.rs index 877c96cd..fc72be4b 100644 --- a/src/types/events/user.rs +++ b/src/types/events/user.rs @@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::types::entities::PublicUser; use crate::types::events::WebSocketEvent; use crate::types::utils::Snowflake; +use crate::types::Connection; #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] /// See ; @@ -16,6 +17,27 @@ pub struct UserUpdate { pub user: PublicUser, } +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] +/// Sent to indicate updates to a user's [Connection]. +/// +/// Not documented anywhere +pub struct UserConnectionsUpdate { + #[serde(flatten)] + pub connection: Connection, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] +/// See ; +/// +/// Sent when a note the current user has on another user is modified; +/// +/// If the field "note" is an empty string, the note was removed. +pub struct UserNoteUpdate { + /// Id of the user the note is for + pub id: Snowflake, + pub note: String, +} + #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] /// Undocumented; /// diff --git a/src/types/schema/user.rs b/src/types/schema/user.rs index 9e25093f..7a2543a6 100644 --- a/src/types/schema/user.rs +++ b/src/types/schema/user.rs @@ -4,10 +4,13 @@ use std::collections::HashMap; -use chrono::NaiveDate; +use chrono::{DateTime, NaiveDate, Utc}; use serde::{Deserialize, Serialize}; -use crate::types::Snowflake; +use crate::types::{ + Connection, GuildAffinity, HarvestBackendType, Snowflake, ThemeColors, TwoWayLinkType, + UserAffinity, +}; #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] #[serde(rename_all = "snake_case")] @@ -41,7 +44,12 @@ pub struct UserModifySchema { pub email: Option, /// The user's email token from their previous email, required if a new email is set. /// - /// See and + /// See: + /// + /// - the endpoints and + /// + /// - the relevant methods [`ChorusUser::initiate_email_change`](crate::instance::ChorusUser::initiate_email_change) and [`ChorusUser::verify_email_change`](crate::instance::ChorusUser::verify_email_change) + /// /// for changing the user's email. /// /// # Note @@ -111,3 +119,347 @@ pub struct PrivateChannelCreateSchema { pub access_tokens: Option>, pub nicks: Option>, } + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// A schema used to modify the current user's profile. +/// +/// Similar to [crate::types::UserProfileMetadata] +/// +/// See +pub struct UserModifyProfileSchema { + // Note: one of these causes a 500 if it is sent + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new pronouns (max 40 characters) + pub pronouns: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new bio (max 190 characters) + pub bio: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + // TODO: Add banner -- do we have an image data struct + /// The user's new accent color encoded as an i32 representation of a hex color code + pub accent_color: Option, + + // Note: without the skip serializing this currently (2024/07/28) causes a 500! + // + // Which in turns locks the user's account, requiring phone number verification + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new [ThemeColors] + pub theme_colors: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new profile popup animation particle type + pub popout_animation_particle_type: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new profile emoji id + pub emoji_id: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new profile ffect id + pub profile_effect_id: Option, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// A schema used to delete or disable the current user's profile. +/// +/// See and +/// +pub struct DeleteDisableUserSchema { + /// The user's current password, if any + pub password: Option, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// A schema used for [ChorusUser::verify_email_change](crate::instance::ChorusUser::verify_email_change) +/// +/// See +pub struct VerifyUserEmailChangeSchema { + /// The verification code sent to the user's email + pub code: String, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// The return type of [ChorusUser::verify_email_change](crate::instance::ChorusUser::verify_email_change) +/// +/// See +pub struct VerifyUserEmailChangeResponse { + /// The email_token to be used in [ChorusUser::modify](crate::instance::ChorusUser::modify) + #[serde(rename = "token")] + pub email_token: String, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)] +/// Query string parameters for the route GET /users/{user.id}/profile +/// ([crate::types::User::get_profile]) +/// +/// See +pub struct GetUserProfileSchema { + #[serde(skip_serializing_if = "Option::is_none")] + /// Whether to include the mutual guilds between the current user. + /// + /// If unset it will default to true + pub with_mutual_guilds: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Whether to include the mutual friends between the current user. + /// + /// If unset it will default to false + pub with_mutual_friends: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Whether to include the number of mutual friends between the current user + /// + /// If unset it will default to false + pub with_mutual_friends_count: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// The guild id to get the user's member profile in, if any. + /// + /// Note: + /// + /// when you click on a user in the member list in the discord client, a request is sent with + /// this property set to the selected guild id. + /// + /// This makes the request include fields such as guild_member and guild_member_profile + pub guild_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// The role id to get the user's application role connection metadata in, if any. + pub connections_role_id: Option, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Internal type for the [crate::instance::ChorusUser::get_pomelo_suggestions] endpoint. +/// +/// See +pub(crate) struct GetPomeloSuggestionsReturn { + pub username: String, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Internal type for the [crate::instance::ChorusUser::get_pomelo_eligibility] endpoint. +/// +/// See +pub(crate) struct GetPomeloEligibilityReturn { + pub taken: bool, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)] +/// Query string parameters for the route GET /users/@me/mentions +/// ([crate::instance::ChorusUser::get_recent_mentions]) +/// +/// See +pub struct GetRecentMentionsSchema { + /// Only fetch messages before this message id + /// + /// Due to the nature of snowflakes, this can be easily used to fetch + /// messages before a certain timestamp + pub before: Option, + /// Max number of messages to return + /// + /// Should be between 1 and 100. + /// + /// If unset the limit is 25 messages + pub limit: Option, + /// Limit messages to a specific guild + pub guild_id: Option, + /// Whether to include role mentions. + /// + /// If unset the server assumes true + pub roles: Option, + /// Whether to include @everyone and @here mentions. + /// + /// If unset the server assumes true + pub everyone: Option, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Internal type for the [crate::instance::ChorusUser::create_harvest] endpoint. +// (koza): imo it's nicer if the user can just pass a vec, instead of having to bother with +// a specific type +/// +/// See +pub(crate) struct CreateUserHarvestSchema { + pub backends: Option>, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Internal type for the [crate::instance::ChorusUser::set_user_note] endpoint. +/// +/// See +pub(crate) struct ModifyUserNoteSchema { + pub note: Option, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Query string parameters for the route GET /connections/{connection.type}/authorize +/// ([crate::instance::ChorusUser::authorize_connection]) +/// +/// See +pub struct AuthorizeConnectionSchema { + /// The type of two-way link ([TwoWayLinkType]) to create + pub two_way_link_type: Option, + /// The device code to use for the two-way link + pub two_way_user_code: Option, + /// If this is a continuation of a previous authorization + pub continuation: bool, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Internal type for the [crate::instance::ChorusUser::authorize_connection] endpoint. +/// +/// See +pub(crate) struct AuthorizeConnectionReturn { + pub url: String, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Json schema for the route POST /connections/{connection.type}/callback ([crate::instance::ChorusUser::create_connection_callback]). +/// +/// See +pub struct CreateConnectionCallbackSchema { + /// The authorization code for the connection + pub code: String, + /// The "state" used to authorize a connection + // TODO: what is this? + pub state: String, + pub two_way_link_code: Option, + pub insecure: Option, + pub friend_sync: Option, + /// Additional parameters used for OpenID Connect + // FIXME: Is this correct? in other connections additional info + // is provided like this, only being string - string + pub openid_params: Option>, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Json schema for the route PUT /users/@me/connections/contacts/{connection.id} ([crate::instance::ChorusUser::create_contact_sync_connection]). +/// +/// See +pub struct CreateContactSyncConnectionSchema { + /// The username of the connection account + pub name: String, + /// Whether to sync friends over the connection + pub friend_sync: Option, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Json schema for the route PATCH /users/@me/connections/{connection.type}/{connection.id} ([crate::instance::ChorusUser::modify_connection]). +/// +/// Note: not all connection types support all parameters. +/// +/// See +pub struct ModifyConnectionSchema { + /// The connection account's username + /// + /// Note: We have not found which connection this could apply to + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, + + /// Whether activities related to this connection will be shown in presence + /// + /// e.g. on a Spotify connection, "Display Spotify as your status" + #[serde(skip_serializing_if = "Option::is_none")] + pub show_activity: Option, + + /// Whether or not to sync friends from this connection + /// + /// Note: we have not found which connections this can apply to + #[serde(skip_serializing_if = "Option::is_none")] + pub friend_sync: Option, + + /// Whether to show additional metadata on the user's profile + /// + /// e.g. on a Steam connection, "Display details on profile" + /// (number of games, items, member since) + /// + /// on a Twitter connection, number of posts / followers, member since + #[serde(skip_serializing_if = "Option::is_none")] + pub metadata_visibility: Option, + + /// Whether to show the connection on the user's profile + #[serde(skip_serializing_if = "Option::is_none")] + pub visibility: Option, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Internal type for the [crate::instance::ChorusUser::get_connection_access_token] endpoint. +/// +/// See +pub(crate) struct GetConnectionAccessTokenReturn { + pub access_token: String, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd)] +/// Return type for the [crate::instance::ChorusUser::get_user_affinities] endpoint. +/// +/// See +pub struct UserAffinities { + pub user_affinities: Vec, + // FIXME: Is this also a UserAffinity vec? + // Also, no idea what this means + pub inverse_user_affinities: Vec, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd)] +/// Return type for the [crate::instance::ChorusUser::get_guild_affinities] endpoint. +/// +/// See +pub struct GuildAffinities { + pub guild_affinities: Vec, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +/// Return type for the error in the [crate::instance::ChorusUser::create_domain_connection] endpoint. +/// +/// This allows us to retrieve the needed proof for actually verifying the connection. +/// +/// See +pub(crate) struct CreateDomainConnectionError { + pub message: String, + pub code: u16, + pub proof: String, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +/// Return type for the [crate::instance::ChorusUser::create_domain_connection] endpoint. +/// +/// See +pub enum CreateDomainConnectionReturn { + /// Additional proof is needed to verify domain ownership. + /// + /// The inner object is a proof string (e.g. + /// `dh=dceaca792e3c40fcf356a9297949940af5cfe538`) + /// + /// To verify ownership, either: + /// + /// - add the proof string as a TXT DNS record to the domain, + /// with the name of the record being `_discord.{domain}` or + /// + /// - serve the proof string as a file at `https://{domain}/.well-known/discord` + /// + /// After either of these proofs are added, the request should be retried. + /// + ProofNeeded(String), + /// The domain connection was successfully created, no further action is needed. + /// + /// The inner object is the new connection. + Ok(Connection), +} + +#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +/// Return type for the [crate::instance::ChorusUser::get_burst_credits] endpoint. +/// +/// # Reference +/// ```json +/// { +/// "amount": 2, +/// "replenished_today": false, +/// "next_replenish_at": "2024-08-18T23:53:17+00:00" +/// } +/// ``` +pub struct BurstCreditsInfo { + /// Amount of remaining burst credits the local user has + pub amount: u16, + pub replenished_today: bool, + /// When the user's burst credits will automatically replenish again + pub next_replenish_at: DateTime, +} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 4b4f9c14..ac85b859 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -5,7 +5,7 @@ use std::str::FromStr; use chorus::gateway::{Gateway, GatewayOptions}; -use chorus::types::{IntoShared, PermissionFlags}; +use chorus::types::{DeleteDisableUserSchema, IntoShared, PermissionFlags}; use chorus::{ instance::{ChorusUser, Instance}, types::{ @@ -146,5 +146,9 @@ pub(crate) async fn setup() -> TestBundle { pub(crate) async fn teardown(mut bundle: TestBundle) { let id = bundle.guild.read().unwrap().id; Guild::delete(&mut bundle.user, id).await.unwrap(); - bundle.user.delete().await.unwrap() + bundle + .user + .delete(DeleteDisableUserSchema { password: None }) + .await + .unwrap() } diff --git a/tests/user.rs b/tests/user.rs index 2fbc1874..e267ae36 100644 --- a/tests/user.rs +++ b/tests/user.rs @@ -2,7 +2,19 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use chorus::types::{PublicUser, Snowflake, User}; +use chorus::{ + errors::ChorusError, + types::{ + ConnectionType, DeleteDisableUserSchema, PublicUser, Snowflake, User, + UserModifyProfileSchema, UserNote, + }, +}; +#[cfg(target_arch = "wasm32")] +use wasm_bindgen_test::*; +#[cfg(target_arch = "wasm32")] +wasm_bindgen_test_configure!(run_in_browser); + +mod common; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), test)] @@ -20,3 +32,181 @@ fn to_public_user() { let from_user = user.into_public_user(); assert_eq!(public_user, from_user); } + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_get_user_profile() { + let mut bundle = common::setup().await; + + let user_id = bundle.user.object.read().unwrap().id; + + let user_profile = bundle + .user + .get_user_profile(user_id, chorus::types::GetUserProfileSchema::default()) + .await; + + assert!(user_profile.is_ok()); + + common::teardown(bundle).await; +} + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_modify_user_profile() { + let mut bundle = common::setup().await; + + let bio = Some(String::from("A user.")); + let pronouns = Some(String::from("they/them")); + + let modify = UserModifyProfileSchema { + bio: bio.clone(), + pronouns: pronouns.clone(), + ..Default::default() + }; + + bundle.user.modify_profile(modify).await.unwrap(); + + let user_id = bundle.user.object.read().unwrap().id; + + let user_profile = bundle + .user + .get_user_profile(user_id, chorus::types::GetUserProfileSchema::default()) + .await + .unwrap(); + + assert_eq!(user_profile.profile_metadata.bio, bio); + assert_eq!(user_profile.profile_metadata.pronouns, pronouns.unwrap()); + + common::teardown(bundle).await; +} + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_disable_user() { + let mut bundle = common::setup().await; + + let mut other_user = bundle.create_user("integrationtestuser4").await; + + other_user + .disable(DeleteDisableUserSchema { password: None }) + .await + .unwrap(); + + common::teardown(bundle).await; +} + +// Note: these two tests are currently broken. +// FIXME: readd them once bitfl0wer/server#2 is merged +/* +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_get_user_note() { + let mut bundle = common::setup().await; + + let mut other_user = bundle.create_user("integrationtestuser3").await; + + let user_id = bundle.user.object.read().unwrap().id; + let other_user_id = other_user.object.read().unwrap().id; + + let result = bundle.user.get_user_note(other_user_id).await; + assert!(matches!( + result.err().unwrap(), + ChorusError::NotFound { .. } + )); + + bundle + .user + .set_user_note(other_user_id, Some(String::from("A note."))) + .await + .unwrap(); + + assert!(false); + + let result = bundle.user.get_user_note(other_user_id).await; + assert_eq!( + result, + Ok(UserNote { + user_id, + note_user_id: other_user_id, + note: String::from("A note.") + }) + ); + + other_user + .delete(DeleteDisableUserSchema { password: None }) + .await + .unwrap(); + common::teardown(bundle).await; +} + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_set_user_note() { + let mut bundle = common::setup().await; + + let mut other_user = bundle.create_user("integrationtestuser3").await; + + let user_id = bundle.user.object.read().unwrap().id; + let other_user_id = other_user.object.read().unwrap().id; + + bundle + .user + .set_user_note(other_user_id, Some(String::from("A note."))) + .await + .unwrap(); + + let result = bundle.user.get_user_note(other_user_id).await; + assert_eq!( + result, + Ok(UserNote { + user_id, + note_user_id: other_user_id, + note: String::from("A note.") + }) + ); + + other_user + .delete(DeleteDisableUserSchema { password: None }) + .await + .unwrap(); + common::teardown(bundle).await; +}*/ + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_get_user_affinities() { + let mut bundle = common::setup().await; + + let result = bundle.user.get_user_affinities().await.unwrap(); + + assert!(result.user_affinities.is_empty()); + assert!(result.inverse_user_affinities.is_empty()); + + common::teardown(bundle).await; +} + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_get_guild_affinities() { + let mut bundle = common::setup().await; + + let result = bundle.user.get_guild_affinities().await.unwrap(); + + assert!(result.guild_affinities.is_empty()); + + common::teardown(bundle).await; +} + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_get_connections() { + let mut bundle = common::setup().await; + + let result = bundle.user.get_connections().await.unwrap(); + + // We can't *really* test creating or getting connections... + // TODO: Find a way? + assert!(result.is_empty()); + + common::teardown(bundle).await; +} From 333dad89c8f22cea9b2448fddda8899123875a5f Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Sat, 28 Sep 2024 10:32:33 +0200 Subject: [PATCH 134/162] Differentiate between instance softwares (#560) * Add InstanceOptions type * feat: add /ping and /version, implement software differentiation * fix: better error handling, missing slash in /policies/instance - handle deserialization errors and not parsing the http content into a string - the route only works on spacebar if you add a trailing slash for some reason --- src/api/instance.rs | 104 ++++++++++++++++++++++++++ src/api/mod.rs | 2 + src/api/policies/instance/instance.rs | 27 ++++++- src/gateway/options.rs | 19 +++++ src/instance.rs | 104 +++++++++++++++++++++++++- src/types/schema/instance.rs | 84 +++++++++++++++++++++ src/types/schema/mod.rs | 4 +- tests/instance.rs | 14 ++++ 8 files changed, 352 insertions(+), 6 deletions(-) create mode 100644 src/api/instance.rs create mode 100644 src/types/schema/instance.rs diff --git a/src/api/instance.rs b/src/api/instance.rs new file mode 100644 index 00000000..20680e41 --- /dev/null +++ b/src/api/instance.rs @@ -0,0 +1,104 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! Contains miscellaneous api routes, such as /version and /ping +use serde_json::from_str; + +use crate::errors::{ChorusError, ChorusResult}; +use crate::instance::Instance; +use crate::types::{GeneralConfiguration, PingReturn, VersionReturn}; + +impl Instance { + /// Pings the instance, also fetches instance info. + /// + /// See: [PingReturn] + /// + /// # Notes + /// This is a Spacebar only endpoint. + /// + /// # Reference + /// See + pub async fn ping(&self) -> ChorusResult { + let endpoint_url = format!("{}/ping", self.urls.api.clone()); + + let request = match self.client.get(&endpoint_url).send().await { + Ok(result) => result, + Err(e) => { + return Err(ChorusError::RequestFailed { + url: endpoint_url, + error: e.to_string(), + }); + } + }; + + if !request.status().as_str().starts_with('2') { + return Err(ChorusError::ReceivedErrorCode { + error_code: request.status().as_u16(), + error: request.text().await.unwrap(), + }); + } + + let response_text = match request.text().await { + Ok(string) => string, + Err(e) => { + return Err(ChorusError::InvalidResponse { + error: format!( + "Error while trying to process the HTTP response into a String: {}", + e + ), + }); + } + }; + + match from_str::(&response_text) { + Ok(return_value) => Ok(return_value), + Err(e) => Err(ChorusError::InvalidResponse { error: format!("Error while trying to deserialize the JSON response into requested type T: {}. JSON Response: {}", + e, response_text) }) + } + } + + /// Fetches the instance's software implementation and version. + /// + /// See: [VersionReturn] + /// + /// # Notes + /// This is a Symfonia only endpoint. (For now, we hope that spacebar will adopt it as well) + pub async fn get_version(&self) -> ChorusResult { + let endpoint_url = format!("{}/version", self.urls.api.clone()); + + let request = match self.client.get(&endpoint_url).send().await { + Ok(result) => result, + Err(e) => { + return Err(ChorusError::RequestFailed { + url: endpoint_url, + error: e.to_string(), + }); + } + }; + + if !request.status().as_str().starts_with('2') { + return Err(ChorusError::ReceivedErrorCode { + error_code: request.status().as_u16(), + error: request.text().await.unwrap(), + }); + } + + let response_text = match request.text().await { + Ok(string) => string, + Err(e) => { + return Err(ChorusError::InvalidResponse { + error: format!( + "Error while trying to process the HTTP response into a String: {}", + e + ), + }); + } + }; + + match from_str::(&response_text) { + Ok(return_value) => Ok(return_value), + Err(e) => Err(ChorusError::InvalidResponse { error: format!("Error while trying to deserialize the JSON response into requested type T: {}. JSON Response: {}", e, response_text) }) + } + } +} diff --git a/src/api/mod.rs b/src/api/mod.rs index c9ca2792..5e2f7cab 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -10,6 +10,7 @@ pub use guilds::*; pub use invites::*; pub use policies::instance::instance::*; pub use users::*; +pub use instance::*; pub mod auth; pub mod channels; @@ -17,3 +18,4 @@ pub mod guilds; pub mod invites; pub mod policies; pub mod users; +pub mod instance; diff --git a/src/api/policies/instance/instance.rs b/src/api/policies/instance/instance.rs index 584db338..f2a40bc1 100644 --- a/src/api/policies/instance/instance.rs +++ b/src/api/policies/instance/instance.rs @@ -17,7 +17,7 @@ impl Instance { /// # Reference /// See pub async fn general_configuration_schema(&self) -> ChorusResult { - let endpoint_url = self.urls.api.clone() + "/policies/instance"; + let endpoint_url = self.urls.api.clone() + "/policies/instance/"; let request = match self.client.get(&endpoint_url).send().await { Ok(result) => result, Err(e) => { @@ -35,7 +35,28 @@ impl Instance { }); } - let body = request.text().await.unwrap(); - Ok(from_str::(&body).unwrap()) + let response_text = match request.text().await { + Ok(string) => string, + Err(e) => { + return Err(ChorusError::InvalidResponse { + error: format!( + "Error while trying to process the HTTP response into a String: {}", + e + ), + }); + } + }; + + match from_str::(&response_text) { + Ok(object) => Ok(object), + Err(e) => { + Err(ChorusError::InvalidResponse { + error: format!( + "Error while trying to deserialize the JSON response into requested type T: {}. JSON Response: {}", + e, response_text + ), + }) + } + } } } diff --git a/src/gateway/options.rs b/src/gateway/options.rs index 4ff6178b..b8ded327 100644 --- a/src/gateway/options.rs +++ b/src/gateway/options.rs @@ -2,6 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use crate::instance::InstanceSoftware; + #[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Debug, Default, Copy)] /// Options passed when initializing the gateway connection. /// @@ -22,6 +24,23 @@ pub struct GatewayOptions { } impl GatewayOptions { + /// Creates the ideal gateway options for an [InstanceSoftware], + /// based off which features it supports. + pub fn for_instance_software(software: InstanceSoftware) -> GatewayOptions { + // TODO: Support ETF + let encoding = GatewayEncoding::Json; + + let transport_compression = match software.supports_gateway_zlib() { + true => GatewayTransportCompression::ZLibStream, + false => GatewayTransportCompression::None, + }; + + GatewayOptions { + encoding, + transport_compression, + } + } + /// Adds the options to an existing gateway url /// /// Returns the new url diff --git a/src/instance.rs b/src/instance.rs index a8671e0a..f0569a99 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -28,11 +28,12 @@ use crate::UrlBundle; pub struct Instance { pub urls: UrlBundle, pub instance_info: GeneralConfiguration, + pub(crate) software: InstanceSoftware, pub limits_information: Option, #[serde(skip)] pub client: Client, #[serde(skip)] - pub gateway_options: GatewayOptions, + pub(crate) gateway_options: GatewayOptions, } #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq)] @@ -72,6 +73,8 @@ impl Instance { /// If `options` is `None`, the default [`GatewayOptions`] will be used. /// /// To create an Instance from one singular url, use [`Instance::new()`]. + // Note: maybe make this just take urls and then add another method which creates an instance + // from urls and custom gateway options, since gateway options will be automatically generated? pub async fn from_url_bundle( urls: UrlBundle, options: Option, @@ -88,6 +91,7 @@ impl Instance { } else { limit_information = None } + let mut instance = Instance { urls: urls.clone(), // Will be overwritten in the next step @@ -95,7 +99,10 @@ impl Instance { limits_information: limit_information, client: Client::new(), gateway_options: options.unwrap_or_default(), + // Will also be detected soon + software: InstanceSoftware::Other, }; + instance.instance_info = match instance.general_configuration_schema().await { Ok(schema) => schema, Err(e) => { @@ -103,6 +110,13 @@ impl Instance { GeneralConfiguration::default() } }; + + instance.software = instance.detect_software().await; + + if options.is_none() { + instance.gateway_options = GatewayOptions::for_instance_software(instance.software()); + } + Ok(instance) } @@ -133,12 +147,98 @@ impl Instance { } } - /// Sets the [`GatewayOptions`] the instance will use when spawning new connections. + /// Detects which [InstanceSoftware] the instance is running. + pub async fn detect_software(&self) -> InstanceSoftware { + + if let Ok(version) = self.get_version().await { + match version.server.to_lowercase().as_str() { + "symfonia" => return InstanceSoftware::Symfonia, + // We can dream this will be implemented one day + "spacebar" => return InstanceSoftware::SpacebarTypescript, + _ => {} + } + } + + // We know it isn't a symfonia server now, work around spacebar + // not really having a version endpoint + let ping = self.ping().await; + + if ping.is_ok() { + return InstanceSoftware::SpacebarTypescript; + } + + InstanceSoftware::Other + } + + /// Returns the [`GatewayOptions`] the instance uses when spawning new connections. + /// + /// These options are used on the gateways created when logging in and registering. + pub fn gateway_options(&self) -> GatewayOptions { + self.gateway_options + } + + /// Manually sets the [`GatewayOptions`] the instance should use when spawning new connections. /// /// These options are used on the gateways created when logging in and registering. pub fn set_gateway_options(&mut self, options: GatewayOptions) { self.gateway_options = options; } + + /// Returns which [`InstanceSoftware`] the instance is running. + pub fn software(&self) -> InstanceSoftware { + self.software + } + + /// Manually sets which [`InstanceSoftware`] the instance is running. + /// + /// Note: you should only use this if you are absolutely sure about an instance (e. g. you run it). + /// If set to an incorrect value, this may cause unexpected errors or even undefined behaviours. + /// + /// Manually setting the software is generally discouraged. Chorus should automatically detect + /// which type of software the instance is running. + pub fn set_software(&mut self, software: InstanceSoftware) { + self.software = software; + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +/// The software implementation the spacebar-compatible instance is running. +/// +/// This is useful since some softwares may support additional features, +/// while other do not fully implement the api yet. +pub enum InstanceSoftware { + /// The official typescript Spacebar server, available + /// at + SpacebarTypescript, + /// The Polyphony server written in rust, available at + /// at + Symfonia, + /// We could not determine the instance software or it + /// is one we don't specifically differentiate. + /// + /// Assume it implements all features of the spacebar protocol. + #[default] + Other, +} + +impl InstanceSoftware { + /// Returns whether the software supports z-lib stream compression on the gateway + pub fn supports_gateway_zlib(self) -> bool { + match self { + InstanceSoftware::SpacebarTypescript => true, + InstanceSoftware::Symfonia => false, + InstanceSoftware::Other => true, + } + } + + /// Returns whether the software supports sending data in the Erlang external term format on the gateway + pub fn supports_gateway_etf(self) -> bool { + match self { + InstanceSoftware::SpacebarTypescript => true, + InstanceSoftware::Symfonia => false, + InstanceSoftware::Other => true, + } + } } #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] diff --git a/src/types/schema/instance.rs b/src/types/schema/instance.rs new file mode 100644 index 00000000..7d19483c --- /dev/null +++ b/src/types/schema/instance.rs @@ -0,0 +1,84 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! Contains schema for miscellaneous api routes, such as /version and /ping +//! +//! Implementations of those routes can be found in /api/instance.rs + +use serde::{Deserialize, Serialize}; + +use crate::types::{GeneralConfiguration, Snowflake}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +/// The return type of the spacebar-only /api/ping endpoint +pub struct PingReturn { + /// Note: always "pong!" + pub ping: String, + pub instance: PingInstance, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +#[serde(rename_all = "camelCase")] +/// [GeneralConfiguration] as returned from the /api/ping endpoint +pub struct PingInstance { + pub id: Option, + pub name: String, + pub description: Option, + pub image: Option, + pub correspondence_email: Option, + pub correspondence_user_id: Option, + pub front_page: Option, + pub tos_page: Option, +} + +impl PingInstance { + /// Converts self into the [GeneralConfiguration] type + pub fn into_general_configuration(self) -> GeneralConfiguration { + GeneralConfiguration { + instance_name: self.name, + instance_description: self.description, + front_page: self.front_page, + tos_page: self.tos_page, + correspondence_email: self.correspondence_email, + correspondence_user_id: self.correspondence_user_id, + image: self.image, + instance_id: self.id, + } + } + + /// Converts the [GeneralConfiguration] type into self + pub fn from_general_configuration(other: GeneralConfiguration) -> Self { + Self { + id: other.instance_id, + name: other.instance_name, + description: other.instance_description, + image: other.image, + correspondence_email: other.correspondence_email, + correspondence_user_id: other.correspondence_user_id, + front_page: other.front_page, + tos_page: other.tos_page, + } + } +} + +impl From for GeneralConfiguration { + fn from(value: PingInstance) -> Self { + value.into_general_configuration() + } +} + +impl From for PingInstance { + fn from(value: GeneralConfiguration) -> Self { + Self::from_general_configuration(value) + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +/// The return type of the symfonia-only /version endpoint +pub struct VersionReturn { + /// The instance's software version, e. g. "0.1.0" + pub version: String, + /// The instance's software, e. g. "symfonia" or "spacebar" + pub server: String, +} diff --git a/src/types/schema/mod.rs b/src/types/schema/mod.rs index 09e542e4..2888046e 100644 --- a/src/types/schema/mod.rs +++ b/src/types/schema/mod.rs @@ -13,6 +13,7 @@ pub use role::*; pub use user::*; pub use invites::*; pub use voice_state::*; +pub use instance::*; mod apierror; mod audit_log; @@ -25,9 +26,10 @@ mod role; mod user; mod invites; mod voice_state; +mod instance; #[derive(Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq, PartialOrd, Eq, Ord)] pub struct GenericSearchQueryWithLimit { pub query: String, pub limit: Option, -} \ No newline at end of file +} diff --git a/tests/instance.rs b/tests/instance.rs index eb5fc606..d83e5e74 100644 --- a/tests/instance.rs +++ b/tests/instance.rs @@ -3,6 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. mod common; +use chorus::instance::InstanceSoftware; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; #[cfg(target_arch = "wasm32")] @@ -19,3 +20,16 @@ async fn generate_general_configuration_schema() { .unwrap(); common::teardown(bundle).await; } + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn detect_instance_software() { + let bundle = common::setup().await; + + let software = bundle.instance.detect_software().await; + assert_eq!(software, InstanceSoftware::SpacebarTypescript); + + assert_eq!(bundle.instance.software(), InstanceSoftware::SpacebarTypescript); + + common::teardown(bundle).await; +} From 2a35429d3fe3fd88ae7a244699d5fa067518ac1b Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Sat, 28 Sep 2024 23:09:49 +0200 Subject: [PATCH 135/162] Ready Event Updates (#561) * Update Ready, Split Ready into User and Bot variants * add supplemental to_bot method for gatewayready * Use serde(default) to fix missing attrs in spacebar server impl --- src/types/events/ready.rs | 107 +++++++++++++++++++++++++++++++++----- 1 file changed, 95 insertions(+), 12 deletions(-) diff --git a/src/types/events/ready.rs b/src/types/events/ready.rs index ffba526a..b5aceea1 100644 --- a/src/types/events/ready.rs +++ b/src/types/events/ready.rs @@ -2,38 +2,121 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use std::collections::HashMap; + use serde::{Deserialize, Serialize}; use crate::types::entities::{Guild, User}; use crate::types::events::{Session, WebSocketEvent}; -use crate::types::{Activity, Channel, ClientStatusObject, GuildMember, PresenceUpdate, Snowflake, VoiceState}; +use crate::types::{ + Activity, Channel, ClientStatusObject, GuildMember, PresenceUpdate, Relationship, Snowflake, + UserSettings, VoiceState, +}; #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] -/// 1/2 officially documented; -/// Received after identifying, provides initial user info; +/// Received after identifying, provides initial user info /// /// See and -// TODO: There are a LOT of fields missing here pub struct GatewayReady { - pub analytics_token: Option, - pub auth_session_id_hash: Option, - pub country_code: Option, + pub analytics_token: String, + pub auth_session_id_hash: String, + pub country_code: String, + pub v: u8, + pub user: User, + #[serde(default)] + pub guilds: Vec, + pub presences: Option>, + pub sessions: Option>, + pub session_id: String, + pub session_type: String, + pub resume_gateway_url: String, + pub shard: Option<(u64, u64)>, + pub user_settings: Option, + pub user_settings_proto: Option, + #[serde(default)] + pub relationships: Vec, + pub friend_suggestion_count: u32, + #[serde(default)] + pub private_channels: Vec, + #[serde(default)] + pub notes: HashMap, + pub merged_presences: Option, + #[serde(default)] + pub users: Vec, + pub auth_token: Option, + #[serde(default)] + pub authenticator_types: Vec, + pub required_action: Option, + #[serde(default)] + pub geo_ordered_rtc_regions: Vec, + /// TODO: Make tutorial object into object + pub tutorial: Option, + pub api_code_version: u8, + #[serde(default)] + pub experiments: Vec, + #[serde(default)] + pub guild_experiments: Vec, +} +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] +/// Received after identifying, provides initial information about the bot session. +/// +/// See and +pub struct GatewayReadyBot { pub v: u8, pub user: User, - /// For bots these are [crate::types::UnavailableGuild]s, for users they are [Guild] pub guilds: Vec, pub presences: Option>, pub sessions: Option>, pub session_id: String, - pub session_type: Option, - pub resume_gateway_url: Option, + pub session_type: String, + pub resume_gateway_url: String, pub shard: Option<(u64, u64)>, + pub merged_presences: Option, + pub users: Vec, + pub authenticator_types: Vec, + pub geo_ordered_rtc_regions: Vec, + pub api_code_version: u8, +} + +impl From for GatewayReadyBot { + fn from(value: GatewayReady) -> Self { + GatewayReadyBot { + v: value.v, + user: value.user, + guilds: value.guilds, + presences: value.presences, + sessions: value.sessions, + session_id: value.session_id, + session_type: value.session_type, + resume_gateway_url: value.resume_gateway_url, + shard: value.shard, + merged_presences: value.merged_presences, + users: value.users, + authenticator_types: value.authenticator_types, + geo_ordered_rtc_regions: value.geo_ordered_rtc_regions, + api_code_version: value.api_code_version, + } + } +} + +impl GatewayReady { + /// Convert this struct into a [GatewayReadyBot] struct + pub fn to_bot(self) -> GatewayReadyBot { + self.into() + } +} +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash)] +#[repr(u8)] +pub enum AuthenticatorType { + WebAuthn = 1, + Totp = 2, + Sms = 3, } #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// Officially Undocumented; -/// Sent after the READY event when a client is a user, +/// Sent after the READY event when a client is a user, /// seems to somehow add onto the ready event; /// /// See @@ -52,7 +135,7 @@ pub struct GatewayReadySupplemental { pub struct MergedPresences { /// "Presences of the user's guilds in the same order as the guilds array in ready" /// (discord.sex) - pub guilds: Vec>, + pub guilds: Vec>, /// "Presences of the user's friends and implicit relationships" (discord.sex) pub friends: Vec, } From f30405d1ccfbdfb2412c901732c6bf9924cf5021 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 29 Sep 2024 12:04:25 +0200 Subject: [PATCH 136/162] Add "Merging" section --- CONTRIBUTING.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 84e70210..0bad470e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,3 +10,7 @@ ever since [we streamlined the process of doing so](https://github.com/polyphony If you'd like to contribute new functionality, check out [The 'Meta'-issues.](https://github.com/polyphony-chat/chorus/issues?q=is%3Aissue+label%3A%22Type%3A+Meta%22+) They contain a comprehensive list of all features which are yet missing for full Discord.com compatibility. Please feel free to open an Issue with the idea you have, or a Pull Request. + +## Merging + +All pull requests opened into the `dev` branch should be merged via the "Squash and Merge" option to keep the commit history small. Merging into the `main` branch should be done via a regular merge commit. This way, GitHub will correctly attribute contributors and count statistics for the insights tab. From b1b0738710e6efaf6d0b9bead1da3d1a00ab374b Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 29 Sep 2024 13:26:18 +0200 Subject: [PATCH 137/162] Document all fields of GatewayReady and GatewayReadyBot --- src/types/events/ready.rs | 65 +++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/src/types/events/ready.rs b/src/types/events/ready.rs index b5aceea1..98bdaa6c 100644 --- a/src/types/events/ready.rs +++ b/src/types/events/ready.rs @@ -14,47 +14,80 @@ use crate::types::{ }; #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] -/// Received after identifying, provides initial user info +/// Received after identifying, provides initial user information and client state. /// /// See and pub struct GatewayReady { + #[serde(default)] + /// An array of stringified JSON values representing the connection trace, used for debugging + pub _trace: Vec, + /// The token used for analytical tracking requests pub analytics_token: String, + /// The hash of the auth session ID corresponding to the auth token used to connect pub auth_session_id_hash: String, + /// The detected ISO 3166-1 alpha-2 country code of the user's current IP address pub country_code: String, - pub v: u8, + #[serde(rename = "v")] + /// API version + pub api_version: u8, + /// The connected user pub user: User, #[serde(default)] + /// The guilds the user is in pub guilds: Vec, + /// The presences of the user's non-offline friends and implicit relationships (depending on the `NO_AFFINE_USER_IDS` Gateway capability). pub presences: Option>, pub sessions: Option>, + /// Unique session ID, used for resuming connections pub session_id: String, + /// The type of session that was started pub session_type: String, + /// WebSocket URL for resuming connections pub resume_gateway_url: String, + /// The shard information (shard_id, num_shards) associated with this session, if sharded pub shard: Option<(u64, u64)>, + /// The client settings for the user pub user_settings: Option, + /// The base-64 encoded preloaded user settings for the user, (if missing, defaults are used) pub user_settings_proto: Option, #[serde(default)] + /// The relationships the user has with other users pub relationships: Vec, + /// The number of friend suggestions the user has pub friend_suggestion_count: u32, #[serde(default)] + /// The DMs and group DMs the user is participating in pub private_channels: Vec, #[serde(default)] + /// A mapping of user IDs to notes the user has made for them pub notes: HashMap, + /// The presences of the user's non-offline friends and implicit relationships (depending on the `NO_AFFINE_USER_IDS` Gateway capability), and any guild presences sent at startup pub merged_presences: Option, #[serde(default)] + /// The deduped users across all objects in the event pub users: Vec, + /// The refreshed auth token for this user; if present, the client should discard the current auth token and use this in subsequent requests to the API pub auth_token: Option, #[serde(default)] + /// The types of multi-factor authenticators the user has enabled pub authenticator_types: Vec, + /// The action a user is required to take before continuing to use Discord pub required_action: Option, #[serde(default)] + /// A geo-ordered list of RTC regions that can be used when when setting a voice channel's `rtc_region` or updating the client's voice state pub geo_ordered_rtc_regions: Vec, + /// The tutorial state of the user, if any /// TODO: Make tutorial object into object pub tutorial: Option, + /// The API code version, used when re-identifying with client state v2 pub api_code_version: u8, #[serde(default)] + /// User experiment rollouts for the user + /// TODO: Make User Experiments into own struct pub experiments: Vec, #[serde(default)] + /// Guild experiment rollouts for the user + /// TODO: Make Guild Experiments into own struct pub guild_experiments: Vec, } @@ -63,30 +96,49 @@ pub struct GatewayReady { /// /// See and pub struct GatewayReadyBot { - pub v: u8, + #[serde(default)] + /// An array of stringified JSON values representing the connection trace, used for debugging + pub _trace: Vec, + #[serde(rename = "v")] + /// API version + pub api_version: u8, + /// The connected bot user pub user: User, + #[serde(default)] + /// The guilds the bot user is in. Will be `UnavailableGuilds` at first. pub guilds: Vec, + /// The presences of the user's non-offline friends and implicit relationships (depending on the `NO_AFFINE_USER_IDS` Gateway capability). pub presences: Option>, - pub sessions: Option>, + /// Unique session ID, used for resuming connections pub session_id: String, + /// The type of session that was started pub session_type: String, + /// WebSocket URL for resuming connections pub resume_gateway_url: String, + /// The shard information (shard_id, num_shards) associated with this session, if sharded pub shard: Option<(u64, u64)>, + /// The presences of the user's non-offline friends and implicit relationships (depending on the `NO_AFFINE_USER_IDS` Gateway capability), and any guild presences sent at startup pub merged_presences: Option, + #[serde(default)] + /// The deduped users across all objects in the event pub users: Vec, + #[serde(default)] + /// The types of multi-factor authenticators the user has enabled pub authenticator_types: Vec, + #[serde(default)] + /// A geo-ordered list of RTC regions that can be used when when setting a voice channel's `rtc_region` or updating the client's voice state pub geo_ordered_rtc_regions: Vec, + /// The API code version, used when re-identifying with client state v2 pub api_code_version: u8, } impl From for GatewayReadyBot { fn from(value: GatewayReady) -> Self { GatewayReadyBot { - v: value.v, + api_version: value.api_version, user: value.user, guilds: value.guilds, presences: value.presences, - sessions: value.sessions, session_id: value.session_id, session_type: value.session_type, resume_gateway_url: value.resume_gateway_url, @@ -96,6 +148,7 @@ impl From for GatewayReadyBot { authenticator_types: value.authenticator_types, geo_ordered_rtc_regions: value.geo_ordered_rtc_regions, api_code_version: value.api_code_version, + _trace: value._trace, } } } From 7f0865b83731ef0a6caa266fc2268804cb7c7b97 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 29 Sep 2024 15:13:35 +0200 Subject: [PATCH 138/162] Fix PostgreSQL compatibility of READY and some newer enum types --- src/types/entities/user.rs | 23 ++++++++++++----------- src/types/events/ready.rs | 18 ++++++++++-------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index 9c7c3b9d..bd74a8cb 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -7,7 +7,7 @@ use crate::types::utils::Snowflake; use crate::{UInt32, UInt8}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use serde_aux::prelude::{deserialize_option_number_from_string, deserialize_default_from_null}; +use serde_aux::prelude::{deserialize_default_from_null, deserialize_option_number_from_string}; use serde_repr::{Deserialize_repr, Serialize_repr}; use std::array::TryFromSliceError; use std::fmt::Debug; @@ -234,7 +234,8 @@ bitflags::bitflags! { Ord, )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// **User** premium (Nitro) type /// @@ -258,9 +259,9 @@ pub struct UserProfileMetadata { /// The guild ID this profile applies to, if it is a guild profile. pub guild_id: Option, /// The user's pronouns, up to 40 characters - #[serde(deserialize_with = "deserialize_default_from_null")] - // Note: spacebar will send this is as null, while it should be "" - // See issue 1188 + #[serde(deserialize_with = "deserialize_default_from_null")] + // Note: spacebar will send this is as null, while it should be "" + // See issue 1188 pub pronouns: String, /// The user's bio / description, up to 190 characters pub bio: Option, @@ -847,13 +848,13 @@ pub struct PremiumUsageData { } impl From for usize { - fn from(value: PremiumUsageData) -> Self { - value.value - } + fn from(value: PremiumUsageData) -> Self { + value.value + } } impl From for PremiumUsageData { - fn from(value: usize) -> Self { - PremiumUsageData { value } - } + fn from(value: usize) -> Self { + PremiumUsageData { value } + } } diff --git a/src/types/events/ready.rs b/src/types/events/ready.rs index 98bdaa6c..d8c11de1 100644 --- a/src/types/events/ready.rs +++ b/src/types/events/ready.rs @@ -12,6 +12,7 @@ use crate::types::{ Activity, Channel, ClientStatusObject, GuildMember, PresenceUpdate, Relationship, Snowflake, UserSettings, VoiceState, }; +use crate::{UInt32, UInt64, UInt8}; #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// Received after identifying, provides initial user information and client state. @@ -29,7 +30,7 @@ pub struct GatewayReady { pub country_code: String, #[serde(rename = "v")] /// API version - pub api_version: u8, + pub api_version: UInt8, /// The connected user pub user: User, #[serde(default)] @@ -45,7 +46,7 @@ pub struct GatewayReady { /// WebSocket URL for resuming connections pub resume_gateway_url: String, /// The shard information (shard_id, num_shards) associated with this session, if sharded - pub shard: Option<(u64, u64)>, + pub shard: Option<(UInt64, UInt64)>, /// The client settings for the user pub user_settings: Option, /// The base-64 encoded preloaded user settings for the user, (if missing, defaults are used) @@ -54,7 +55,7 @@ pub struct GatewayReady { /// The relationships the user has with other users pub relationships: Vec, /// The number of friend suggestions the user has - pub friend_suggestion_count: u32, + pub friend_suggestion_count: UInt32, #[serde(default)] /// The DMs and group DMs the user is participating in pub private_channels: Vec, @@ -80,7 +81,7 @@ pub struct GatewayReady { /// TODO: Make tutorial object into object pub tutorial: Option, /// The API code version, used when re-identifying with client state v2 - pub api_code_version: u8, + pub api_code_version: UInt8, #[serde(default)] /// User experiment rollouts for the user /// TODO: Make User Experiments into own struct @@ -101,7 +102,7 @@ pub struct GatewayReadyBot { pub _trace: Vec, #[serde(rename = "v")] /// API version - pub api_version: u8, + pub api_version: UInt8, /// The connected bot user pub user: User, #[serde(default)] @@ -116,7 +117,7 @@ pub struct GatewayReadyBot { /// WebSocket URL for resuming connections pub resume_gateway_url: String, /// The shard information (shard_id, num_shards) associated with this session, if sharded - pub shard: Option<(u64, u64)>, + pub shard: Option<(UInt64, UInt64)>, /// The presences of the user's non-offline friends and implicit relationships (depending on the `NO_AFFINE_USER_IDS` Gateway capability), and any guild presences sent at startup pub merged_presences: Option, #[serde(default)] @@ -129,7 +130,7 @@ pub struct GatewayReadyBot { /// A geo-ordered list of RTC regions that can be used when when setting a voice channel's `rtc_region` or updating the client's voice state pub geo_ordered_rtc_regions: Vec, /// The API code version, used when re-identifying with client state v2 - pub api_code_version: u8, + pub api_code_version: UInt8, } impl From for GatewayReadyBot { @@ -160,7 +161,8 @@ impl GatewayReady { } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash)] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] pub enum AuthenticatorType { WebAuthn = 1, Totp = 2, From f06929fded37a3e6a09418835fc4e05fb03f7b3c Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 29 Sep 2024 15:13:43 +0200 Subject: [PATCH 139/162] update Cargo.lock --- Cargo.lock | 260 ++++++++++++++++++++++++----------------------------- 1 file changed, 118 insertions(+), 142 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 974a8dc7..7fd179fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,19 +4,13 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -77,13 +71,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -114,23 +108,23 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -209,15 +203,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "cc" -version = "1.1.15" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" dependencies = [ "shlex", ] @@ -276,7 +270,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-bindgen-test", "wasmtimer", - "webpki-roots 0.26.5", + "webpki-roots 0.26.6", "ws_stream_wasm", ] @@ -286,7 +280,7 @@ version = "0.5.0" dependencies = [ "async-trait", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -358,9 +352,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -457,7 +451,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -468,7 +462,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -590,12 +584,12 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -691,7 +685,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -750,9 +744,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "h2" @@ -1025,9 +1019,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", "futures-util", @@ -1040,9 +1034,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1110,9 +1104,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" [[package]] name = "ipnetwork" @@ -1163,9 +1157,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libm" @@ -1260,15 +1254,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -1422,9 +1407,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -1444,7 +1429,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.3", + "redox_syscall", "smallvec", "windows-targets 0.52.6", ] @@ -1524,9 +1509,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "pnet_base" @@ -1560,9 +1545,9 @@ dependencies = [ [[package]] name = "poem" -version = "3.0.4" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1ba1c27f8f89e1bccdda0c680f72790545a11a8d8555819472f5839d7a8ca9d" +checksum = "e5419c612a492fce4961c521dca0c2249b5c48dc46eb5c8048063843f37a711d" dependencies = [ "bytes", "futures-util", @@ -1594,14 +1579,14 @@ dependencies = [ [[package]] name = "poem-derive" -version = "3.0.4" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62fea1692d80a000126f9b28d865012a160b80000abb53ccf152b428222c155" +checksum = "cdfed15c1102d2a9a51b9f1aba945628c72ccb52fc5d3e4ad4ffbbd222e11821" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1698,18 +1683,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" dependencies = [ "bitflags 2.6.0", ] @@ -1861,9 +1837,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.35" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -1886,14 +1862,14 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "once_cell", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.7", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -1919,9 +1895,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" [[package]] name = "rustls-webpki" @@ -1935,9 +1911,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.7" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -2004,9 +1980,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -2024,20 +2000,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -2053,7 +2029,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2095,7 +2071,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2213,9 +2189,9 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" dependencies = [ "nom", "unicode_categories", @@ -2223,9 +2199,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcfa89bea9500db4a0d038513d7a060566bfc51d46d1c014847049a45cce85e8" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2236,9 +2212,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06e2f2bd861719b1f3f0c7dbe1d80c30bf59e76cf019f07d9014ed7eefb8e08" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" dependencies = [ "atoi", "bigdecimal", @@ -2264,7 +2240,7 @@ dependencies = [ "once_cell", "paste", "percent-encoding", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pemfile 2.1.3", "serde", "serde_json", @@ -2276,27 +2252,27 @@ dependencies = [ "tokio-stream", "tracing", "url", - "webpki-roots 0.26.5", + "webpki-roots 0.26.6", ] [[package]] name = "sqlx-macros" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f998a9defdbd48ed005a89362bd40dd2117502f15294f61c8d47034107dbbdc" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "sqlx-macros-core" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d100558134176a2629d46cec0c8891ba0be8910f7896abfdb75ef4ab6f4e7ce" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" dependencies = [ "dotenvy", "either", @@ -2312,7 +2288,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.77", + "syn 2.0.79", "tempfile", "tokio", "url", @@ -2320,9 +2296,9 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cac0ab331b14cb3921c62156d913e4c15b74fb6ec0f3146bd4ef6e4fb3c12" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", "base64 0.22.1", @@ -2382,14 +2358,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e527060e9f43479e5b386e4237ab320a36fce39394f6ed73c8870f4637f2e5f" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "sqlx-postgres" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9734dbce698c67ecf67c442f768a5e90a49b2a4d61a9f1d59f73874bd4cf0710" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", "base64 0.22.1", @@ -2429,9 +2405,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75b419c3c1b1697833dd927bdc4c6545a620bc1bbafabd44e1efbe9afcd337e" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" dependencies = [ "atoi", "chrono", @@ -2487,9 +2463,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -2534,9 +2510,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -2547,22 +2523,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2635,7 +2611,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2650,9 +2626,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -2676,9 +2652,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -2695,9 +2671,9 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap 2.5.0", "toml_datetime", @@ -2730,7 +2706,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2800,15 +2776,15 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] @@ -2929,7 +2905,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-shared", ] @@ -2963,7 +2939,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2997,7 +2973,7 @@ checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3032,20 +3008,20 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.5" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] [[package]] name = "whoami" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.4.1", + "redox_syscall", "wasite", ] @@ -3245,9 +3221,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -3299,7 +3275,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] From 490e421f76e6c7552211b215da18f5d496176300 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 29 Sep 2024 22:46:30 +0200 Subject: [PATCH 140/162] Bump sqlx and sqlx-pg-uint --- Cargo.lock | 4 ++-- Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7fd179fe..067322f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2340,9 +2340,9 @@ dependencies = [ [[package]] name = "sqlx-pg-uint" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1c03c61ff481e8dfca7e5fef11245378c2b27cd7f0d45096d360a7adbb07391" +checksum = "60e5ec2fd2d274ebf9ad6b44b3986f9bcdbb554bb162c4b1ac4af05a439c66f2" dependencies = [ "bigdecimal", "serde", diff --git a/Cargo.toml b/Cargo.toml index 359d20fb..031aeff1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ jsonwebtoken = "8.3.0" log = "0.4.22" async-trait = "0.1.81" chorus-macros = { path = "./chorus-macros", version = "0" } # Note: version here is used when releasing. This will use the latest release. Make sure to republish the crate when code in macros is changed! -sqlx = { version = "0.8.1", features = [ +sqlx = { version = "0.8.2", features = [ "json", "chrono", "ipnetwork", @@ -67,7 +67,7 @@ rand = "0.8.5" flate2 = { version = "1.0.33", optional = true } webpki-roots = "0.26.3" pubserve = { version = "1.1.0", features = ["async", "send"] } -sqlx-pg-uint = { version = "0.7.1", features = ["serde"], optional = true } +sqlx-pg-uint = { version = "0.7.2", features = ["serde"], optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] rustls = "0.21.12" From 07c5530fece461b5f7375d77ce66f9e6219ae9af Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Mon, 30 Sep 2024 23:12:47 +0200 Subject: [PATCH 141/162] Adjust premium_type field to be of type PremiumType (#563) --- src/types/config/types/subconfigs/defaults/user.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/types/config/types/subconfigs/defaults/user.rs b/src/types/config/types/subconfigs/defaults/user.rs index a533b0ac..982507ea 100644 --- a/src/types/config/types/subconfigs/defaults/user.rs +++ b/src/types/config/types/subconfigs/defaults/user.rs @@ -4,11 +4,13 @@ use serde::{Deserialize, Serialize}; +use crate::types::PremiumType; + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, Hash, PartialOrd, Ord)] #[serde(rename_all = "camelCase")] pub struct UserDefaults { pub premium: bool, - pub premium_type: u8, + pub premium_type: PremiumType, pub verified: bool, } @@ -16,7 +18,7 @@ impl Default for UserDefaults { fn default() -> Self { Self { premium: true, - premium_type: 2, + premium_type: PremiumType::Tier2, verified: true, } } From b87df594845f34d92cf30c6fc111cefe0b92de9d Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Mon, 7 Oct 2024 21:38:33 +0200 Subject: [PATCH 142/162] Implement custom sqlx::Postgres en-/decoding for PremiumType enum (#565) --- src/types/entities/user.rs | 48 +++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index bd74a8cb..5e761307 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -233,9 +233,7 @@ bitflags::bitflags! { PartialOrd, Ord, )] -#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[cfg_attr(not(feature = "sqlx"), repr(u8))] -#[cfg_attr(feature = "sqlx", repr(i16))] +#[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// **User** premium (Nitro) type /// @@ -252,6 +250,50 @@ pub enum PremiumType { Tier3 = 3, } +impl TryFrom for PremiumType { + type Error = ChorusError; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::None), + 1 => Ok(Self::Tier1), + 2 => Ok(Self::Tier2), + 3 => Ok(Self::Tier3), + _ => Err(ChorusError::InvalidArguments { + error: "Value is not a valid PremiumType".to_string(), + }), + } + } +} + +#[cfg(feature = "sqlx")] +impl sqlx::Type for PremiumType { + fn type_info() -> ::TypeInfo { + >::type_info() + } +} + +#[cfg(feature = "sqlx")] +impl<'q> sqlx::Encode<'q, sqlx::Postgres> for PremiumType { + fn encode_by_ref( + &self, + buf: &mut ::ArgumentBuffer<'q>, + ) -> Result { + let sqlx_pg_uint = sqlx_pg_uint::PgU8::from(*self as u8); + sqlx_pg_uint.encode_by_ref(buf) + } +} + +#[cfg(feature = "sqlx")] +impl<'r> sqlx::Decode<'r, sqlx::Postgres> for PremiumType { + fn decode( + value: ::ValueRef<'r>, + ) -> Result { + let sqlx_pg_uint = sqlx_pg_uint::PgU8::decode(value)?; + PremiumType::try_from(sqlx_pg_uint.to_uint()).map_err(|e| e.into()) + } +} + #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] /// # Reference /// See From 515750c2a6f9346e699d74f35073c479ab2b90d9 Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Tue, 8 Oct 2024 15:37:35 +0200 Subject: [PATCH 143/162] Make Relationship struct sqlx/symfonia-ready (#567) --- src/types/entities/relationship.rs | 60 +++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/types/entities/relationship.rs b/src/types/entities/relationship.rs index 08cb41f1..e6d14f42 100644 --- a/src/types/entities/relationship.rs +++ b/src/types/entities/relationship.rs @@ -6,18 +6,28 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; +use crate::errors::ChorusError; use crate::types::{Shared, Snowflake}; use super::{arc_rwlock_ptr_eq, PublicUser}; #[derive(Debug, Deserialize, Serialize, Clone, Default)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] /// See pub struct Relationship { + /// The ID of the target user + #[cfg_attr(feature = "sqlx", sqlx(rename = "to_id"))] pub id: Snowflake, #[serde(rename = "type")] + #[cfg_attr(feature = "sqlx", sqlx(rename = "type"))] pub relationship_type: RelationshipType, + #[cfg_attr(feature = "sqlx", sqlx(skip))] // Can be derived from the user id + /// The nickname of the user in this relationship pub nickname: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] // Can be derived from the user id + /// The target user pub user: Shared, + /// When the user requested a relationship pub since: Option>, } @@ -45,8 +55,7 @@ impl PartialEq for Relationship { Copy, Hash, )] -#[cfg_attr(not(feature = "sqlx"), repr(u8))] -#[cfg_attr(feature = "sqlx", repr(i16))] +#[repr(u8)] /// See pub enum RelationshipType { Suggestion = 6, @@ -58,3 +67,50 @@ pub enum RelationshipType { Friends = 1, None = 0, } + +#[cfg(feature = "sqlx")] +impl sqlx::Type for RelationshipType { + fn type_info() -> ::TypeInfo { + >::type_info() + } +} + +#[cfg(feature = "sqlx")] +impl<'q> sqlx::Encode<'q, sqlx::Postgres> for RelationshipType { + fn encode_by_ref( + &self, + buf: &mut ::ArgumentBuffer<'q>, + ) -> Result { + let sqlx_pg_uint = sqlx_pg_uint::PgU8::from(*self as u8); + sqlx_pg_uint.encode_by_ref(buf) + } +} + +#[cfg(feature = "sqlx")] +impl<'r> sqlx::Decode<'r, sqlx::Postgres> for RelationshipType { + fn decode( + value: ::ValueRef<'r>, + ) -> Result { + let sqlx_pg_uint = sqlx_pg_uint::PgU8::decode(value)?; + Self::try_from(sqlx_pg_uint.to_uint()).map_err(|e| e.into()) + } +} + +impl TryFrom for RelationshipType { + type Error = ChorusError; + + fn try_from(value: u8) -> Result { + match value { + 6 => Ok(Self::Suggestion), + 5 => Ok(Self::Implicit), + 4 => Ok(Self::Outgoing), + 3 => Ok(Self::Incoming), + 2 => Ok(Self::Blocked), + 1 => Ok(Self::Friends), + 0 => Ok(Self::None), + _ => Err(ChorusError::InvalidArguments { + error: format!("Value {} is not a valid RelationshipType", value), + }), + } + } +} From c52012e55b3f12960b570414c2719c94bc75090e Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 8 Oct 2024 17:18:39 +0200 Subject: [PATCH 144/162] #567: Append: Nickname *cannot* be derived from user id --- src/types/entities/relationship.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/types/entities/relationship.rs b/src/types/entities/relationship.rs index e6d14f42..da2a9dc7 100644 --- a/src/types/entities/relationship.rs +++ b/src/types/entities/relationship.rs @@ -21,7 +21,6 @@ pub struct Relationship { #[serde(rename = "type")] #[cfg_attr(feature = "sqlx", sqlx(rename = "type"))] pub relationship_type: RelationshipType, - #[cfg_attr(feature = "sqlx", sqlx(skip))] // Can be derived from the user id /// The nickname of the user in this relationship pub nickname: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] // Can be derived from the user id From 7b50d56783c306b3eab0887b380bc0120beab7aa Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Sun, 28 Apr 2024 14:15:57 +0200 Subject: [PATCH 145/162] Move Shared to types/mod.rs, bump some dependencies (#492) * deps: bump rustls to 0.21.11 This is done to fix CVE-2024-32650, which practically shouldn't affect us but it's still better not to use vulnerable dependencies. * deps: bump h2 to 0.3.26 This is done to fix another vulnerability, which should also not affect us (non-critical, in h2 servers) * fix: move Shared to types/mod.rs --- src/types/entities/integration.rs | 1 + src/types/entities/message.rs | 1 + src/types/entities/template.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/src/types/entities/integration.rs b/src/types/entities/integration.rs index 50a82819..b119e55c 100644 --- a/src/types/entities/integration.rs +++ b/src/types/entities/integration.rs @@ -6,6 +6,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::types::{ + Shared, entities::{Application, User}, utils::Snowflake, Shared, diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index b63eb3bf..3fd7b43f 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; use crate::types::{ + Shared, entities::{ Application, Attachment, Channel, Emoji, GuildMember, PublicUser, RoleSubscriptionData, Sticker, StickerItem, User, diff --git a/src/types/entities/template.rs b/src/types/entities/template.rs index 29e53689..f95bb574 100644 --- a/src/types/entities/template.rs +++ b/src/types/entities/template.rs @@ -6,6 +6,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::types::{ + Shared, entities::{Guild, User}, utils::Snowflake, Shared, From 673181e8f316516f79396949cb8d7743c98ba841 Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Sun, 5 May 2024 14:43:23 +0200 Subject: [PATCH 146/162] Refactor / fix login and register (#495) Change login and register to only use one ChorusUser object, change the api of related methods which were also somewhat ugly Feature lock different types for UserSettings::status Add sqlx::FromRow derive to GuildMember Use Snowflake in Claims Use ChannelType enum on ChannelModifySchema Add From> impl for GuildFeaturesList Add feature sqlx locks for user, roles on GuildMember Use distinct type for explicit_content_filter Revert c4452132 Fix errors in documentation tests update dev-dependencies Expand documentation to explain facade type Fix oversight for premium_since Add sqlx Type, Encode, Decode impl for InviteFlags bitflag object. Fix inverted type wrapping Remove unused imports, feature locks in macro forgot a file :( Fix test I feel silly. Fix compilation for real, no dirty hack u8 -> u64 --- Cargo.toml | 6 ++++++ src/api/auth/login.rs | 10 ++++++++++ src/api/auth/mod.rs | 6 ++++++ src/api/auth/register.rs | 10 ++++++++++ src/api/users/users.rs | 8 ++++++++ src/types/schema/channel.rs | 23 +++++++++++++++++++++++ src/types/utils/serde.rs | 12 ++++++------ 7 files changed, 69 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6d4830ed..42e23836 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,6 +84,7 @@ wasm-bindgen-futures = "0.4.43" wasmtimer = "0.2.0" [dev-dependencies] +<<<<<<< HEAD lazy_static = "1.5.0" wasm-bindgen-test = "0.3.43" wasm-bindgen = "0.2.93" @@ -91,3 +92,8 @@ simple_logger = { version = "5.0.0", default-features = false } [lints.rust] unexpected_cfgs = { level = "allow", check-cfg = ['cfg(tarpaulin_include)'] } +======= +lazy_static = "1.4.0" +wasm-bindgen-test = "0.3.42" +wasm-bindgen = "0.2.92" +>>>>>>> 50c5c29 (update dev-dependencies) diff --git a/src/api/auth/login.rs b/src/api/auth/login.rs index 3a9a9eeb..1af19e05 100644 --- a/src/api/auth/login.rs +++ b/src/api/auth/login.rs @@ -30,12 +30,22 @@ impl Instance { // We do not have a user yet, and the UserRateLimits will not be affected by a login // request (since login is an instance wide limit), which is why we are just cloning the // instances' limits to pass them on as user_rate_limits later. +<<<<<<< HEAD let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None").await; let login_result = chorus_request .deserialize_response::(&mut user) .await?; user.set_token(&login_result.token); +======= + let mut user = + ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None".to_string()).await; + + let login_result = chorus_request + .deserialize_response::(&mut user) + .await?; + user.set_token(login_result.token); +>>>>>>> 03f1e7d (Refactor / fix login and register (#495)) user.settings = login_result.settings; let object = User::get(&mut user, None).await?; diff --git a/src/api/auth/mod.rs b/src/api/auth/mod.rs index b9050e14..7aaf13f5 100644 --- a/src/api/auth/mod.rs +++ b/src/api/auth/mod.rs @@ -22,8 +22,14 @@ pub mod register; impl Instance { /// Logs into an existing account on the spacebar server, using only a token. +<<<<<<< HEAD pub async fn login_with_token(&mut self, token: &str) -> ChorusResult { let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await; +======= + pub async fn login_with_token(&mut self, token: String) -> ChorusResult { + let mut user = + ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await; +>>>>>>> 03f1e7d (Refactor / fix login and register (#495)) let object = User::get(&mut user, None).await?; let settings = User::get_settings(&mut user).await?; diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs index 821a52ff..532a65c6 100644 --- a/src/api/auth/register.rs +++ b/src/api/auth/register.rs @@ -37,13 +37,23 @@ impl Instance { // We do not have a user yet, and the UserRateLimits will not be affected by a login // request (since register is an instance wide limit), which is why we are just cloning // the instances' limits to pass them on as user_rate_limits later. +<<<<<<< HEAD let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None").await; +======= + let mut user = + ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None".to_string()).await; + +>>>>>>> 03f1e7d (Refactor / fix login and register (#495)) let token = chorus_request .deserialize_response::(&mut user) .await? .token; +<<<<<<< HEAD user.set_token(&token); +======= + user.set_token(token); +>>>>>>> 03f1e7d (Refactor / fix login and register (#495)) let object = User::get(&mut user, None).await?; let settings = User::get_settings(&mut user).await?; diff --git a/src/api/users/users.rs b/src/api/users/users.rs index 4f6ef579..3f43efbf 100644 --- a/src/api/users/users.rs +++ b/src/api/users/users.rs @@ -32,7 +32,11 @@ impl ChorusUser { /// # Notes /// This function is a wrapper around [`User::get_settings`]. pub async fn get_settings(&mut self) -> ChorusResult { +<<<<<<< HEAD User::get_settings(self).await +======= + User::get_settings(self).await +>>>>>>> 03f1e7d (Refactor / fix login and register (#495)) } /// Modifies the current user's representation. (See [`User`]) @@ -138,3 +142,7 @@ impl User { } } } +<<<<<<< HEAD +======= + +>>>>>>> 03f1e7d (Refactor / fix login and register (#495)) diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 62b3b53a..fea2545a 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -138,6 +138,29 @@ bitflags! { } } +#[cfg(feature = "sqlx")] +impl sqlx::Type for InviteFlags { + fn type_info() -> sqlx::mysql::MySqlTypeInfo { + u64::type_info() + } +} + +#[cfg(feature = "sqlx")] +impl<'q> sqlx::Encode<'q, sqlx::MySql> for InviteFlags { + fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { + u64::encode_by_ref(&self.0.0, buf) + } +} + +#[cfg(feature = "sqlx")] +impl<'r> sqlx::Decode<'r, sqlx::MySql> for InviteFlags { + fn decode(value: >::ValueRef) -> Result { + let raw = u64::decode(value)?; + + Ok(Self::from_bits(raw).unwrap()) + } +} + #[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] diff --git a/src/types/utils/serde.rs b/src/types/utils/serde.rs index da41f4ac..f682bb0b 100644 --- a/src/types/utils/serde.rs +++ b/src/types/utils/serde.rs @@ -32,7 +32,7 @@ pub struct SecondsStringTimestampVisitor; /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// // Ok::<(), serde_json::Error>(()) /// ``` pub mod ts_seconds_str { @@ -64,7 +64,7 @@ pub mod ts_seconds_str { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); - /// # Ok::<(), serde_json::Error>(()) + /// // Ok::<(), serde_json::Error>(()) /// ``` pub fn serialize(dt: &DateTime, serializer: S) -> Result where @@ -91,7 +91,7 @@ pub mod ts_seconds_str { /// /// let my_s: S = serde_json::from_str(r#"{ "time": "1431684000" }"#)?; /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).unwrap() }); - /// # Ok::<(), serde_json::Error>(()) + /// // Ok::<(), serde_json::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -145,7 +145,7 @@ pub mod ts_seconds_str { /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// # Ok::<(), serde_json::Error>(()) +/// // Ok::<(), serde_json::Error>(()) /// ``` pub mod ts_seconds_option_str { use super::SecondsStringTimestampVisitor; @@ -174,7 +174,7 @@ pub mod ts_seconds_option_str { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); - /// # Ok::<(), serde_json::Error>(()) + /// // Ok::<(), serde_json::Error>(()) /// ``` pub fn serialize(opt: &Option>, serializer: S) -> Result where @@ -204,7 +204,7 @@ pub mod ts_seconds_option_str { /// /// let my_s: S = serde_json::from_str(r#"{ "time": "1431684000" }"#)?; /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).single() }); - /// # Ok::<(), serde_json::Error>(()) + /// // Ok::<(), serde_json::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where From f5c4fc39249d09ffbb203fe3caa700d3ba32e7f4 Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Sun, 23 Jun 2024 17:23:13 +0200 Subject: [PATCH 147/162] Implement gateway options, zlib-stream compression (#508) * feat: add GatewayOptions * feat: implement zlib-stream compression This also changes how gateway messages work. Now each gateway backend converts its message into an intermediary RawGatewayMessage, from which we inflate and parse GatewayMessages. Thanks to ByteAlex and their zlib-stream-rs crate, which helped me understand how to parse a compressed websocket stream --- Cargo.lock | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 2d79f4a4..f36d5a4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -598,6 +598,16 @@ dependencies = [ "miniz_oxide 0.8.0", ] +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "flume" version = "0.11.0" From 17e46db3bec6d455670c329b5c2ac5a16417aa9e Mon Sep 17 00:00:00 2001 From: Quat3rnion <81202811+Quat3rnion@users.noreply.github.com> Date: Thu, 27 Jun 2024 02:45:51 -0400 Subject: [PATCH 148/162] Backend/guilds (#509) * Fix SQL encode/decode for GuildFeatures * Use distinct PermissionFlags type * Add Emoji schema types, modify GuildBan with feature lock * Add Schemas for pruning guild members * Add schemas for interfacing with stickers backend routes * Add schemas for interfacing with vanity-url backend routes * Add schema for interfacing with guilds/id/welcome-screen route * Make all Option types Vec types with #[serde(default)] * Add various types to support guilds/* api routes * Add missing enums and structs for searching messages * Use proper distinct types * Add EmbedType enum * Use distinct PermissionFlags type * Changes supporting backend for VoiceState * Changes supporting backend for AuditLog's Fix voice, voice_udp features Add one BILLION derives Fix: Wrong function name Fix: Turn unconditional import of sqlx::types::Json into conditional one Fix: Compile error with no default features Update CONTRIBUTING.md Fix/Correct UnavailableGuild object Fix testcase that relied on false behavior implemented by older spacebar servers Increase limit integer size to match spacebars' possibilities forgor installing nextest Bump browser_version according to https://www.useragents.me/#most-common-desktop-useragents Fix voice_simple example Update documentation in gateway_observers example Readd Observer trait as reexport remove cargo lock from example More accurate "GatewayHello::default()" Manually implement std::default::Default for GatewayHeartbeat and GatewayHeartbeatAck bump versions of packages to latest compatible versions --- .github/workflows/build_and_test.yml | 2 ++ Cargo.lock | 14 ++++++++++++++ Cargo.toml | 27 +++++++++++++++++++++++++++ src/types/entities/integration.rs | 1 - src/types/entities/message.rs | 3 ++- src/types/schema/role.rs | 1 + 6 files changed, 46 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 547e2e83..b9cebea5 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -97,6 +97,7 @@ jobs: with: cache-all-crates: "true" prefix-key: "macos" + - uses: taiki-e/install-action@nextest - name: Run WASM tests with Safari, Firefox, Chrome run: | rustup target add wasm32-unknown-unknown @@ -126,6 +127,7 @@ jobs: with: cache-all-crates: "true" prefix-key: "macos" + - uses: taiki-e/install-action@nextest - name: Run WASM tests with Safari, Firefox, Chrome run: | rustup target add wasm32-unknown-unknown diff --git a/Cargo.lock b/Cargo.lock index f36d5a4f..f9e2ec43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1280,6 +1280,7 @@ dependencies = [ ] [[package]] +<<<<<<< HEAD name = "miniz_oxide" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1294,6 +1295,13 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ +======= +name = "mio" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +dependencies = [ +>>>>>>> f2f45b4 (bump versions of packages to latest compatible versions) "hermit-abi", "libc", "wasi", @@ -2623,9 +2631,15 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" +<<<<<<< HEAD version = "1.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +======= +version = "1.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +>>>>>>> f2f45b4 (bump versions of packages to latest compatible versions) dependencies = [ "backtrace", "bytes", diff --git a/Cargo.toml b/Cargo.toml index 42e23836..6c35eb39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,15 @@ voice_gateway = [] sqlx-pg-uint = ["dep:sqlx-pg-uint", "sqlx-pg-uint/serde"] [dependencies] +<<<<<<< HEAD tokio = { version = "1.39.3", features = ["macros", "sync"] } serde = { version = "1.0.209", features = ["derive", "rc"] } serde_json = { version = "1.0.127", features = ["raw_value"] } +======= +tokio = { version = "1.38.1", features = ["macros", "sync"] } +serde = { version = "1.0.204", features = ["derive", "rc"] } +serde_json = { version = "1.0.120", features = ["raw_value"] } +>>>>>>> f2f45b4 (bump versions of packages to latest compatible versions) serde-aux = "4.5.0" serde_with = "3.9.0" serde_repr = "0.1.19" @@ -36,7 +42,11 @@ reqwest = { features = [ ], version = "=0.11.26", default-features = false } url = "2.5.2" chrono = { version = "0.4.38", features = ["serde"] } +<<<<<<< HEAD regex = "1.10.6" +======= +regex = "1.10.5" +>>>>>>> f2f45b4 (bump versions of packages to latest compatible versions) custom_error = "1.9.2" futures-util = "0.3.30" http = "0.2.12" @@ -49,7 +59,13 @@ jsonwebtoken = "8.3.0" log = "0.4.22" async-trait = "0.1.81" chorus-macros = { path = "./chorus-macros", version = "0" } # Note: version here is used when releasing. This will use the latest release. Make sure to republish the crate when code in macros is changed! +<<<<<<< HEAD sqlx = { version = "0.8.1", features = [ +======= +sqlx = { version = "0.7.4", features = [ + "mysql", + "sqlite", +>>>>>>> f2f45b4 (bump versions of packages to latest compatible versions) "json", "chrono", "ipnetwork", @@ -67,7 +83,10 @@ rand = "0.8.5" flate2 = { version = "1.0.33", optional = true } webpki-roots = "0.26.3" pubserve = { version = "1.1.0", features = ["async", "send"] } +<<<<<<< HEAD sqlx-pg-uint = { version = "0.5.0", features = ["serde"], optional = true } +======= +>>>>>>> f2f45b4 (bump versions of packages to latest compatible versions) [target.'cfg(not(target_arch = "wasm32"))'.dependencies] rustls = "0.21.12" @@ -80,6 +99,7 @@ getrandom = { version = "0.2.15" } [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2.15", features = ["js"] } ws_stream_wasm = "0.7.4" +<<<<<<< HEAD wasm-bindgen-futures = "0.4.43" wasmtimer = "0.2.0" @@ -94,6 +114,13 @@ simple_logger = { version = "5.0.0", default-features = false } unexpected_cfgs = { level = "allow", check-cfg = ['cfg(tarpaulin_include)'] } ======= lazy_static = "1.4.0" +======= +wasm-bindgen-futures = "0.4.42" +wasmtimer = "0.2.0" + +[dev-dependencies] +lazy_static = "1.5.0" +>>>>>>> f2f45b4 (bump versions of packages to latest compatible versions) wasm-bindgen-test = "0.3.42" wasm-bindgen = "0.2.92" >>>>>>> 50c5c29 (update dev-dependencies) diff --git a/src/types/entities/integration.rs b/src/types/entities/integration.rs index b119e55c..50a82819 100644 --- a/src/types/entities/integration.rs +++ b/src/types/entities/integration.rs @@ -6,7 +6,6 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::types::{ - Shared, entities::{Application, User}, utils::Snowflake, Shared, diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index 3fd7b43f..ef7f392e 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -8,7 +8,6 @@ use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; use crate::types::{ - Shared, entities::{ Application, Attachment, Channel, Emoji, GuildMember, PublicUser, RoleSubscriptionData, Sticker, StickerItem, User, @@ -20,6 +19,8 @@ use crate::{UInt32, UInt8}; use super::option_arc_rwlock_ptr_eq; +use super::option_arc_rwlock_ptr_eq; + #[derive(Debug, Serialize, Deserialize, Default, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] /// Represents a message sent in a channel. diff --git a/src/types/schema/role.rs b/src/types/schema/role.rs index 805d0263..17292fea 100644 --- a/src/types/schema/role.rs +++ b/src/types/schema/role.rs @@ -4,6 +4,7 @@ use crate::types::{PermissionFlags, Snowflake}; use serde::{Deserialize, Serialize}; +use crate::types::{PermissionFlags, Snowflake}; #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] #[serde(rename_all = "snake_case")] From b6ca485b8226604613d34bfad810492d84a12ae0 Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Wed, 21 Aug 2024 23:43:42 +0200 Subject: [PATCH 149/162] Initial support for PostgreSQL (#548) * Change sqlx::Any to sqlx::Postgres * Change sqlx::Any to sqlx::Postgres * Remove JSONified overrides when sqlx feature is enabled, where it makes sense * Add num-bigint dep * Remove generic impl for From for Snowflake For some reason, this trait bound conflicts with another trait bound from the sqlx-pg-uint crate, even though I personally don't get why. * Remove num_bigint, adsd sqlx-pg-uint * swap u64 for PgU64 in some files * use v0.3.0 of sqlx-pg-uint * Lots of sqlx-postgres type changes * Lots of sqlx-postgres type changes * gwah * Change repr(i8) to repr(i16) in enums when sqlx feature is enabled, fix sqlx incompatibilities * impl sqlx::postgres::PgHasArrayType for Snowflake * Try: derive Type for FriendSourceFlags, GuildFolder * Try: Derive FromRow, Type for DefaultReaction * Try: Derive Type for CustomStatus * Try: Derive Type, FromRow for Tag * Replace conditional compiling of uNN/PgUNN with conditional compiled type alias * Fix: Conditional compiling errors and warnings * Bump: wasm-bindgen* crate versions Uncomment and update decode_token() Add missing `impl From for u64`, closes `From for u64` missing #550 Update README.md move up sending identify Revert d846ce9948ebb07988428250d6a02d2ea920a451 Bump version to v0.16.0 --- src/types/entities/template.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/types/entities/template.rs b/src/types/entities/template.rs index f95bb574..29e53689 100644 --- a/src/types/entities/template.rs +++ b/src/types/entities/template.rs @@ -6,7 +6,6 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::types::{ - Shared, entities::{Guild, User}, utils::Snowflake, Shared, From 239f994841549bd8a05a2843342c59eaa3b61c40 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 26 Sep 2024 21:26:19 +0200 Subject: [PATCH 150/162] Add Clone derive to GatewayRequestGuildMembers --- src/types/events/request_members.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/types/events/request_members.rs b/src/types/events/request_members.rs index a6cffdf6..5228170d 100644 --- a/src/types/events/request_members.rs +++ b/src/types/events/request_members.rs @@ -5,7 +5,7 @@ use crate::types::{events::WebSocketEvent, Snowflake}; use serde::{Deserialize, Serialize}; -#[derive(Debug, Deserialize, Serialize, Default, WebSocketEvent)] +#[derive(Debug, Deserialize, Serialize, Default, WebSocketEvent, Clone)] /// See pub struct GatewayRequestGuildMembers { pub guild_id: Snowflake, @@ -16,4 +16,3 @@ pub struct GatewayRequestGuildMembers { pub user_ids: Option, pub nonce: Option, } - From 0eea35a59a0c92b98b0ae8bba0b5c4aa263a9864 Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Fri, 27 Sep 2024 17:39:04 +0200 Subject: [PATCH 151/162] User routes update (#537) * feat: Add UserProfile and other types * api: re-do a large part of the users api * feat: add modify user profile * feat: delete and disable user endpoints * feat: modify email and verify email endpoints * feat!: add discriminator parameter to get_user_by_username * feat!: add get_user_profile query string schema * chore: add integration expire behavior * feat: add get_pomelo_suggestions and get_pomelo_eligibility * feat: add create_pomelo_migration * fix: rustdoc lints * feat: recent_mentions endpoints Adds GET /users/@me/mentions and DELETE /users/@me/mentions/{message.id} * feat: add get_user_harvest & create_user_harvest Also adds /types/entities/harvest.rs, types for Harvest * feat: user notes endpoints Adds: get_user_notes, get_user_note, set_user_note * feat: add #545 and #546 Adds the RECENT_MENTION_DELETE and USER_NOTE_UPDATE gateway events. The events can be accessed at: message.recent_mention_delete & user.note_update * feat: add authorize_connection Also adds: src/types/entities/connection.rs, Connection and PublicConnection, src/api/users/connections.rs * feat: add rest* of Connections api * The only thing not added yet is create_domain_connection, because it uses errors in a funky way adds: - create_connection_callback - create_contact_sync_connection - get_connections - refresh_connection - modify_connection - delete_connection - get_connection_access_token - get_connection_subreddits + related schema for all those routes, and some supporting types * feat: add connected_accounts to UserProfile * feat: add affinities * feat: add get_premium_usage endpoint note: not fully tested; I do not have an account with premium * cliipy my arch nemesis strikes again * aa * feat: add create_domain_connection * feat: add get_burst_credits * grumble grumble * clippy * fix READY deserialization error on spacebar * fix a deserialization error on Spacebar See spacebarchat/server#1188 A deserialization error was happening with get_user_profile, where pronouns should have been serialized as an empty string, but were instead serialized as null. * skip serializing None query parameters * add test for get_user_profile * apparently Sb does not implement users/@me/notes * add some tests, minor connection updates - Document that create_domain_connection is unimplemented on Spacebar - Add Discord connection type - Change ConnectionType::array() into ConnectionType::vector() - returning a fixed size array is dubious, since it'll likely be expanded. Returning a vector is easier keep up to variable length - Add ConnectionType::discord_vector() and ConnectionType::spacebar_vector() to return a vector ConnectionTypes available on the respective server backends - add tests test_modify_user_profile, test_disable_user, test_get_user_note, test_set_user_note, test_get_user_affinities, test_get_guild_affinities, test_get_connections Note: connections are hard to test, since they require secrets / an external service's account * minor pre merge changes - add some extra doc comments - and into_public() for connection - remove a todo that is no longer valid --- src/api/auth/login.rs | 2 +- src/api/auth/mod.rs | 2 +- src/api/users/connections.rs | 391 +++++++++++++++ src/api/users/mod.rs | 2 + src/api/users/users.rs | 806 ++++++++++++++++++++++++++++-- src/gateway/events.rs | 3 + src/gateway/gateway.rs | 3 + src/types/entities/connection.rs | 300 +++++++++++ src/types/entities/guild.rs | 13 +- src/types/entities/harvest.rs | 97 ++++ src/types/entities/integration.rs | 33 +- src/types/entities/mod.rs | 4 + src/types/entities/user.rs | 650 +++++++++++++++++++++++- src/types/events/message.rs | 9 + src/types/events/session.rs | 2 +- src/types/events/user.rs | 22 + src/types/schema/user.rs | 358 ++++++++++++- tests/common/mod.rs | 8 +- tests/user.rs | 192 ++++++- 19 files changed, 2846 insertions(+), 51 deletions(-) create mode 100644 src/api/users/connections.rs create mode 100644 src/types/entities/connection.rs create mode 100644 src/types/entities/harvest.rs diff --git a/src/api/auth/login.rs b/src/api/auth/login.rs index 1af19e05..4d8cbce6 100644 --- a/src/api/auth/login.rs +++ b/src/api/auth/login.rs @@ -48,7 +48,7 @@ impl Instance { >>>>>>> 03f1e7d (Refactor / fix login and register (#495)) user.settings = login_result.settings; - let object = User::get(&mut user, None).await?; + let object = User::get_current(&mut user).await?; *user.object.write().unwrap() = object; let mut identify = GatewayIdentifyPayload::common(); diff --git a/src/api/auth/mod.rs b/src/api/auth/mod.rs index 7aaf13f5..cdc41ba8 100644 --- a/src/api/auth/mod.rs +++ b/src/api/auth/mod.rs @@ -31,7 +31,7 @@ impl Instance { ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await; >>>>>>> 03f1e7d (Refactor / fix login and register (#495)) - let object = User::get(&mut user, None).await?; + let object = User::get_current(&mut user).await?; let settings = User::get_settings(&mut user).await?; *user.object.write().unwrap() = object; diff --git a/src/api/users/connections.rs b/src/api/users/connections.rs new file mode 100644 index 00000000..29c40df1 --- /dev/null +++ b/src/api/users/connections.rs @@ -0,0 +1,391 @@ +use futures_util::FutureExt; +use reqwest::Client; + +use crate::{ + errors::{ChorusError, ChorusResult}, + instance::ChorusUser, + ratelimiter::ChorusRequest, + types::{ + AuthorizeConnectionReturn, AuthorizeConnectionSchema, Connection, ConnectionSubreddit, + ConnectionType, CreateConnectionCallbackSchema, CreateContactSyncConnectionSchema, + CreateDomainConnectionError, CreateDomainConnectionReturn, GetConnectionAccessTokenReturn, + LimitType, ModifyConnectionSchema, + }, +}; + +impl ChorusUser { + /// Fetches a url that can be used for authorizing a new connection. + /// + /// The user should then visit the url and authenticate to create the connection. + /// + /// # Notes + /// This route seems to be preferred by the official infrastructure (client) to + /// [Self::create_connection_callback]. + /// + /// # Reference + /// See + /// + /// Note: it doesn't seem to be actually unauthenticated + pub async fn authorize_connection( + &mut self, + connection_type: ConnectionType, + query_parameters: AuthorizeConnectionSchema, + ) -> ChorusResult { + let connection_type_string = serde_json::to_string(&connection_type) + .expect("Failed to serialize connection type!") + .replace('"', ""); + + let request = Client::new() + .get(format!( + "{}/connections/{}/authorize", + self.belongs_to.read().unwrap().urls.api, + connection_type_string + )) + // Note: ommiting this header causes a 401 Unauthorized, + // even though discord.sex mentions it as unauthenticated + .header("Authorization", self.token()) + .query(&query_parameters); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request + .deserialize_response::(self) + .await + .map(|response| response.url) + } + + /// Creates a new connection for the current user. + /// + /// # Notes + /// The official infrastructure (client) prefers the route + /// [Self::authorize_connection] to this one. + /// + /// # Reference + /// See + // TODO: When is this called? When should it be used over authorize_connection? + pub async fn create_connection_callback( + &mut self, + connection_type: ConnectionType, + json_schema: CreateConnectionCallbackSchema, + ) -> ChorusResult { + let connection_type_string = serde_json::to_string(&connection_type) + .expect("Failed to serialize connection type!") + .replace('"', ""); + + let request = Client::new() + .post(format!( + "{}/connections/{}/callback", + self.belongs_to.read().unwrap().urls.api, + connection_type_string + )) + .header("Authorization", self.token()) + .json(&json_schema); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Creates a new contact sync connection for the current user. + /// + /// # Notes + /// To create normal connection types, see [Self::authorize_connection] and + /// [Self::create_connection_callback] + /// + /// # Reference + /// See + pub async fn create_contact_sync_connection( + &mut self, + connection_account_id: &String, + json_schema: CreateContactSyncConnectionSchema, + ) -> ChorusResult { + let request = Client::new() + .put(format!( + "{}/users/@me/connections/contacts/{}", + self.belongs_to.read().unwrap().urls.api, + connection_account_id + )) + .header("Authorization", self.token()) + .json(&json_schema); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Creates a new domain connection for the current user. + /// + /// This route has two possible successful return values: + /// [CreateDomainConnectionReturn::Ok] and [CreateDomainConnectionReturn::ProofNeeded] + /// + /// To properly handle both, please see their respective documentation pages. + /// + /// # Notes + /// To create normal connection types, see [Self::authorize_connection] and + /// [Self::create_connection_callback] + /// + /// As of 2024/08/21, Spacebar does not yet implement this endpoint. + /// + /// # Examples + /// ```no_run + /// let domain = "example.com".to_string(); + /// + /// let user: ChorusUser; // Get this by registering / logging in + /// + /// let result = user.create_domain_connection(&domain).await; + /// + /// if let Ok(returned) = result { + /// match returned { + /// CreateDomainConnectionReturn::ProofNeeded(proof) => { + /// println!("Additional proof needed!"); + /// println!("Either:"); + /// println!(""); + /// println!("- create a DNS TXT record with the name _discord.{domain} and content {proof}"); + /// println!("or"); + /// println!("- create a file at https://{domain}/.well-known/discord with the content {proof}"); + /// // Once the user has added the proof, retry calling the endpoint + /// } + /// CreateDomainConnectionReturn::Ok(connection) => { + /// println!("Successfulyl created connection! {:?}", connection); + /// } + /// } + /// } else { + /// println!("Failed to create connection: {:?}", result); + /// } + /// ``` + /// + /// # Reference + /// See + pub async fn create_domain_connection( + &mut self, + domain: &String, + ) -> ChorusResult { + let request = Client::new() + .post(format!( + "{}/users/@me/connections/domain/{}", + self.belongs_to.read().unwrap().urls.api, + domain + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + let result = chorus_request + .deserialize_response::(self) + .await; + + if let Ok(connection) = result { + return Ok(CreateDomainConnectionReturn::Ok(connection)); + } + + let error = result.err().unwrap(); + + if let ChorusError::ReceivedErrorCode { + error_code, + error: ref error_string, + } = error + { + if error_code == 400 { + let try_deserialize: Result = + serde_json::from_str(error_string); + + if let Ok(deserialized_error) = try_deserialize { + return Ok(CreateDomainConnectionReturn::ProofNeeded( + deserialized_error.proof, + )); + } + } + } + + Err(error) + } + + /// Fetches the current user's [Connection]s + /// + /// # Reference + /// See + pub async fn get_connections(&mut self) -> ChorusResult> { + let request = Client::new() + .get(format!( + "{}/users/@me/connections", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Refreshes a local user's [Connection]. + /// + /// # Reference + /// See + pub async fn refresh_connection( + &mut self, + connection_type: ConnectionType, + connection_account_id: &String, + ) -> ChorusResult<()> { + let connection_type_string = serde_json::to_string(&connection_type) + .expect("Failed to serialize connection type!") + .replace('"', ""); + + let request = Client::new() + .post(format!( + "{}/users/@me/connections/{}/{}/refresh", + self.belongs_to.read().unwrap().urls.api, + connection_type_string, + connection_account_id + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.handle_request_as_result(self).await + } + + /// Changes settings on a local user's [Connection]. + /// + /// # Notes + /// Not all connection types support all parameters. + /// + /// # Reference + /// See + pub async fn modify_connection( + &mut self, + connection_type: ConnectionType, + connection_account_id: &String, + json_schema: ModifyConnectionSchema, + ) -> ChorusResult { + let connection_type_string = serde_json::to_string(&connection_type) + .expect("Failed to serialize connection type!") + .replace('"', ""); + + let request = Client::new() + .patch(format!( + "{}/users/@me/connections/{}/{}", + self.belongs_to.read().unwrap().urls.api, + connection_type_string, + connection_account_id + )) + .header("Authorization", self.token()) + .json(&json_schema); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Deletes a local user's [Connection]. + /// + /// # Reference + /// See + pub async fn delete_connection( + &mut self, + connection_type: ConnectionType, + connection_account_id: &String, + ) -> ChorusResult<()> { + let connection_type_string = serde_json::to_string(&connection_type) + .expect("Failed to serialize connection type!") + .replace('"', ""); + + let request = Client::new() + .delete(format!( + "{}/users/@me/connections/{}/{}", + self.belongs_to.read().unwrap().urls.api, + connection_type_string, + connection_account_id + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.handle_request_as_result(self).await + } + + /// Returns a new access token for the given connection. + /// + /// Only available for [ConnectionType::Twitch], [ConnectionType::YouTube] and [ConnectionType::Spotify] connections. + /// + /// # Reference + /// See + pub async fn get_connection_access_token( + &mut self, + connection_type: ConnectionType, + connection_account_id: &String, + ) -> ChorusResult { + let connection_type_string = serde_json::to_string(&connection_type) + .expect("Failed to serialize connection type!") + .replace('"', ""); + + let request = Client::new() + .get(format!( + "{}/users/@me/connections/{}/{}/access-token", + self.belongs_to.read().unwrap().urls.api, + connection_type_string, + connection_account_id + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request + .deserialize_response::(self) + .await + .map(|res| res.access_token) + } + + /// Fetches a list of [subreddits](crate::types::ConnectionSubreddit) + /// the connected account moderates. + /// + /// Only available for [ConnectionType::Reddit] connections. + /// + /// # Reference + /// See + pub async fn get_connection_subreddits( + &mut self, + connection_account_id: &String, + ) -> ChorusResult> { + let request = Client::new() + .get(format!( + "{}/users/@me/connections/reddit/{}/subreddits", + self.belongs_to.read().unwrap().urls.api, + connection_account_id + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } +} diff --git a/src/api/users/mod.rs b/src/api/users/mod.rs index b11772ab..702233cb 100644 --- a/src/api/users/mod.rs +++ b/src/api/users/mod.rs @@ -4,11 +4,13 @@ #![allow(unused_imports)] pub use channels::*; +pub use connections::*; pub use guilds::*; pub use relationships::*; pub use users::*; pub mod channels; +pub mod connections; pub mod guilds; pub mod relationships; pub mod users; diff --git a/src/api/users/users.rs b/src/api/users/users.rs index 3f43efbf..b8ab8d6a 100644 --- a/src/api/users/users.rs +++ b/src/api/users/users.rs @@ -2,7 +2,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::sync::{Arc, RwLock}; +use std::{ + collections::HashMap, + sync::{Arc, RwLock}, +}; use reqwest::Client; use serde_json::to_string; @@ -11,22 +14,69 @@ use crate::{ errors::{ChorusError, ChorusResult}, instance::{ChorusUser, Instance}, ratelimiter::ChorusRequest, - types::{LimitType, User, UserModifySchema, UserSettings}, + types::{ + AuthorizeConnectionSchema, BurstCreditsInfo, ConnectionType, CreateUserHarvestSchema, + DeleteDisableUserSchema, GetPomeloEligibilityReturn, GetPomeloSuggestionsReturn, + GetRecentMentionsSchema, GetUserProfileSchema, GuildAffinities, Harvest, + HarvestBackendType, LimitType, ModifyUserNoteSchema, PremiumUsage, PublicUser, Snowflake, + User, UserAffinities, UserModifyProfileSchema, UserModifySchema, UserNote, UserProfile, + UserProfileMetadata, UserSettings, VerifyUserEmailChangeResponse, + VerifyUserEmailChangeSchema, + }, }; impl ChorusUser { - /// Gets a user by id, or if the id is None, gets the current user. + /// Gets the local / current user. + /// + /// # Notes + /// This function is a wrapper around [`User::get_current`]. + /// + /// # Reference + /// See + pub async fn get_current_user(&mut self) -> ChorusResult { + User::get_current(self).await + } + + /// Gets a non-local user by their id /// /// # Notes /// This function is a wrapper around [`User::get`]. /// /// # Reference - /// See and - /// - pub async fn get_user(&mut self, id: Option<&String>) -> ChorusResult { + /// See + pub async fn get_user(&mut self, id: Snowflake) -> ChorusResult { User::get(self, id).await } + /// Gets a non-local user by their unique username. + /// + /// As of 2024/07/28, Spacebar does not yet implement this endpoint. + /// + /// If fetching with a pomelo username, discriminator should be set to None. + /// + /// This route also permits fetching users with their old pre-pomelo username#discriminator + /// combo. + /// + /// Note: + /// + /// "Unless the target user is a bot, you must be able to add + /// the user as a friend to resolve them by username. + /// + /// Due to this restriction, you are not able to resolve your own username." + /// + /// # Notes + /// This function is a wrapper around [`User::get_by_username`]. + /// + /// # Reference + /// See + pub async fn get_user_by_username( + &mut self, + username: &String, + discriminator: Option<&String>, + ) -> ChorusResult { + User::get_by_username(self, username, discriminator).await + } + /// Gets the user's settings. /// /// # Notes @@ -44,7 +94,6 @@ impl ChorusUser { /// # Reference /// See pub async fn modify(&mut self, modify_schema: UserModifySchema) -> ChorusResult { - // See , note 1 let requires_current_password = modify_schema.username.is_some() || modify_schema.discriminator.is_some() @@ -71,39 +120,583 @@ impl ChorusUser { chorus_request.deserialize_response::(self).await } - /// Deletes the user from the Instance. + /// Disables the current user's account. + /// + /// Invalidates all active tokens. + /// + /// Requires the user's current password (if any) + /// + /// # Notes + /// Requires MFA /// /// # Reference - /// See - pub async fn delete(mut self) -> ChorusResult<()> { + /// See + pub async fn disable(&mut self, schema: DeleteDisableUserSchema) -> ChorusResult<()> { + let request = Client::new() + .post(format!( + "{}/users/@me/disable", + self.belongs_to.read().unwrap().urls.api + )) + .header("Authorization", self.token()) + .json(&schema); + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + chorus_request.handle_request_as_result(self).await + } + + /// Deletes the current user from the Instance. + /// + /// Requires the user's current password (if any) + /// + /// # Notes + /// Requires MFA + /// + /// # Reference + /// See + pub async fn delete(&mut self, schema: DeleteDisableUserSchema) -> ChorusResult<()> { let request = Client::new() .post(format!( "{}/users/@me/delete", self.belongs_to.read().unwrap().urls.api )) .header("Authorization", self.token()) + .json(&schema); + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + chorus_request.handle_request_as_result(self).await + } + + /// Gets a user's profile object by their id. + /// + /// This endpoint requires one of the following: + /// + /// - The other user is a bot + /// - The other user shares a mutual guild with the current user + /// - The other user is a friend of the current user + /// - The other user is a friend suggestion of the current user + /// - The other user has an outgoing friend request to the current user + /// + /// # Notes + /// This function is a wrapper around [`User::get_profile`]. + /// + /// # Reference + /// See + pub async fn get_user_profile( + &mut self, + id: Snowflake, + query_parameters: GetUserProfileSchema, + ) -> ChorusResult { + User::get_profile(self, id, query_parameters).await + } + + /// Modifies the current user's profile. + /// + /// Returns the updated [UserProfileMetadata]. + /// + /// # Notes + /// This function is a wrapper around [`User::modify_profile`]. + /// + /// # Reference + /// See + pub async fn modify_profile( + &mut self, + schema: UserModifyProfileSchema, + ) -> ChorusResult { + User::modify_profile(self, schema).await + } + + /// Initiates the email change process. + /// + /// Sends a verification code to the current user's email. + /// + /// Should be followed up with [Self::verify_email_change] + /// + /// # Reference + /// See + pub async fn initiate_email_change(&mut self) -> ChorusResult<()> { + let request = Client::new() + .put(format!( + "{}/users/@me/email", + self.belongs_to.read().unwrap().urls.api + )) + .header("Authorization", self.token()); + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + chorus_request.handle_request_as_result(self).await + } + + /// Verifies a code sent to change the current user's email. + /// + /// This endpoint returns a token which can be used with [Self::modify] + /// to set a new email address (email_token). + /// + /// # Notes + /// Should be the follow-up to [Self::initiate_email_change] + /// + /// As of 2024/08/08, Spacebar does not yet implement this endpoint. + // FIXME: Does this mean PUT users/@me/email is different? + /// + /// # Reference + /// See + pub async fn verify_email_change( + &mut self, + schema: VerifyUserEmailChangeSchema, + ) -> ChorusResult { + let request = Client::new() + .post(format!( + "{}/users/@me/email/verify-code", + self.belongs_to.read().unwrap().urls.api + )) + .header("Authorization", self.token()) + .json(&schema); + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + chorus_request + .deserialize_response::(self) + .await + } + + /// Returns a suggested unique username based on the current user's username. + /// + /// # Notes: + /// "This endpoint is used during the pomelo migration flow. + /// + /// The user must be in the rollout to use this endpoint." + /// + /// If a user has already migrated, this endpoint will likely return a 401 Unauthorized + /// ([ChorusError::NoPermission]) + /// + /// As of 2024/08/08, Spacebar does not yet implement this endpoint. + /// + /// # Reference + /// See + pub async fn get_pomelo_suggestions(&mut self) -> ChorusResult { + let request = Client::new() + .get(format!( + "{}/users/@me/pomelo-suggestions", + self.belongs_to.read().unwrap().urls.api + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + chorus_request + .deserialize_response::(self) + .await + .map(|returned| returned.username) + } + + /// Checks whether a unique username is available. + /// + /// Returns whether the username is not taken yet. + /// + /// # Notes + /// As of 2024/08/08, Spacebar does not yet implement this endpoint. + /// + /// # Reference + /// See + pub async fn get_pomelo_eligibility(&mut self, username: &String) -> ChorusResult { + let request = Client::new() + .post(format!( + "{}/users/@me/pomelo-attempt", + self.belongs_to.read().unwrap().urls.api + )) + .header("Authorization", self.token()) + // FIXME: should we create a type for this? + .body(format!(r#"{{ "username": {:?} }}"#, username)) + .header("Content-Type", "application/json"); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + chorus_request + .deserialize_response::(self) + .await + .map(|returned| !returned.taken) + } + + /// Migrates the user from the username#discriminator to the unique username system. + /// + /// Fires a [UserUpdate](crate::types::UserUpdate) gateway event. + /// + /// Updates [Self::object] to an updated representation returned by the server. + // FIXME: Is this appropriate behaviour? + /// + /// # Notes + /// "This endpoint is used during the pomelo migration flow. + /// + /// The user must be in the rollout to use this endpoint." + /// + /// If a user has already migrated, this endpoint will likely return a 401 Unauthorized + /// ([ChorusError::NoPermission]) + // + /// As of 2024/08/08, Spacebar does not yet implement this endpoint. + /// + /// # Reference + /// See + pub async fn create_pomelo_migration(&mut self, username: &String) -> ChorusResult<()> { + let request = Client::new() + .post(format!( + "{}/users/@me/pomelo", + self.belongs_to.read().unwrap().urls.api + )) + .header("Authorization", self.token()) + // FIXME: should we create a type for this? + .body(format!(r#"{{ "username": {:?} }}"#, username)) .header("Content-Type", "application/json"); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + let result = chorus_request.deserialize_response::(self).await; + + // FIXME: Does UserUpdate do this automatically? or would a user need to manually observe ChorusUser::object + if let Ok(new_object) = result { + *self.object.write().unwrap() = new_object; + return ChorusResult::Ok(()); + } + + ChorusResult::Err(result.err().unwrap()) + } + + /// Fetches a list of [Message](crate::types::Message)s that the current user has been + /// mentioned in during the last 7 days. + /// + /// # Notes + /// As of 2024/08/09, Spacebar does not yet implement this endpoint. + /// + /// # Reference + /// See + pub async fn get_recent_mentions( + &mut self, + query_parameters: GetRecentMentionsSchema, + ) -> ChorusResult> { + let request = Client::new() + .get(format!( + "{}/users/@me/mentions", + self.belongs_to.read().unwrap().urls.api + )) + .header("Authorization", self.token()) + .query(&query_parameters); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request + .deserialize_response::>(self) + .await + } + + /// Acknowledges a message the current user has been mentioned in. + /// + /// Fires a `RecentMentionDelete` gateway event. (Note: yet to be implemented in chorus, see [#545](https://github.com/polyphony-chat/chorus/issues/545)) + /// + /// # Notes + /// As of 2024/08/09, Spacebar does not yet implement this endpoint. + /// + /// # Reference + /// See + pub async fn delete_recent_mention(&mut self, message_id: Snowflake) -> ChorusResult<()> { + let request = Client::new() + .delete(format!( + "{}/users/@me/mentions/{}", + self.belongs_to.read().unwrap().urls.api, + message_id + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.handle_request_as_result(self).await + } + + /// If it exists, returns the most recent [Harvest] (personal data harvest request). + /// + /// To create a new [Harvest], see [Self::create_harvest]. + /// + /// # Notes + /// As of 2024/08/09, Spacebar does not yet implement this endpoint. (Or data harvesting) + /// + /// # Reference + /// See + pub async fn get_harvest(&mut self) -> ChorusResult> { + let request = Client::new() + .get(format!( + "{}/users/@me/harvest", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + // Manual handling, because a 204 with no harvest is a success state + // TODO: Maybe make this a method on ChorusRequest if we need it a lot + let response = chorus_request.send_request(self).await?; + log::trace!("Got response: {:?}", response); + + if response.status() == http::StatusCode::NO_CONTENT { + return Ok(None); + } + + let response_text = match response.text().await { + Ok(string) => string, + Err(e) => { + return Err(ChorusError::InvalidResponse { + error: format!( + "Error while trying to process the HTTP response into a String: {}", + e + ), + }); + } + }; + + let object = match serde_json::from_str::(&response_text) { + Ok(object) => object, + Err(e) => { + return Err(ChorusError::InvalidResponse { + error: format!( + "Error while trying to deserialize the JSON response into requested type T: {}. JSON Response: {}", + e, response_text + ), + }) + } + }; + Ok(Some(object)) + } + + /// Creates a personal data harvest request ([Harvest]) for the current user. + /// + /// # Notes + /// To fetch the latest existing harvest, see [Self::get_harvest]. + /// + /// Invalid options in the backends array are ignored. + /// + /// If the array is empty (after ignoring), it requests all [HarvestBackendType]s. + /// + /// As of 2024/08/09, Spacebar does not yet implement this endpoint. (Or data harvesting) + /// + /// # Reference + /// See + pub async fn create_harvest( + &mut self, + backends: Vec, + ) -> ChorusResult { + let schema = if backends.is_empty() { + CreateUserHarvestSchema { backends: None } + } else { + CreateUserHarvestSchema { + backends: Some(backends), + } + }; + + let request = Client::new() + .post(format!( + "{}/users/@me/harvest", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()) + .json(&schema); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Returns a mapping of user IDs ([Snowflake]s) to notes ([String]s) for the current user. + /// + /// # Notes + /// As of 2024/08/21, Spacebar does not yet implement this endpoint. + /// + /// # Reference + /// See + pub async fn get_user_notes(&mut self) -> ChorusResult> { + let request = Client::new() + .get(format!( + "{}/users/@me/notes", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + let chorus_request = ChorusRequest { request, limit_type: LimitType::default(), }; - chorus_request.handle_request_as_result(&mut self).await + + chorus_request.deserialize_response(self).await + } + + /// Fetches the note ([UserNote]) for the given user. + /// + /// If the current user has no note for the target, this endpoint + /// returns `Err(NotFound { error: "{\"message\": \"Unknown User\", \"code\": 10013}" })` + /// + /// # Notes + /// This function is a wrapper around [`User::get_note`]. + /// + /// # Reference + /// See + pub async fn get_user_note(&mut self, target_user_id: Snowflake) -> ChorusResult { + User::get_note(self, target_user_id).await + } + + /// Sets the note for the given user. + /// + /// Fires a `UserNoteUpdate` gateway event. (Note: yet to be implemented in chorus, see [#546](https://github.com/polyphony-chat/chorus/issues/546)) + /// + /// # Notes + /// This function is a wrapper around [`User::set_note`]. + /// + /// # Reference + /// See + pub async fn set_user_note( + &mut self, + target_user_id: Snowflake, + note: Option, + ) -> ChorusResult<()> { + User::set_note(self, target_user_id, note).await + } + + /// Fetches the current user's affinity scores for other users. + /// + /// (Affinity scores are a measure of how likely a user is to be friends with another user.) + /// + /// # Reference + /// See + pub async fn get_user_affinities(&mut self) -> ChorusResult { + let request = Client::new() + .get(format!( + "{}/users/@me/affinities/users", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Fetches the current user's affinity scores for their joined guilds. + /// + /// # Reference + /// See + pub async fn get_guild_affinities(&mut self) -> ChorusResult { + let request = Client::new() + .get(format!( + "{}/users/@me/affinities/guilds", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Fetches the current user's usage of various premium perks ([PremiumUsage] object). + /// + /// The local user must have premium (nitro), otherwise the request will fail + /// with a 404 NotFound error and the message {"message": "Premium usage not available", "code": 10084}. + /// + /// # Notes + /// As of 2024/08/16, Spacebar does not yet implement this endpoint. + /// + /// # Reference + /// See + pub async fn get_premium_usage(&mut self) -> ChorusResult { + let request = Client::new() + .get(format!( + "{}/users/@me/premium-usage", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Fetches info about the current user's burst credits + /// (how many are remaining, when they will replenish). + /// + /// Burst credits are used to create burst reactions. + /// + /// # Notes + /// As of 2024/08/18, Spacebar does not yet implement this endpoint. + pub async fn get_burst_credits(&mut self) -> ChorusResult { + let request = Client::new() + .get(format!( + "{}/users/@me/burst-credits", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await } } impl User { - /// Gets a user by id, or if the id is None, gets the current user. + /// Gets the local / current user. /// /// # Reference - /// See and - /// - pub async fn get(user: &mut ChorusUser, id: Option<&String>) -> ChorusResult { + /// See + pub async fn get_current(user: &mut ChorusUser) -> ChorusResult { let url_api = user.belongs_to.read().unwrap().urls.api.clone(); - let url = if id.is_none() { - format!("{}/users/@me", url_api) - } else { - format!("{}/users/{}", url_api, id.unwrap()) + let url = format!("{}/users/@me", url_api); + let request = reqwest::Client::new() + .get(url) + .header("Authorization", user.token()); + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::Global, }; + chorus_request.deserialize_response::(user).await + } + + /// Gets a non-local user by their id + /// + /// # Reference + /// See + pub async fn get(user: &mut ChorusUser, id: Snowflake) -> ChorusResult { + let url_api = user.belongs_to.read().unwrap().urls.api.clone(); + let url = format!("{}/users/{}", url_api, id); let request = reqwest::Client::new() .get(url) .header("Authorization", user.token()); @@ -111,16 +704,54 @@ impl User { request, limit_type: LimitType::Global, }; - match chorus_request.send_request(user).await { - Ok(result) => { - let result_text = result.text().await.unwrap(); - Ok(serde_json::from_str::(&result_text).unwrap()) - } - Err(e) => Err(e), + chorus_request + .deserialize_response::(user) + .await + } + + /// Gets a user by their unique username. + /// + /// As of 2024/07/28, Spacebar does not yet implement this endpoint. + /// + /// If fetching with a pomelo username, discriminator should be set to None. + /// + /// This route also permits fetching users with their old pre-pomelo username#discriminator + /// combo. + /// + /// Note: + /// + /// "Unless the target user is a bot, you must be able to add + /// the user as a friend to resolve them by username. + /// + /// Due to this restriction, you are not able to resolve your own username." + /// + /// # Reference + /// See + pub async fn get_by_username( + user: &mut ChorusUser, + username: &String, + discriminator: Option<&String>, + ) -> ChorusResult { + let url_api = user.belongs_to.read().unwrap().urls.api.clone(); + let url = format!("{}/users/username/{username}", url_api); + let mut request = reqwest::Client::new() + .get(url) + .header("Authorization", user.token()); + + if let Some(some_discriminator) = discriminator { + request = request.query(&[("discriminator", some_discriminator)]); } + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::Global, + }; + chorus_request + .deserialize_response::(user) + .await } - /// Gets the user's settings. + /// Gets the current user's settings. /// /// # Reference /// See @@ -133,13 +764,122 @@ impl User { request, limit_type: LimitType::Global, }; - match chorus_request.send_request(user).await { - Ok(result) => { - let result_text = result.text().await.unwrap(); - Ok(serde_json::from_str(&result_text).unwrap()) - } - Err(e) => Err(e), - } + chorus_request + .deserialize_response::(user) + .await + } + + /// Gets a user's profile object by their id. + /// + /// This endpoint requires one of the following: + /// + /// - The other user is a bot + /// - The other user shares a mutual guild with the current user + /// - The other user is a friend of the current user + /// - The other user is a friend suggestion of the current user + /// - The other user has an outgoing friend request to the current user + /// + /// # Reference + /// See + pub async fn get_profile( + user: &mut ChorusUser, + id: Snowflake, + query_parameters: GetUserProfileSchema, + ) -> ChorusResult { + let url_api = user.belongs_to.read().unwrap().urls.api.clone(); + let request: reqwest::RequestBuilder = Client::new() + .get(format!("{}/users/{}/profile", url_api, id)) + .header("Authorization", user.token()) + .query(&query_parameters); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::Global, + }; + chorus_request + .deserialize_response::(user) + .await + } + + /// Modifies the current user's profile. + /// + /// Returns the updated [UserProfileMetadata]. + /// + /// # Reference + /// See + pub async fn modify_profile( + user: &mut ChorusUser, + schema: UserModifyProfileSchema, + ) -> ChorusResult { + let url_api = user.belongs_to.read().unwrap().urls.api.clone(); + let request: reqwest::RequestBuilder = Client::new() + .patch(format!("{}/users/@me/profile", url_api)) + .header("Authorization", user.token()) + .json(&schema); + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::Global, + }; + chorus_request + .deserialize_response::(user) + .await + } + + /// Fetches the note ([UserNote]) for the given user. + /// + /// If the current user has no note for the target, this endpoint + /// returns `Err(NotFound { error: "{\"message\": \"Unknown User\", \"code\": 10013}" })` + /// + /// # Reference + /// See + pub async fn get_note( + user: &mut ChorusUser, + target_user_id: Snowflake, + ) -> ChorusResult { + let request = Client::new() + .get(format!( + "{}/users/@me/notes/{}", + user.belongs_to.read().unwrap().urls.api, + target_user_id + )) + .header("Authorization", user.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(user).await + } + + /// Sets the note for the given user. + /// + /// Fires a `UserNoteUpdate` gateway event. (Note: yet to be implemented in chorus, see [#546](https://github.com/polyphony-chat/chorus/issues/546)) + /// + /// # Reference + /// See + pub async fn set_note( + user: &mut ChorusUser, + target_user_id: Snowflake, + note: Option, + ) -> ChorusResult<()> { + let schema = ModifyUserNoteSchema { note }; + + let request = Client::new() + .put(format!( + "{}/users/@me/notes/{}", + user.belongs_to.read().unwrap().urls.api, + target_user_id + )) + .header("Authorization", user.token()) + .json(&schema); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.handle_request_as_result(user).await } } <<<<<<< HEAD diff --git a/src/gateway/events.rs b/src/gateway/events.rs index 049434be..4663fe1a 100644 --- a/src/gateway/events.rs +++ b/src/gateway/events.rs @@ -69,12 +69,15 @@ pub struct Message { pub reaction_remove: Publisher, pub reaction_remove_all: Publisher, pub reaction_remove_emoji: Publisher, + pub recent_mention_delete: Publisher, pub ack: Publisher, } #[derive(Default, Debug)] pub struct User { pub update: Publisher, + pub connections_update: Publisher, + pub note_update: Publisher, pub guild_settings_update: Publisher, pub presence_update: Publisher, pub typing_start: Publisher, diff --git a/src/gateway/gateway.rs b/src/gateway/gateway.rs index 976769d2..20f86407 100644 --- a/src/gateway/gateway.rs +++ b/src/gateway/gateway.rs @@ -404,6 +404,7 @@ impl Gateway { "MESSAGE_REACTION_REMOVE" => message.reaction_remove, // TODO "MESSAGE_REACTION_REMOVE_ALL" => message.reaction_remove_all, // TODO "MESSAGE_REACTION_REMOVE_EMOJI" => message.reaction_remove_emoji, // TODO + "RECENT_MENTION_DELETE" => message.recent_mention_delete, "MESSAGE_ACK" => message.ack, "PRESENCE_UPDATE" => user.presence_update, // TODO "RELATIONSHIP_ADD" => relationship.add, @@ -413,6 +414,8 @@ impl Gateway { "STAGE_INSTANCE_DELETE" => stage_instance.delete, "TYPING_START" => user.typing_start, "USER_UPDATE" => user.update, // TODO + "USER_CONNECTIONS_UPDATE" => user.connections_update, // TODO + "USER_NOTE_UPDATE" => user.note_update, "USER_GUILD_SETTINGS_UPDATE" => user.guild_settings_update, "VOICE_STATE_UPDATE" => voice.state_update, // TODO "VOICE_SERVER_UPDATE" => voice.server_update, diff --git a/src/types/entities/connection.rs b/src/types/entities/connection.rs new file mode 100644 index 00000000..e6421b07 --- /dev/null +++ b/src/types/entities/connection.rs @@ -0,0 +1,300 @@ +use std::{collections::HashMap, fmt::Display}; + +use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; + +/// A 3rd party service connection to a user's account. +/// +/// # Reference +/// See +// TODO: Should (could) this type be Updateable and Composite? +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +pub struct Connection { + /// The id of the account on the 3rd party service + #[serde(rename = "id")] + pub connected_account_id: String, + + /// The service of the connected account + #[serde(rename = "type")] + pub connection_type: ConnectionType, + + /// The username of the connection account + pub name: String, + + /// If the connection is verified + pub verified: bool, + + /// Service specific metadata about the connection / connected account + // FIXME: Is there a better type? As far as I see the value is always encoded as a string + pub metadata: Option>, + pub metadata_visibility: ConnectionVisibilityType, + + /// If the connection if revoked + pub revoked: bool, + + // TODO: Add integrations + pub friend_sync: bool, + + /// Whether activities related to this connection will be shown in presence + pub show_activity: bool, + + /// Whether this connection has a corresponding 3rd party OAuth2 token + pub two_way_link: bool, + + /// Who can see this connection + pub visibility: ConnectionVisibilityType, + + /// The access token for the connection account + /// + /// Note: not included when fetching a user's connections via OAuth2 + pub access_token: Option, +} + +impl Connection { + /// Converts self info a [PublicConnection], forgetting private data + pub fn into_public(self: Connection) -> PublicConnection { + PublicConnection { + name: self.name, + verified: self.verified, + connection_type: self.connection_type, + connected_account_id: self.connected_account_id, + metadata: self.metadata, + } + } +} + +/// A partial / public [Connection] type. +/// +/// # Reference +/// See +// FIXME: Should (could) this type also be Updateable and Composite? +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +pub struct PublicConnection { + /// The id of the account on the 3rd party service + #[serde(rename = "id")] + pub connected_account_id: String, + + #[serde(rename = "type")] + pub connection_type: ConnectionType, + + /// The username of the connection account + pub name: String, + + /// If the connection is verified + pub verified: bool, + + /// Service specific metadata about the connection / connected account + // FIXME: Is there a better type? As far as I see the value is always encoded as a string + pub metadata: Option>, +} + +impl From for PublicConnection { + fn from(value: Connection) -> Self { + value.into_public() + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, Copy, PartialOrd, Ord)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[serde(rename_all = "lowercase")] +/// A type of connection; the service the connection is for +/// +/// Note: this is subject to change, and the enum is likely non-exhaustive +/// +/// # Reference +/// See +pub enum ConnectionType { + #[serde(rename = "amazon-music")] + AmazonMusic, + /// Battle.net + BattleNet, + /// Bungie.net + Bungie, + /// Discord?'s contact sync + /// + /// (Not returned in Get User Profile or when fetching connections) + Contacts, + Crunchyroll, + /// Note: spacebar only + Discord, + Domain, + Ebay, + EpicGames, + Facebook, + GitHub, + Instagram, + LeagueOfLegends, + PayPal, + /// Playstation network + Playstation, + Reddit, + Roblox, + RiotGames, + /// Samsung Galaxy + /// + /// Users can no longer add this service + Samsung, + Spotify, + /// Users can no longer add this service + Skype, + Steam, + TikTok, + Twitch, + Twitter, + Xbox, + YouTube, +} + +impl Display for ConnectionType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + Self::AmazonMusic => f.write_str("Amazon Music"), + Self::BattleNet => f.write_str("Battle.net"), + Self::Bungie => f.write_str("Bungie.net"), + Self::Ebay => f.write_str("eBay"), + Self::EpicGames => f.write_str("Epic Games"), + Self::LeagueOfLegends => f.write_str("League of Legends"), + Self::Playstation => f.write_str("PlayStation Network"), + Self::RiotGames => f.write_str("Riot Games"), + Self::Samsung => f.write_str("Samsung Galaxy"), + _ => f.write_str(format!("{:?}", self).as_str()), + } + } +} + +impl ConnectionType { + /// Returns an vector of all the connection types + // API note: this could be an array, but it is subject to change. + pub fn vector() -> Vec { + vec![ + ConnectionType::AmazonMusic, + ConnectionType::BattleNet, + ConnectionType::Bungie, + ConnectionType::Contacts, + ConnectionType::Crunchyroll, + ConnectionType::Discord, + ConnectionType::Domain, + ConnectionType::Ebay, + ConnectionType::EpicGames, + ConnectionType::Facebook, + ConnectionType::GitHub, + ConnectionType::Instagram, + ConnectionType::LeagueOfLegends, + ConnectionType::PayPal, + ConnectionType::Playstation, + ConnectionType::Reddit, + ConnectionType::RiotGames, + ConnectionType::Samsung, + ConnectionType::Spotify, + ConnectionType::Skype, + ConnectionType::Steam, + ConnectionType::TikTok, + ConnectionType::Twitch, + ConnectionType::Twitter, + ConnectionType::Xbox, + ConnectionType::YouTube, + ] + } + + /// Returns an vector of all the connection types available on discord + pub fn discord_vector() -> Vec { + vec![ + ConnectionType::AmazonMusic, + ConnectionType::BattleNet, + ConnectionType::Bungie, + ConnectionType::Contacts, + ConnectionType::Crunchyroll, + ConnectionType::Domain, + ConnectionType::Ebay, + ConnectionType::EpicGames, + ConnectionType::Facebook, + ConnectionType::GitHub, + ConnectionType::Instagram, + ConnectionType::LeagueOfLegends, + ConnectionType::PayPal, + ConnectionType::Playstation, + ConnectionType::Reddit, + ConnectionType::RiotGames, + ConnectionType::Samsung, + ConnectionType::Spotify, + ConnectionType::Skype, + ConnectionType::Steam, + ConnectionType::TikTok, + ConnectionType::Twitch, + ConnectionType::Twitter, + ConnectionType::Xbox, + ConnectionType::YouTube, + ] + } + + /// Returns an vector of all the connection types available on spacebar + pub fn spacebar_vector() -> Vec { + vec![ + ConnectionType::BattleNet, + ConnectionType::Discord, + ConnectionType::EpicGames, + ConnectionType::Facebook, + ConnectionType::GitHub, + ConnectionType::Reddit, + ConnectionType::Spotify, + ConnectionType::Twitch, + ConnectionType::Twitter, + ConnectionType::Xbox, + ConnectionType::YouTube, + ] + } +} + +#[derive( + Serialize_repr, Deserialize_repr, Debug, Clone, Eq, PartialEq, Hash, Copy, PartialOrd, Ord, +)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[repr(u8)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +/// # Reference +/// See +pub enum ConnectionVisibilityType { + /// Invisible to everyone except the user themselves + None = 0, + /// Visible to everyone + Everyone = 1, +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, Copy, PartialOrd, Ord)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[serde(rename_all = "lowercase")] +/// A type of two-way connection link +/// +/// # Reference +/// See +pub enum TwoWayLinkType { + /// The connection is linked via web + Web, + /// The connection is linked via mobile + Mobile, + /// The connection is linked via desktop + Desktop, +} + +impl Display for TwoWayLinkType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(format!("{:?}", self).as_str()) + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +/// Defines a subreddit as fetched through a Reddit connection ([[ConnectionType::Reddit]]). +/// +/// # Reference +/// See +pub struct ConnectionSubreddit { + /// The subreddit's internal id, e.g. "t5_388p4" + pub id: String, + + /// How many reddit users follow the subreddit + pub subscribers: usize, + + /// The subreddit's relative url, e.g. "/r/discordapp/" + pub url: String, +} diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 423339a1..91850ac2 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -452,7 +452,7 @@ pub enum VerificationLevel { #[cfg_attr(not(feature = "sqlx"), repr(u8))] #[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -/// See +/// See pub enum MFALevel { #[default] None = 0, @@ -476,7 +476,7 @@ pub enum MFALevel { #[cfg_attr(not(feature = "sqlx"), repr(u8))] #[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -/// See +/// See pub enum NSFWLevel { #[default] Default = 0, @@ -502,12 +502,19 @@ pub enum NSFWLevel { #[cfg_attr(not(feature = "sqlx"), repr(u8))] #[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -/// See +// Note: Maybe rename this to GuildPremiumTier? +/// **Guild** premium (Boosting) tier +/// +/// See pub enum PremiumTier { #[default] + /// No server boost perks None = 0, + /// Level 1 server boost perks Tier1 = 1, + /// Level 2 server boost perks Tier2 = 2, + /// Level 3 server boost perks Tier3 = 3, } diff --git a/src/types/entities/harvest.rs b/src/types/entities/harvest.rs new file mode 100644 index 00000000..b747641a --- /dev/null +++ b/src/types/entities/harvest.rs @@ -0,0 +1,97 @@ +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; + +use crate::types::Snowflake; + +#[cfg(feature = "client")] +use crate::gateway::Updateable; + +// FIXME: Should this type be Composite? +#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +/// A user's data harvest. +/// +/// # Reference +/// +/// See +pub struct Harvest { + pub harvest_id: Snowflake, + /// The id of the user being harvested + pub user_id: Snowflake, + /// How much the harvest has been processed + pub status: HarvestStatus, + /// The time the harvest was created + pub created_at: DateTime, + /// The time the harvest was last polled + pub polled_at: Option>, + /// The time the harvest was completed + pub completed_at: Option>, +} + +#[cfg(feature = "client")] +impl Updateable for Harvest { + #[cfg(not(tarpaulin_include))] + fn id(&self) -> Snowflake { + self.harvest_id + } +} + +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Default, + Clone, + Eq, + PartialEq, + Hash, + Copy, + PartialOrd, + Ord, +)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[repr(u8)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +/// Current status of a [Harvest] +/// +/// See and +pub enum HarvestStatus { + /// The harvest is queued and has not been started + Queued = 0, + /// The harvest is currently running / being processed + Running = 1, + /// The harvest has failed + Failed = 2, + /// The harvest has been completed successfully + Completed = 3, + #[default] + Unknown = 4, +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, Copy, PartialOrd, Ord)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +/// A type of backend / service a harvest can be requested for. +/// +/// See and +pub enum HarvestBackendType { + /// All account information; + Accounts, + /// Actions the user has taken; + /// + /// Represented as "Your Activity" in the discord client + Analytics, + /// First-party embedded activity information; + /// + /// e.g.: Chess in the Park, Checkers in the Park, Poker Night 2.0; + /// Sketch Heads, Watch Together, Letter League, Land-io, Know What I Meme + Activities, + /// The user's messages + Messages, + /// Official Discord programes; + /// + /// e.g.: Partner, HypeSquad, Verified Server + Programs, + /// Guilds the user is a member of; + Servers, +} diff --git a/src/types/entities/integration.rs b/src/types/entities/integration.rs index 50a82819..8afec21f 100644 --- a/src/types/entities/integration.rs +++ b/src/types/entities/integration.rs @@ -4,6 +4,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; use crate::types::{ entities::{Application, User}, @@ -24,7 +25,7 @@ pub struct Integration { pub syncing: Option, pub role_id: Option, pub enabled_emoticons: Option, - pub expire_behaviour: Option, + pub expire_behaviour: Option, pub expire_grace_period: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub user: Option>, @@ -51,6 +52,7 @@ pub struct IntegrationAccount { #[serde(rename_all = "snake_case")] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr(feature = "sqlx", sqlx(rename_all = "snake_case"))] +/// See pub enum IntegrationType { #[default] Twitch, @@ -58,3 +60,32 @@ pub enum IntegrationType { Discord, GuildSubscription, } + +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Default, + Clone, + Eq, + PartialEq, + Hash, + Copy, + PartialOrd, + Ord, +)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[repr(u8)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +/// Defines the behaviour that is executed when a user's subscription to the integration expires. +/// +/// See +pub enum IntegrationExpireBehaviour { + #[default] + /// Remove the subscriber role from the user + RemoveRole = 0, + /// Kick the user from the guild + Kick = 1, +} + + diff --git a/src/types/entities/mod.rs b/src/types/entities/mod.rs index 545614cd..969d731a 100644 --- a/src/types/entities/mod.rs +++ b/src/types/entities/mod.rs @@ -8,9 +8,11 @@ pub use audit_log::*; pub use auto_moderation::*; pub use channel::*; pub use config::*; +pub use connection::*; pub use emoji::*; pub use guild::*; pub use guild_member::*; +pub use harvest::*; pub use integration::*; pub use invite::*; pub use message::*; @@ -49,9 +51,11 @@ mod audit_log; mod auto_moderation; mod channel; mod config; +mod connection; mod emoji; mod guild; mod guild_member; +mod harvest; mod integration; mod invite; mod message; diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index 866d66cf..9c7c3b9d 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -7,7 +7,8 @@ use crate::types::utils::Snowflake; use crate::{UInt32, UInt8}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use serde_aux::prelude::deserialize_option_number_from_string; +use serde_aux::prelude::{deserialize_option_number_from_string, deserialize_default_from_null}; +use serde_repr::{Deserialize_repr, Serialize_repr}; use std::array::TryFromSliceError; use std::fmt::Debug; @@ -23,7 +24,7 @@ use crate::gateway::GatewayHandle; #[cfg(feature = "client")] use chorus_macros::{Composite, Updateable}; -use super::Emoji; +use super::{Emoji, GuildMember, PublicConnection}; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] @@ -40,6 +41,8 @@ impl User { #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "client", derive(Updateable, Composite))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +/// # Reference +/// See pub struct User { pub id: Snowflake, pub username: String, @@ -58,8 +61,10 @@ pub struct User { #[serde(default)] #[serde(deserialize_with = "deserialize_option_number_from_string")] pub flags: Option, + pub premium: Option, + /// The type of premium (Nitro) a user has + pub premium_type: Option, pub premium_since: Option>, - pub premium_type: Option, pub pronouns: Option, pub public_flags: Option, pub banner: Option, @@ -67,13 +72,15 @@ pub struct User { pub theme_colors: Option, pub phone: Option, pub nsfw_allowed: Option, - pub premium: Option, pub purchased_flags: Option, pub premium_usage_flags: Option, pub disabled: Option, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Copy)] +/// A user's theme colors, as u32s representing hex color codes +/// +/// found in [UserProfileMetadata] pub struct ThemeColors { #[serde(flatten)] inner: (u32, u32), @@ -140,6 +147,8 @@ impl sqlx::Type for ThemeColors { } #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +/// # Reference +/// See pub struct PublicUser { pub id: Snowflake, pub username: Option, @@ -151,7 +160,9 @@ pub struct PublicUser { pub pronouns: Option, pub bot: Option, pub bio: Option, - pub premium_type: Option, + /// The type of premium (Nitro) a user has + pub premium_type: Option, + /// The date the user's premium (Nitro) subscribtion started pub premium_since: Option>, pub public_flags: Option, } @@ -182,6 +193,8 @@ const CUSTOM_USER_FLAG_OFFSET: u64 = 1 << 32; bitflags::bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, chorus_macros::SerdeBitFlags)] #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] + /// # Reference + /// See pub struct UserFlags: u64 { const DISCORD_EMPLOYEE = 1 << 0; const PARTNERED_SERVER_OWNER = 1 << 1; @@ -195,6 +208,7 @@ bitflags::bitflags! { const EARLY_SUPPORTER = 1 << 9; const TEAM_USER = 1 << 10; const TRUST_AND_SAFETY = 1 << 11; + /// Note: deprecated by Discord const SYSTEM = 1 << 12; const HAS_UNREAD_URGENT_MESSAGES = 1 << 13; const BUGHUNTER_LEVEL_2 = 1 << 14; @@ -206,14 +220,640 @@ bitflags::bitflags! { } } +#[derive( + Serialize_repr, + Deserialize_repr, + Debug, + Default, + Clone, + Eq, + PartialEq, + Hash, + Copy, + PartialOrd, + Ord, +)] +#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] +#[repr(u8)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +/// **User** premium (Nitro) type +/// +/// See +pub enum PremiumType { + #[default] + /// No Nitro + None = 0, + /// Nitro Classic + Tier1 = 1, + /// Nitro + Tier2 = 2, + /// Nitro Basic + Tier3 = 3, +} + #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +/// # Reference +/// See pub struct UserProfileMetadata { + /// The guild ID this profile applies to, if it is a guild profile. pub guild_id: Option, + /// The user's pronouns, up to 40 characters + #[serde(deserialize_with = "deserialize_default_from_null")] + // Note: spacebar will send this is as null, while it should be "" + // See issue 1188 pub pronouns: String, + /// The user's bio / description, up to 190 characters pub bio: Option, + /// The hash used to retrieve the user's banned from the CDN pub banner: Option, + /// Banner color encoded as an i32 representation of a hex color code pub accent_color: Option, + /// See [ThemeColors] pub theme_colors: Option, pub popout_animation_particle_type: Option, pub emoji: Option, } + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +/// A user's publically facing profile +/// +/// # Reference +/// See +pub struct UserProfile { + // TODO: add profile application object + pub user: PublicUser, + + #[serde(rename = "user_profile")] + pub profile_metadata: UserProfileMetadata, + + #[serde(default)] + pub badges: Vec, + + pub guild_member: Option, + + #[serde(rename = "guild_member_profile")] + pub guild_member_profile_metadata: Option, + + #[serde(default)] + pub guild_badges: Vec, + + /// The user's legacy username#discriminator, if existing and shown + pub legacy_username: Option, + + #[serde(default)] + pub mutual_guilds: Vec, + + #[serde(default)] + pub mutual_friends: Vec, + + pub mutual_friends_count: Option, + + pub connected_accounts: Vec, + + // TODO: Add application role connections! + /// The type of premium (Nitro) a user has + pub premium_type: Option, + /// The date the user's premium (Nitro) subscribtion started + pub premium_since: Option>, + /// The date the user's premium guild (Boosting) subscribtion started + pub premium_guild_since: Option>, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +/// Info about a badge on a user's profile ([UserProfile]) +/// +/// # Reference +/// See +/// +/// For a list of know badges, see +pub struct ProfileBadge { + /// The badge's unique id, e.g. "staff", "partner", "premium", ... + pub id: String, + /// Description of what the badge represents, e.g. "Discord Staff" + pub description: String, + /// An icon hash, to get the badge's icon from the CDN + pub icon: String, + /// A link (potentially used for href) for the badge. + /// + /// e.g.: + /// `"staff"` badge links to `"https://discord.com/company"` + /// `"certified_moderator"` links to `"https://discord.com/safety"` + pub link: Option, +} + +impl PartialEq for ProfileBadge { + fn eq(&self, other: &Self) -> bool { + // Note: does not include description, since it changes for some badges + // + // Think nitro "Subscriber since ...", "Server boosting since ..." + self.id.eq(&other.id) && self.icon.eq(&other.icon) && self.link.eq(&other.link) + } +} + +impl ProfileBadge { + /// Returns a badge representing the "staff" badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_staff() -> Self { + Self { + id: "staff".to_string(), + description: "Discord Staff".to_string(), + icon: "5e74e9b61934fc1f67c65515d1f7e60d".to_string(), + link: Some("https://discord.com/company".to_string()), + } + } + + /// Returns a badge representing the partnered server owner badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_partner() -> Self { + Self { + id: "partner".to_string(), + description: "Partnered Server Owner".to_string(), + icon: "3f9748e53446a137a052f3454e2de41e".to_string(), + link: Some("https://discord.com/partners".to_string()), + } + } + + /// Returns a badge representing the certified moderator badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_certified_moderator() -> Self { + Self { + id: "certified_moderator".to_string(), + description: "Moderator Programs Alumni".to_string(), + icon: "fee1624003e2fee35cb398e125dc479b".to_string(), + link: Some("https://discord.com/safety".to_string()), + } + } + + /// Returns a badge representing the hypesquad events badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_hypesquad() -> Self { + Self { + id: "hypesquad".to_string(), + description: "HypeSquad Events".to_string(), + icon: "bf01d1073931f921909045f3a39fd264".to_string(), + link: Some("https://support.discord.com/hc/en-us/articles/360035962891-Profile-Badges-101#h_01GM67K5EJ16ZHYZQ5MPRW3JT3".to_string()), + } + } + + /// Returns a badge representing the hypesquad bravery badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_hypesquad_bravery() -> Self { + Self { + id: "hypesquad_house_1".to_string(), + description: "HypeSquad Bravery".to_string(), + icon: "8a88d63823d8a71cd5e390baa45efa02".to_string(), + link: Some("https://discord.com/settings/hypesquad-online".to_string()), + } + } + + /// Returns a badge representing the hypesquad brilliance badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_hypesquad_brilliance() -> Self { + Self { + id: "hypesquad_house_2".to_string(), + description: "HypeSquad Brilliance".to_string(), + icon: "011940fd013da3f7fb926e4a1cd2e618".to_string(), + link: Some("https://discord.com/settings/hypesquad-online".to_string()), + } + } + + /// Returns a badge representing the hypesquad balance badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_hypesquad_balance() -> Self { + Self { + id: "hypesquad_house_3".to_string(), + description: "HypeSquad Balance".to_string(), + icon: "3aa41de486fa12454c3761e8e223442e".to_string(), + link: Some("https://discord.com/settings/hypesquad-online".to_string()), + } + } + + /// Returns a badge representing the bug hunter level 1 badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_bug_hunter_1() -> Self { + Self { + id: "bug_hunter_level_1".to_string(), + description: "Discord Bug Hunter".to_string(), + icon: "2717692c7dca7289b35297368a940dd0".to_string(), + link: Some( + "https://support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs" + .to_string(), + ), + } + } + + /// Returns a badge representing the bug hunter level 2 badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_bug_hunter_2() -> Self { + Self { + id: "bug_hunter_level_2".to_string(), + description: "Discord Bug Hunter".to_string(), + icon: "848f79194d4be5ff5f81505cbd0ce1e6".to_string(), + link: Some( + "https://support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs" + .to_string(), + ), + } + } + + /// Returns a badge representing the active developer badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_active_developer() -> Self { + Self { + id: "active_developer".to_string(), + description: "Active Developer".to_string(), + icon: "6bdc42827a38498929a4920da12695d9".to_string(), + link: Some( + "https://support-dev.discord.com/hc/en-us/articles/10113997751447?ref=badge" + .to_string(), + ), + } + } + + /// Returns a badge representing the early verified bot developer badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_early_verified_developer() -> Self { + Self { + id: "verified_developer".to_string(), + description: "Early Verified Bot Developer".to_string(), + icon: "6df5892e0f35b051f8b61eace34f4967".to_string(), + link: None, + } + } + + /// Returns a badge representing the early supporter badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_early_supporter() -> Self { + Self { + id: "early_supporter".to_string(), + description: "Early Supporter".to_string(), + icon: "7060786766c9c840eb3019e725d2b358".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the nitro subscriber badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_nitro() -> Self { + Self { + id: "premium".to_string(), + description: "Subscriber since 1 Jan 2015".to_string(), + icon: "2ba85e8026a8614b640c2837bcdfe21b".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 1 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_1() -> Self { + Self { + id: "guild_booster_lvl1".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "51040c70d4f20a921ad6674ff86fc95c".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 2 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_2() -> Self { + Self { + id: "guild_booster_lvl2".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "0e4080d1d333bc7ad29ef6528b6f2fb7".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 3 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_3() -> Self { + Self { + id: "guild_booster_lvl3".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "72bed924410c304dbe3d00a6e593ff59".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 4 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_4() -> Self { + Self { + id: "guild_booster_lvl4".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "df199d2050d3ed4ebf84d64ae83989f8".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 5 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_5() -> Self { + Self { + id: "guild_booster_lvl5".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "996b3e870e8a22ce519b3a50e6bdd52f".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 6 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_6() -> Self { + Self { + id: "guild_booster_lvl6".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "991c9f39ee33d7537d9f408c3e53141e".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 7 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_7() -> Self { + Self { + id: "guild_booster_lvl7".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "cb3ae83c15e970e8f3d410bc62cb8b99".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 8 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_8() -> Self { + Self { + id: "guild_booster_lvl8".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "7142225d31238f6387d9f09efaa02759".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the level 9 server boosting badge on Discord.com + /// + /// Note: The description updates for the start date + /// + /// # Reference + /// See + pub fn discord_server_boosting_9() -> Self { + Self { + id: "guild_booster_lvl9".to_string(), + description: "Server boosting since 1 Jan 2015".to_string(), + icon: "ec92202290b48d0879b7413d2dde3bab".to_string(), + link: Some("https://discord.com/settings/premium".to_string()), + } + } + + /// Returns a badge representing the legacy username badge on Discord.com + /// + /// # Reference + /// See + pub fn discord_legacy_username() -> Self { + Self { + id: "legacy_username".to_string(), + description: "Originally known as USERNAME".to_string(), + icon: "6de6d34650760ba5551a79732e98ed60".to_string(), + link: None, + } + } + + /// Returns a badge representing the legacy username badge on Discord.com, + /// with the provided username (which should already contain the #DISCRIM part) + /// + /// # Reference + /// See + pub fn discord_legacy_username_with_username(username: String) -> Self { + Self { + id: "legacy_username".to_string(), + description: format!("Originally known as {username}"), + icon: "6de6d34650760ba5551a79732e98ed60".to_string(), + link: None, + } + } + + /// Returns a badge representing the legacy username badge on Discord.com, + /// with the provided username and discriminator + /// + /// # Reference + /// See + pub fn discord_legacy_username_with_username_and_discriminator( + username: String, + discriminator: String, + ) -> Self { + Self { + id: "legacy_username".to_string(), + description: format!("Originally known as {username}#{discriminator}"), + icon: "6de6d34650760ba5551a79732e98ed60".to_string(), + link: None, + } + } + + /// Returns a badge representing the bot commands badge on Discord.com + /// + /// Note: This badge is only for bot accounts + /// + /// # Reference + /// See + pub fn discord_bot_commands() -> Self { + Self { + id: "bot_commands".to_string(), + description: "Supports Commands".to_string(), + icon: "6f9e37f9029ff57aef81db857890005e".to_string(), + link: Some( + "https://discord.com/blog/welcome-to-the-new-era-of-discord-apps?ref=badge" + .to_string(), + ), + } + } + + /// Returns a badge representing the bot automod badge on Discord.com + /// + /// Note: This badge is only for bot accounts + /// + /// # Reference + /// See + pub fn discord_bot_automod() -> Self { + Self { + id: "automod".to_string(), + description: "Uses AutoMod".to_string(), + icon: "f2459b691ac7453ed6039bbcfaccbfcd".to_string(), + link: None, + } + } + + /// Returns a badge representing the application guild subscription badge on Discord.com + /// + /// No idea where this badge could show up, but apparently it means a guild has an + /// application's premium + /// + /// # Reference + /// See + pub fn discord_application_guild_subscription() -> Self { + Self { + id: "application_guild_subscription".to_string(), + description: "This server has APPLICATION Premium".to_string(), + icon: "d2010c413a8da2208b7e4f35bd8cd4ac".to_string(), + link: None, + } + } +} + +/// Structure which shows a mutual guild with a user +/// +/// # Reference +/// See +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct MutualGuild { + pub id: Snowflake, + /// The user's nickname in the guild, if any + pub nick: Option, +} + +/// Structure which is returned by the [crate::instance::ChorusUser::get_user_note] endpoint. +/// +/// Note that [crate::instance::ChorusUser::get_user_notes] endpoint +/// returns a completely different structure; +// Specualation: this is probably how Discord stores notes internally +/// +/// # Reference +/// See +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +pub struct UserNote { + /// Actual note contents; max 256 characters + pub note: String, + /// The ID of the user the note is on + pub note_user_id: Snowflake, + /// The ID of the user who created the note (always the current user) + pub user_id: Snowflake, +} + +/// Structure which defines an affinity the local user has with another user. +/// +/// # Reference +/// See +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, PartialOrd)] +pub struct UserAffinity { + /// The other user's id + pub user_id: Snowflake, + /// The affinity score + pub affinity: f32, +} + +/// Structure which defines an affinity the local user has with a guild. +/// +/// # Reference +/// See +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, PartialOrd)] +pub struct GuildAffinity { + /// The guild's id + pub guild_id: Snowflake, + /// The affinity score + pub affinity: f32, +} + +/// Structure which defines the local user's premium perk usage. +/// +/// # Reference +/// See +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct PremiumUsage { + /// Number of Nitro stickers the user has sent + pub nitro_sticker_sends: PremiumUsageData, + /// Number of animated emojis the user has sent + pub total_animated_emojis: PremiumUsageData, + /// Number of global emojis the user has sent + pub total_global_emojis: PremiumUsageData, + /// Number of large uploads the user has made + pub total_large_uploads: PremiumUsageData, + /// Number of times the user has streamed in HD + pub total_hd_streams: PremiumUsageData, + /// Number of hours the user has streamed in HD + pub hd_hours_streamed: PremiumUsageData, +} + +/// Structure for the data in [PremiumUsage]. +/// +/// Currently only contains the number of uses of a premium perk. +/// +/// # Reference +/// See +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct PremiumUsageData { + /// Total number of uses for this perk + pub value: usize, +} + +impl From for usize { + fn from(value: PremiumUsageData) -> Self { + value.value + } +} + +impl From for PremiumUsageData { + fn from(value: usize) -> Self { + PremiumUsageData { value } + } +} diff --git a/src/types/events/message.rs b/src/types/events/message.rs index 1b855dfc..d2ca3082 100644 --- a/src/types/events/message.rs +++ b/src/types/events/message.rs @@ -149,6 +149,15 @@ pub struct MessageReactionRemoveEmoji { pub emoji: Emoji, } +#[derive(Debug, Serialize, Deserialize, Default, Clone, Copy, WebSocketEvent)] +/// Sent when a message that mentioned the current user in the last week is acknowledged and deleted. +/// +/// # Reference +/// See +pub struct RecentMentionDelete { + pub message_id: Snowflake, +} + #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// Officially Undocumented /// diff --git a/src/types/events/session.rs b/src/types/events/session.rs index a76ebc3c..8adaa336 100644 --- a/src/types/events/session.rs +++ b/src/types/events/session.rs @@ -30,7 +30,7 @@ pub struct Session { // Note: I don't think this one exists yet? Though I might've made a mistake and this might be a duplicate pub struct ClientInfo { pub client: Option, - pub os: String, + pub os: Option, pub version: u8, } diff --git a/src/types/events/user.rs b/src/types/events/user.rs index 877c96cd..fc72be4b 100644 --- a/src/types/events/user.rs +++ b/src/types/events/user.rs @@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::types::entities::PublicUser; use crate::types::events::WebSocketEvent; use crate::types::utils::Snowflake; +use crate::types::Connection; #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] /// See ; @@ -16,6 +17,27 @@ pub struct UserUpdate { pub user: PublicUser, } +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] +/// Sent to indicate updates to a user's [Connection]. +/// +/// Not documented anywhere +pub struct UserConnectionsUpdate { + #[serde(flatten)] + pub connection: Connection, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] +/// See ; +/// +/// Sent when a note the current user has on another user is modified; +/// +/// If the field "note" is an empty string, the note was removed. +pub struct UserNoteUpdate { + /// Id of the user the note is for + pub id: Snowflake, + pub note: String, +} + #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, WebSocketEvent)] /// Undocumented; /// diff --git a/src/types/schema/user.rs b/src/types/schema/user.rs index 9e25093f..7a2543a6 100644 --- a/src/types/schema/user.rs +++ b/src/types/schema/user.rs @@ -4,10 +4,13 @@ use std::collections::HashMap; -use chrono::NaiveDate; +use chrono::{DateTime, NaiveDate, Utc}; use serde::{Deserialize, Serialize}; -use crate::types::Snowflake; +use crate::types::{ + Connection, GuildAffinity, HarvestBackendType, Snowflake, ThemeColors, TwoWayLinkType, + UserAffinity, +}; #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] #[serde(rename_all = "snake_case")] @@ -41,7 +44,12 @@ pub struct UserModifySchema { pub email: Option, /// The user's email token from their previous email, required if a new email is set. /// - /// See and + /// See: + /// + /// - the endpoints and + /// + /// - the relevant methods [`ChorusUser::initiate_email_change`](crate::instance::ChorusUser::initiate_email_change) and [`ChorusUser::verify_email_change`](crate::instance::ChorusUser::verify_email_change) + /// /// for changing the user's email. /// /// # Note @@ -111,3 +119,347 @@ pub struct PrivateChannelCreateSchema { pub access_tokens: Option>, pub nicks: Option>, } + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// A schema used to modify the current user's profile. +/// +/// Similar to [crate::types::UserProfileMetadata] +/// +/// See +pub struct UserModifyProfileSchema { + // Note: one of these causes a 500 if it is sent + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new pronouns (max 40 characters) + pub pronouns: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new bio (max 190 characters) + pub bio: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + // TODO: Add banner -- do we have an image data struct + /// The user's new accent color encoded as an i32 representation of a hex color code + pub accent_color: Option, + + // Note: without the skip serializing this currently (2024/07/28) causes a 500! + // + // Which in turns locks the user's account, requiring phone number verification + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new [ThemeColors] + pub theme_colors: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new profile popup animation particle type + pub popout_animation_particle_type: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new profile emoji id + pub emoji_id: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new profile ffect id + pub profile_effect_id: Option, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// A schema used to delete or disable the current user's profile. +/// +/// See and +/// +pub struct DeleteDisableUserSchema { + /// The user's current password, if any + pub password: Option, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// A schema used for [ChorusUser::verify_email_change](crate::instance::ChorusUser::verify_email_change) +/// +/// See +pub struct VerifyUserEmailChangeSchema { + /// The verification code sent to the user's email + pub code: String, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// The return type of [ChorusUser::verify_email_change](crate::instance::ChorusUser::verify_email_change) +/// +/// See +pub struct VerifyUserEmailChangeResponse { + /// The email_token to be used in [ChorusUser::modify](crate::instance::ChorusUser::modify) + #[serde(rename = "token")] + pub email_token: String, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)] +/// Query string parameters for the route GET /users/{user.id}/profile +/// ([crate::types::User::get_profile]) +/// +/// See +pub struct GetUserProfileSchema { + #[serde(skip_serializing_if = "Option::is_none")] + /// Whether to include the mutual guilds between the current user. + /// + /// If unset it will default to true + pub with_mutual_guilds: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Whether to include the mutual friends between the current user. + /// + /// If unset it will default to false + pub with_mutual_friends: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Whether to include the number of mutual friends between the current user + /// + /// If unset it will default to false + pub with_mutual_friends_count: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// The guild id to get the user's member profile in, if any. + /// + /// Note: + /// + /// when you click on a user in the member list in the discord client, a request is sent with + /// this property set to the selected guild id. + /// + /// This makes the request include fields such as guild_member and guild_member_profile + pub guild_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// The role id to get the user's application role connection metadata in, if any. + pub connections_role_id: Option, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Internal type for the [crate::instance::ChorusUser::get_pomelo_suggestions] endpoint. +/// +/// See +pub(crate) struct GetPomeloSuggestionsReturn { + pub username: String, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Internal type for the [crate::instance::ChorusUser::get_pomelo_eligibility] endpoint. +/// +/// See +pub(crate) struct GetPomeloEligibilityReturn { + pub taken: bool, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)] +/// Query string parameters for the route GET /users/@me/mentions +/// ([crate::instance::ChorusUser::get_recent_mentions]) +/// +/// See +pub struct GetRecentMentionsSchema { + /// Only fetch messages before this message id + /// + /// Due to the nature of snowflakes, this can be easily used to fetch + /// messages before a certain timestamp + pub before: Option, + /// Max number of messages to return + /// + /// Should be between 1 and 100. + /// + /// If unset the limit is 25 messages + pub limit: Option, + /// Limit messages to a specific guild + pub guild_id: Option, + /// Whether to include role mentions. + /// + /// If unset the server assumes true + pub roles: Option, + /// Whether to include @everyone and @here mentions. + /// + /// If unset the server assumes true + pub everyone: Option, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Internal type for the [crate::instance::ChorusUser::create_harvest] endpoint. +// (koza): imo it's nicer if the user can just pass a vec, instead of having to bother with +// a specific type +/// +/// See +pub(crate) struct CreateUserHarvestSchema { + pub backends: Option>, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Internal type for the [crate::instance::ChorusUser::set_user_note] endpoint. +/// +/// See +pub(crate) struct ModifyUserNoteSchema { + pub note: Option, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Query string parameters for the route GET /connections/{connection.type}/authorize +/// ([crate::instance::ChorusUser::authorize_connection]) +/// +/// See +pub struct AuthorizeConnectionSchema { + /// The type of two-way link ([TwoWayLinkType]) to create + pub two_way_link_type: Option, + /// The device code to use for the two-way link + pub two_way_user_code: Option, + /// If this is a continuation of a previous authorization + pub continuation: bool, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Internal type for the [crate::instance::ChorusUser::authorize_connection] endpoint. +/// +/// See +pub(crate) struct AuthorizeConnectionReturn { + pub url: String, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Json schema for the route POST /connections/{connection.type}/callback ([crate::instance::ChorusUser::create_connection_callback]). +/// +/// See +pub struct CreateConnectionCallbackSchema { + /// The authorization code for the connection + pub code: String, + /// The "state" used to authorize a connection + // TODO: what is this? + pub state: String, + pub two_way_link_code: Option, + pub insecure: Option, + pub friend_sync: Option, + /// Additional parameters used for OpenID Connect + // FIXME: Is this correct? in other connections additional info + // is provided like this, only being string - string + pub openid_params: Option>, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Json schema for the route PUT /users/@me/connections/contacts/{connection.id} ([crate::instance::ChorusUser::create_contact_sync_connection]). +/// +/// See +pub struct CreateContactSyncConnectionSchema { + /// The username of the connection account + pub name: String, + /// Whether to sync friends over the connection + pub friend_sync: Option, +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Json schema for the route PATCH /users/@me/connections/{connection.type}/{connection.id} ([crate::instance::ChorusUser::modify_connection]). +/// +/// Note: not all connection types support all parameters. +/// +/// See +pub struct ModifyConnectionSchema { + /// The connection account's username + /// + /// Note: We have not found which connection this could apply to + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, + + /// Whether activities related to this connection will be shown in presence + /// + /// e.g. on a Spotify connection, "Display Spotify as your status" + #[serde(skip_serializing_if = "Option::is_none")] + pub show_activity: Option, + + /// Whether or not to sync friends from this connection + /// + /// Note: we have not found which connections this can apply to + #[serde(skip_serializing_if = "Option::is_none")] + pub friend_sync: Option, + + /// Whether to show additional metadata on the user's profile + /// + /// e.g. on a Steam connection, "Display details on profile" + /// (number of games, items, member since) + /// + /// on a Twitter connection, number of posts / followers, member since + #[serde(skip_serializing_if = "Option::is_none")] + pub metadata_visibility: Option, + + /// Whether to show the connection on the user's profile + #[serde(skip_serializing_if = "Option::is_none")] + pub visibility: Option, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Internal type for the [crate::instance::ChorusUser::get_connection_access_token] endpoint. +/// +/// See +pub(crate) struct GetConnectionAccessTokenReturn { + pub access_token: String, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd)] +/// Return type for the [crate::instance::ChorusUser::get_user_affinities] endpoint. +/// +/// See +pub struct UserAffinities { + pub user_affinities: Vec, + // FIXME: Is this also a UserAffinity vec? + // Also, no idea what this means + pub inverse_user_affinities: Vec, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd)] +/// Return type for the [crate::instance::ChorusUser::get_guild_affinities] endpoint. +/// +/// See +pub struct GuildAffinities { + pub guild_affinities: Vec, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +/// Return type for the error in the [crate::instance::ChorusUser::create_domain_connection] endpoint. +/// +/// This allows us to retrieve the needed proof for actually verifying the connection. +/// +/// See +pub(crate) struct CreateDomainConnectionError { + pub message: String, + pub code: u16, + pub proof: String, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +/// Return type for the [crate::instance::ChorusUser::create_domain_connection] endpoint. +/// +/// See +pub enum CreateDomainConnectionReturn { + /// Additional proof is needed to verify domain ownership. + /// + /// The inner object is a proof string (e.g. + /// `dh=dceaca792e3c40fcf356a9297949940af5cfe538`) + /// + /// To verify ownership, either: + /// + /// - add the proof string as a TXT DNS record to the domain, + /// with the name of the record being `_discord.{domain}` or + /// + /// - serve the proof string as a file at `https://{domain}/.well-known/discord` + /// + /// After either of these proofs are added, the request should be retried. + /// + ProofNeeded(String), + /// The domain connection was successfully created, no further action is needed. + /// + /// The inner object is the new connection. + Ok(Connection), +} + +#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +/// Return type for the [crate::instance::ChorusUser::get_burst_credits] endpoint. +/// +/// # Reference +/// ```json +/// { +/// "amount": 2, +/// "replenished_today": false, +/// "next_replenish_at": "2024-08-18T23:53:17+00:00" +/// } +/// ``` +pub struct BurstCreditsInfo { + /// Amount of remaining burst credits the local user has + pub amount: u16, + pub replenished_today: bool, + /// When the user's burst credits will automatically replenish again + pub next_replenish_at: DateTime, +} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 4b4f9c14..ac85b859 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -5,7 +5,7 @@ use std::str::FromStr; use chorus::gateway::{Gateway, GatewayOptions}; -use chorus::types::{IntoShared, PermissionFlags}; +use chorus::types::{DeleteDisableUserSchema, IntoShared, PermissionFlags}; use chorus::{ instance::{ChorusUser, Instance}, types::{ @@ -146,5 +146,9 @@ pub(crate) async fn setup() -> TestBundle { pub(crate) async fn teardown(mut bundle: TestBundle) { let id = bundle.guild.read().unwrap().id; Guild::delete(&mut bundle.user, id).await.unwrap(); - bundle.user.delete().await.unwrap() + bundle + .user + .delete(DeleteDisableUserSchema { password: None }) + .await + .unwrap() } diff --git a/tests/user.rs b/tests/user.rs index 2fbc1874..e267ae36 100644 --- a/tests/user.rs +++ b/tests/user.rs @@ -2,7 +2,19 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use chorus::types::{PublicUser, Snowflake, User}; +use chorus::{ + errors::ChorusError, + types::{ + ConnectionType, DeleteDisableUserSchema, PublicUser, Snowflake, User, + UserModifyProfileSchema, UserNote, + }, +}; +#[cfg(target_arch = "wasm32")] +use wasm_bindgen_test::*; +#[cfg(target_arch = "wasm32")] +wasm_bindgen_test_configure!(run_in_browser); + +mod common; #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), test)] @@ -20,3 +32,181 @@ fn to_public_user() { let from_user = user.into_public_user(); assert_eq!(public_user, from_user); } + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_get_user_profile() { + let mut bundle = common::setup().await; + + let user_id = bundle.user.object.read().unwrap().id; + + let user_profile = bundle + .user + .get_user_profile(user_id, chorus::types::GetUserProfileSchema::default()) + .await; + + assert!(user_profile.is_ok()); + + common::teardown(bundle).await; +} + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_modify_user_profile() { + let mut bundle = common::setup().await; + + let bio = Some(String::from("A user.")); + let pronouns = Some(String::from("they/them")); + + let modify = UserModifyProfileSchema { + bio: bio.clone(), + pronouns: pronouns.clone(), + ..Default::default() + }; + + bundle.user.modify_profile(modify).await.unwrap(); + + let user_id = bundle.user.object.read().unwrap().id; + + let user_profile = bundle + .user + .get_user_profile(user_id, chorus::types::GetUserProfileSchema::default()) + .await + .unwrap(); + + assert_eq!(user_profile.profile_metadata.bio, bio); + assert_eq!(user_profile.profile_metadata.pronouns, pronouns.unwrap()); + + common::teardown(bundle).await; +} + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_disable_user() { + let mut bundle = common::setup().await; + + let mut other_user = bundle.create_user("integrationtestuser4").await; + + other_user + .disable(DeleteDisableUserSchema { password: None }) + .await + .unwrap(); + + common::teardown(bundle).await; +} + +// Note: these two tests are currently broken. +// FIXME: readd them once bitfl0wer/server#2 is merged +/* +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_get_user_note() { + let mut bundle = common::setup().await; + + let mut other_user = bundle.create_user("integrationtestuser3").await; + + let user_id = bundle.user.object.read().unwrap().id; + let other_user_id = other_user.object.read().unwrap().id; + + let result = bundle.user.get_user_note(other_user_id).await; + assert!(matches!( + result.err().unwrap(), + ChorusError::NotFound { .. } + )); + + bundle + .user + .set_user_note(other_user_id, Some(String::from("A note."))) + .await + .unwrap(); + + assert!(false); + + let result = bundle.user.get_user_note(other_user_id).await; + assert_eq!( + result, + Ok(UserNote { + user_id, + note_user_id: other_user_id, + note: String::from("A note.") + }) + ); + + other_user + .delete(DeleteDisableUserSchema { password: None }) + .await + .unwrap(); + common::teardown(bundle).await; +} + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_set_user_note() { + let mut bundle = common::setup().await; + + let mut other_user = bundle.create_user("integrationtestuser3").await; + + let user_id = bundle.user.object.read().unwrap().id; + let other_user_id = other_user.object.read().unwrap().id; + + bundle + .user + .set_user_note(other_user_id, Some(String::from("A note."))) + .await + .unwrap(); + + let result = bundle.user.get_user_note(other_user_id).await; + assert_eq!( + result, + Ok(UserNote { + user_id, + note_user_id: other_user_id, + note: String::from("A note.") + }) + ); + + other_user + .delete(DeleteDisableUserSchema { password: None }) + .await + .unwrap(); + common::teardown(bundle).await; +}*/ + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_get_user_affinities() { + let mut bundle = common::setup().await; + + let result = bundle.user.get_user_affinities().await.unwrap(); + + assert!(result.user_affinities.is_empty()); + assert!(result.inverse_user_affinities.is_empty()); + + common::teardown(bundle).await; +} + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_get_guild_affinities() { + let mut bundle = common::setup().await; + + let result = bundle.user.get_guild_affinities().await.unwrap(); + + assert!(result.guild_affinities.is_empty()); + + common::teardown(bundle).await; +} + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn test_get_connections() { + let mut bundle = common::setup().await; + + let result = bundle.user.get_connections().await.unwrap(); + + // We can't *really* test creating or getting connections... + // TODO: Find a way? + assert!(result.is_empty()); + + common::teardown(bundle).await; +} From 08783cc5b8e1241392a994966ddd8a8112c4a70a Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Sat, 28 Sep 2024 10:32:33 +0200 Subject: [PATCH 152/162] Differentiate between instance softwares (#560) * Add InstanceOptions type * feat: add /ping and /version, implement software differentiation * fix: better error handling, missing slash in /policies/instance - handle deserialization errors and not parsing the http content into a string - the route only works on spacebar if you add a trailing slash for some reason --- src/api/instance.rs | 104 ++++++++++++++++++++++++++ src/api/mod.rs | 2 + src/api/policies/instance/instance.rs | 27 ++++++- src/gateway/options.rs | 19 +++++ src/instance.rs | 104 +++++++++++++++++++++++++- src/types/schema/instance.rs | 84 +++++++++++++++++++++ src/types/schema/mod.rs | 4 +- tests/instance.rs | 14 ++++ 8 files changed, 352 insertions(+), 6 deletions(-) create mode 100644 src/api/instance.rs create mode 100644 src/types/schema/instance.rs diff --git a/src/api/instance.rs b/src/api/instance.rs new file mode 100644 index 00000000..20680e41 --- /dev/null +++ b/src/api/instance.rs @@ -0,0 +1,104 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! Contains miscellaneous api routes, such as /version and /ping +use serde_json::from_str; + +use crate::errors::{ChorusError, ChorusResult}; +use crate::instance::Instance; +use crate::types::{GeneralConfiguration, PingReturn, VersionReturn}; + +impl Instance { + /// Pings the instance, also fetches instance info. + /// + /// See: [PingReturn] + /// + /// # Notes + /// This is a Spacebar only endpoint. + /// + /// # Reference + /// See + pub async fn ping(&self) -> ChorusResult { + let endpoint_url = format!("{}/ping", self.urls.api.clone()); + + let request = match self.client.get(&endpoint_url).send().await { + Ok(result) => result, + Err(e) => { + return Err(ChorusError::RequestFailed { + url: endpoint_url, + error: e.to_string(), + }); + } + }; + + if !request.status().as_str().starts_with('2') { + return Err(ChorusError::ReceivedErrorCode { + error_code: request.status().as_u16(), + error: request.text().await.unwrap(), + }); + } + + let response_text = match request.text().await { + Ok(string) => string, + Err(e) => { + return Err(ChorusError::InvalidResponse { + error: format!( + "Error while trying to process the HTTP response into a String: {}", + e + ), + }); + } + }; + + match from_str::(&response_text) { + Ok(return_value) => Ok(return_value), + Err(e) => Err(ChorusError::InvalidResponse { error: format!("Error while trying to deserialize the JSON response into requested type T: {}. JSON Response: {}", + e, response_text) }) + } + } + + /// Fetches the instance's software implementation and version. + /// + /// See: [VersionReturn] + /// + /// # Notes + /// This is a Symfonia only endpoint. (For now, we hope that spacebar will adopt it as well) + pub async fn get_version(&self) -> ChorusResult { + let endpoint_url = format!("{}/version", self.urls.api.clone()); + + let request = match self.client.get(&endpoint_url).send().await { + Ok(result) => result, + Err(e) => { + return Err(ChorusError::RequestFailed { + url: endpoint_url, + error: e.to_string(), + }); + } + }; + + if !request.status().as_str().starts_with('2') { + return Err(ChorusError::ReceivedErrorCode { + error_code: request.status().as_u16(), + error: request.text().await.unwrap(), + }); + } + + let response_text = match request.text().await { + Ok(string) => string, + Err(e) => { + return Err(ChorusError::InvalidResponse { + error: format!( + "Error while trying to process the HTTP response into a String: {}", + e + ), + }); + } + }; + + match from_str::(&response_text) { + Ok(return_value) => Ok(return_value), + Err(e) => Err(ChorusError::InvalidResponse { error: format!("Error while trying to deserialize the JSON response into requested type T: {}. JSON Response: {}", e, response_text) }) + } + } +} diff --git a/src/api/mod.rs b/src/api/mod.rs index c9ca2792..5e2f7cab 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -10,6 +10,7 @@ pub use guilds::*; pub use invites::*; pub use policies::instance::instance::*; pub use users::*; +pub use instance::*; pub mod auth; pub mod channels; @@ -17,3 +18,4 @@ pub mod guilds; pub mod invites; pub mod policies; pub mod users; +pub mod instance; diff --git a/src/api/policies/instance/instance.rs b/src/api/policies/instance/instance.rs index 584db338..f2a40bc1 100644 --- a/src/api/policies/instance/instance.rs +++ b/src/api/policies/instance/instance.rs @@ -17,7 +17,7 @@ impl Instance { /// # Reference /// See pub async fn general_configuration_schema(&self) -> ChorusResult { - let endpoint_url = self.urls.api.clone() + "/policies/instance"; + let endpoint_url = self.urls.api.clone() + "/policies/instance/"; let request = match self.client.get(&endpoint_url).send().await { Ok(result) => result, Err(e) => { @@ -35,7 +35,28 @@ impl Instance { }); } - let body = request.text().await.unwrap(); - Ok(from_str::(&body).unwrap()) + let response_text = match request.text().await { + Ok(string) => string, + Err(e) => { + return Err(ChorusError::InvalidResponse { + error: format!( + "Error while trying to process the HTTP response into a String: {}", + e + ), + }); + } + }; + + match from_str::(&response_text) { + Ok(object) => Ok(object), + Err(e) => { + Err(ChorusError::InvalidResponse { + error: format!( + "Error while trying to deserialize the JSON response into requested type T: {}. JSON Response: {}", + e, response_text + ), + }) + } + } } } diff --git a/src/gateway/options.rs b/src/gateway/options.rs index 4ff6178b..b8ded327 100644 --- a/src/gateway/options.rs +++ b/src/gateway/options.rs @@ -2,6 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use crate::instance::InstanceSoftware; + #[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Debug, Default, Copy)] /// Options passed when initializing the gateway connection. /// @@ -22,6 +24,23 @@ pub struct GatewayOptions { } impl GatewayOptions { + /// Creates the ideal gateway options for an [InstanceSoftware], + /// based off which features it supports. + pub fn for_instance_software(software: InstanceSoftware) -> GatewayOptions { + // TODO: Support ETF + let encoding = GatewayEncoding::Json; + + let transport_compression = match software.supports_gateway_zlib() { + true => GatewayTransportCompression::ZLibStream, + false => GatewayTransportCompression::None, + }; + + GatewayOptions { + encoding, + transport_compression, + } + } + /// Adds the options to an existing gateway url /// /// Returns the new url diff --git a/src/instance.rs b/src/instance.rs index a8671e0a..f0569a99 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -28,11 +28,12 @@ use crate::UrlBundle; pub struct Instance { pub urls: UrlBundle, pub instance_info: GeneralConfiguration, + pub(crate) software: InstanceSoftware, pub limits_information: Option, #[serde(skip)] pub client: Client, #[serde(skip)] - pub gateway_options: GatewayOptions, + pub(crate) gateway_options: GatewayOptions, } #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq)] @@ -72,6 +73,8 @@ impl Instance { /// If `options` is `None`, the default [`GatewayOptions`] will be used. /// /// To create an Instance from one singular url, use [`Instance::new()`]. + // Note: maybe make this just take urls and then add another method which creates an instance + // from urls and custom gateway options, since gateway options will be automatically generated? pub async fn from_url_bundle( urls: UrlBundle, options: Option, @@ -88,6 +91,7 @@ impl Instance { } else { limit_information = None } + let mut instance = Instance { urls: urls.clone(), // Will be overwritten in the next step @@ -95,7 +99,10 @@ impl Instance { limits_information: limit_information, client: Client::new(), gateway_options: options.unwrap_or_default(), + // Will also be detected soon + software: InstanceSoftware::Other, }; + instance.instance_info = match instance.general_configuration_schema().await { Ok(schema) => schema, Err(e) => { @@ -103,6 +110,13 @@ impl Instance { GeneralConfiguration::default() } }; + + instance.software = instance.detect_software().await; + + if options.is_none() { + instance.gateway_options = GatewayOptions::for_instance_software(instance.software()); + } + Ok(instance) } @@ -133,12 +147,98 @@ impl Instance { } } - /// Sets the [`GatewayOptions`] the instance will use when spawning new connections. + /// Detects which [InstanceSoftware] the instance is running. + pub async fn detect_software(&self) -> InstanceSoftware { + + if let Ok(version) = self.get_version().await { + match version.server.to_lowercase().as_str() { + "symfonia" => return InstanceSoftware::Symfonia, + // We can dream this will be implemented one day + "spacebar" => return InstanceSoftware::SpacebarTypescript, + _ => {} + } + } + + // We know it isn't a symfonia server now, work around spacebar + // not really having a version endpoint + let ping = self.ping().await; + + if ping.is_ok() { + return InstanceSoftware::SpacebarTypescript; + } + + InstanceSoftware::Other + } + + /// Returns the [`GatewayOptions`] the instance uses when spawning new connections. + /// + /// These options are used on the gateways created when logging in and registering. + pub fn gateway_options(&self) -> GatewayOptions { + self.gateway_options + } + + /// Manually sets the [`GatewayOptions`] the instance should use when spawning new connections. /// /// These options are used on the gateways created when logging in and registering. pub fn set_gateway_options(&mut self, options: GatewayOptions) { self.gateway_options = options; } + + /// Returns which [`InstanceSoftware`] the instance is running. + pub fn software(&self) -> InstanceSoftware { + self.software + } + + /// Manually sets which [`InstanceSoftware`] the instance is running. + /// + /// Note: you should only use this if you are absolutely sure about an instance (e. g. you run it). + /// If set to an incorrect value, this may cause unexpected errors or even undefined behaviours. + /// + /// Manually setting the software is generally discouraged. Chorus should automatically detect + /// which type of software the instance is running. + pub fn set_software(&mut self, software: InstanceSoftware) { + self.software = software; + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +/// The software implementation the spacebar-compatible instance is running. +/// +/// This is useful since some softwares may support additional features, +/// while other do not fully implement the api yet. +pub enum InstanceSoftware { + /// The official typescript Spacebar server, available + /// at + SpacebarTypescript, + /// The Polyphony server written in rust, available at + /// at + Symfonia, + /// We could not determine the instance software or it + /// is one we don't specifically differentiate. + /// + /// Assume it implements all features of the spacebar protocol. + #[default] + Other, +} + +impl InstanceSoftware { + /// Returns whether the software supports z-lib stream compression on the gateway + pub fn supports_gateway_zlib(self) -> bool { + match self { + InstanceSoftware::SpacebarTypescript => true, + InstanceSoftware::Symfonia => false, + InstanceSoftware::Other => true, + } + } + + /// Returns whether the software supports sending data in the Erlang external term format on the gateway + pub fn supports_gateway_etf(self) -> bool { + match self { + InstanceSoftware::SpacebarTypescript => true, + InstanceSoftware::Symfonia => false, + InstanceSoftware::Other => true, + } + } } #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] diff --git a/src/types/schema/instance.rs b/src/types/schema/instance.rs new file mode 100644 index 00000000..7d19483c --- /dev/null +++ b/src/types/schema/instance.rs @@ -0,0 +1,84 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! Contains schema for miscellaneous api routes, such as /version and /ping +//! +//! Implementations of those routes can be found in /api/instance.rs + +use serde::{Deserialize, Serialize}; + +use crate::types::{GeneralConfiguration, Snowflake}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +/// The return type of the spacebar-only /api/ping endpoint +pub struct PingReturn { + /// Note: always "pong!" + pub ping: String, + pub instance: PingInstance, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +#[serde(rename_all = "camelCase")] +/// [GeneralConfiguration] as returned from the /api/ping endpoint +pub struct PingInstance { + pub id: Option, + pub name: String, + pub description: Option, + pub image: Option, + pub correspondence_email: Option, + pub correspondence_user_id: Option, + pub front_page: Option, + pub tos_page: Option, +} + +impl PingInstance { + /// Converts self into the [GeneralConfiguration] type + pub fn into_general_configuration(self) -> GeneralConfiguration { + GeneralConfiguration { + instance_name: self.name, + instance_description: self.description, + front_page: self.front_page, + tos_page: self.tos_page, + correspondence_email: self.correspondence_email, + correspondence_user_id: self.correspondence_user_id, + image: self.image, + instance_id: self.id, + } + } + + /// Converts the [GeneralConfiguration] type into self + pub fn from_general_configuration(other: GeneralConfiguration) -> Self { + Self { + id: other.instance_id, + name: other.instance_name, + description: other.instance_description, + image: other.image, + correspondence_email: other.correspondence_email, + correspondence_user_id: other.correspondence_user_id, + front_page: other.front_page, + tos_page: other.tos_page, + } + } +} + +impl From for GeneralConfiguration { + fn from(value: PingInstance) -> Self { + value.into_general_configuration() + } +} + +impl From for PingInstance { + fn from(value: GeneralConfiguration) -> Self { + Self::from_general_configuration(value) + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +/// The return type of the symfonia-only /version endpoint +pub struct VersionReturn { + /// The instance's software version, e. g. "0.1.0" + pub version: String, + /// The instance's software, e. g. "symfonia" or "spacebar" + pub server: String, +} diff --git a/src/types/schema/mod.rs b/src/types/schema/mod.rs index 09e542e4..2888046e 100644 --- a/src/types/schema/mod.rs +++ b/src/types/schema/mod.rs @@ -13,6 +13,7 @@ pub use role::*; pub use user::*; pub use invites::*; pub use voice_state::*; +pub use instance::*; mod apierror; mod audit_log; @@ -25,9 +26,10 @@ mod role; mod user; mod invites; mod voice_state; +mod instance; #[derive(Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq, PartialOrd, Eq, Ord)] pub struct GenericSearchQueryWithLimit { pub query: String, pub limit: Option, -} \ No newline at end of file +} diff --git a/tests/instance.rs b/tests/instance.rs index eb5fc606..d83e5e74 100644 --- a/tests/instance.rs +++ b/tests/instance.rs @@ -3,6 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. mod common; +use chorus::instance::InstanceSoftware; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; #[cfg(target_arch = "wasm32")] @@ -19,3 +20,16 @@ async fn generate_general_configuration_schema() { .unwrap(); common::teardown(bundle).await; } + +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +async fn detect_instance_software() { + let bundle = common::setup().await; + + let software = bundle.instance.detect_software().await; + assert_eq!(software, InstanceSoftware::SpacebarTypescript); + + assert_eq!(bundle.instance.software(), InstanceSoftware::SpacebarTypescript); + + common::teardown(bundle).await; +} From 3aac8ea4e6917c5535d3cc31c5a1656554494c28 Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Sat, 28 Sep 2024 23:09:49 +0200 Subject: [PATCH 153/162] Ready Event Updates (#561) * Update Ready, Split Ready into User and Bot variants * add supplemental to_bot method for gatewayready * Use serde(default) to fix missing attrs in spacebar server impl --- src/types/events/ready.rs | 107 +++++++++++++++++++++++++++++++++----- 1 file changed, 95 insertions(+), 12 deletions(-) diff --git a/src/types/events/ready.rs b/src/types/events/ready.rs index ffba526a..b5aceea1 100644 --- a/src/types/events/ready.rs +++ b/src/types/events/ready.rs @@ -2,38 +2,121 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use std::collections::HashMap; + use serde::{Deserialize, Serialize}; use crate::types::entities::{Guild, User}; use crate::types::events::{Session, WebSocketEvent}; -use crate::types::{Activity, Channel, ClientStatusObject, GuildMember, PresenceUpdate, Snowflake, VoiceState}; +use crate::types::{ + Activity, Channel, ClientStatusObject, GuildMember, PresenceUpdate, Relationship, Snowflake, + UserSettings, VoiceState, +}; #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] -/// 1/2 officially documented; -/// Received after identifying, provides initial user info; +/// Received after identifying, provides initial user info /// /// See and -// TODO: There are a LOT of fields missing here pub struct GatewayReady { - pub analytics_token: Option, - pub auth_session_id_hash: Option, - pub country_code: Option, + pub analytics_token: String, + pub auth_session_id_hash: String, + pub country_code: String, + pub v: u8, + pub user: User, + #[serde(default)] + pub guilds: Vec, + pub presences: Option>, + pub sessions: Option>, + pub session_id: String, + pub session_type: String, + pub resume_gateway_url: String, + pub shard: Option<(u64, u64)>, + pub user_settings: Option, + pub user_settings_proto: Option, + #[serde(default)] + pub relationships: Vec, + pub friend_suggestion_count: u32, + #[serde(default)] + pub private_channels: Vec, + #[serde(default)] + pub notes: HashMap, + pub merged_presences: Option, + #[serde(default)] + pub users: Vec, + pub auth_token: Option, + #[serde(default)] + pub authenticator_types: Vec, + pub required_action: Option, + #[serde(default)] + pub geo_ordered_rtc_regions: Vec, + /// TODO: Make tutorial object into object + pub tutorial: Option, + pub api_code_version: u8, + #[serde(default)] + pub experiments: Vec, + #[serde(default)] + pub guild_experiments: Vec, +} +#[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] +/// Received after identifying, provides initial information about the bot session. +/// +/// See and +pub struct GatewayReadyBot { pub v: u8, pub user: User, - /// For bots these are [crate::types::UnavailableGuild]s, for users they are [Guild] pub guilds: Vec, pub presences: Option>, pub sessions: Option>, pub session_id: String, - pub session_type: Option, - pub resume_gateway_url: Option, + pub session_type: String, + pub resume_gateway_url: String, pub shard: Option<(u64, u64)>, + pub merged_presences: Option, + pub users: Vec, + pub authenticator_types: Vec, + pub geo_ordered_rtc_regions: Vec, + pub api_code_version: u8, +} + +impl From for GatewayReadyBot { + fn from(value: GatewayReady) -> Self { + GatewayReadyBot { + v: value.v, + user: value.user, + guilds: value.guilds, + presences: value.presences, + sessions: value.sessions, + session_id: value.session_id, + session_type: value.session_type, + resume_gateway_url: value.resume_gateway_url, + shard: value.shard, + merged_presences: value.merged_presences, + users: value.users, + authenticator_types: value.authenticator_types, + geo_ordered_rtc_regions: value.geo_ordered_rtc_regions, + api_code_version: value.api_code_version, + } + } +} + +impl GatewayReady { + /// Convert this struct into a [GatewayReadyBot] struct + pub fn to_bot(self) -> GatewayReadyBot { + self.into() + } +} +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash)] +#[repr(u8)] +pub enum AuthenticatorType { + WebAuthn = 1, + Totp = 2, + Sms = 3, } #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// Officially Undocumented; -/// Sent after the READY event when a client is a user, +/// Sent after the READY event when a client is a user, /// seems to somehow add onto the ready event; /// /// See @@ -52,7 +135,7 @@ pub struct GatewayReadySupplemental { pub struct MergedPresences { /// "Presences of the user's guilds in the same order as the guilds array in ready" /// (discord.sex) - pub guilds: Vec>, + pub guilds: Vec>, /// "Presences of the user's friends and implicit relationships" (discord.sex) pub friends: Vec, } From 048d129f521101c644468752f39d91b81aaf37ef Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 29 Sep 2024 12:04:25 +0200 Subject: [PATCH 154/162] Add "Merging" section --- CONTRIBUTING.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 84e70210..0bad470e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,3 +10,7 @@ ever since [we streamlined the process of doing so](https://github.com/polyphony If you'd like to contribute new functionality, check out [The 'Meta'-issues.](https://github.com/polyphony-chat/chorus/issues?q=is%3Aissue+label%3A%22Type%3A+Meta%22+) They contain a comprehensive list of all features which are yet missing for full Discord.com compatibility. Please feel free to open an Issue with the idea you have, or a Pull Request. + +## Merging + +All pull requests opened into the `dev` branch should be merged via the "Squash and Merge" option to keep the commit history small. Merging into the `main` branch should be done via a regular merge commit. This way, GitHub will correctly attribute contributors and count statistics for the insights tab. From 36a4ac9b516aaa18d33dc056759f8903605db343 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 29 Sep 2024 13:26:18 +0200 Subject: [PATCH 155/162] Document all fields of GatewayReady and GatewayReadyBot --- src/types/events/ready.rs | 65 +++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/src/types/events/ready.rs b/src/types/events/ready.rs index b5aceea1..98bdaa6c 100644 --- a/src/types/events/ready.rs +++ b/src/types/events/ready.rs @@ -14,47 +14,80 @@ use crate::types::{ }; #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] -/// Received after identifying, provides initial user info +/// Received after identifying, provides initial user information and client state. /// /// See and pub struct GatewayReady { + #[serde(default)] + /// An array of stringified JSON values representing the connection trace, used for debugging + pub _trace: Vec, + /// The token used for analytical tracking requests pub analytics_token: String, + /// The hash of the auth session ID corresponding to the auth token used to connect pub auth_session_id_hash: String, + /// The detected ISO 3166-1 alpha-2 country code of the user's current IP address pub country_code: String, - pub v: u8, + #[serde(rename = "v")] + /// API version + pub api_version: u8, + /// The connected user pub user: User, #[serde(default)] + /// The guilds the user is in pub guilds: Vec, + /// The presences of the user's non-offline friends and implicit relationships (depending on the `NO_AFFINE_USER_IDS` Gateway capability). pub presences: Option>, pub sessions: Option>, + /// Unique session ID, used for resuming connections pub session_id: String, + /// The type of session that was started pub session_type: String, + /// WebSocket URL for resuming connections pub resume_gateway_url: String, + /// The shard information (shard_id, num_shards) associated with this session, if sharded pub shard: Option<(u64, u64)>, + /// The client settings for the user pub user_settings: Option, + /// The base-64 encoded preloaded user settings for the user, (if missing, defaults are used) pub user_settings_proto: Option, #[serde(default)] + /// The relationships the user has with other users pub relationships: Vec, + /// The number of friend suggestions the user has pub friend_suggestion_count: u32, #[serde(default)] + /// The DMs and group DMs the user is participating in pub private_channels: Vec, #[serde(default)] + /// A mapping of user IDs to notes the user has made for them pub notes: HashMap, + /// The presences of the user's non-offline friends and implicit relationships (depending on the `NO_AFFINE_USER_IDS` Gateway capability), and any guild presences sent at startup pub merged_presences: Option, #[serde(default)] + /// The deduped users across all objects in the event pub users: Vec, + /// The refreshed auth token for this user; if present, the client should discard the current auth token and use this in subsequent requests to the API pub auth_token: Option, #[serde(default)] + /// The types of multi-factor authenticators the user has enabled pub authenticator_types: Vec, + /// The action a user is required to take before continuing to use Discord pub required_action: Option, #[serde(default)] + /// A geo-ordered list of RTC regions that can be used when when setting a voice channel's `rtc_region` or updating the client's voice state pub geo_ordered_rtc_regions: Vec, + /// The tutorial state of the user, if any /// TODO: Make tutorial object into object pub tutorial: Option, + /// The API code version, used when re-identifying with client state v2 pub api_code_version: u8, #[serde(default)] + /// User experiment rollouts for the user + /// TODO: Make User Experiments into own struct pub experiments: Vec, #[serde(default)] + /// Guild experiment rollouts for the user + /// TODO: Make Guild Experiments into own struct pub guild_experiments: Vec, } @@ -63,30 +96,49 @@ pub struct GatewayReady { /// /// See and pub struct GatewayReadyBot { - pub v: u8, + #[serde(default)] + /// An array of stringified JSON values representing the connection trace, used for debugging + pub _trace: Vec, + #[serde(rename = "v")] + /// API version + pub api_version: u8, + /// The connected bot user pub user: User, + #[serde(default)] + /// The guilds the bot user is in. Will be `UnavailableGuilds` at first. pub guilds: Vec, + /// The presences of the user's non-offline friends and implicit relationships (depending on the `NO_AFFINE_USER_IDS` Gateway capability). pub presences: Option>, - pub sessions: Option>, + /// Unique session ID, used for resuming connections pub session_id: String, + /// The type of session that was started pub session_type: String, + /// WebSocket URL for resuming connections pub resume_gateway_url: String, + /// The shard information (shard_id, num_shards) associated with this session, if sharded pub shard: Option<(u64, u64)>, + /// The presences of the user's non-offline friends and implicit relationships (depending on the `NO_AFFINE_USER_IDS` Gateway capability), and any guild presences sent at startup pub merged_presences: Option, + #[serde(default)] + /// The deduped users across all objects in the event pub users: Vec, + #[serde(default)] + /// The types of multi-factor authenticators the user has enabled pub authenticator_types: Vec, + #[serde(default)] + /// A geo-ordered list of RTC regions that can be used when when setting a voice channel's `rtc_region` or updating the client's voice state pub geo_ordered_rtc_regions: Vec, + /// The API code version, used when re-identifying with client state v2 pub api_code_version: u8, } impl From for GatewayReadyBot { fn from(value: GatewayReady) -> Self { GatewayReadyBot { - v: value.v, + api_version: value.api_version, user: value.user, guilds: value.guilds, presences: value.presences, - sessions: value.sessions, session_id: value.session_id, session_type: value.session_type, resume_gateway_url: value.resume_gateway_url, @@ -96,6 +148,7 @@ impl From for GatewayReadyBot { authenticator_types: value.authenticator_types, geo_ordered_rtc_regions: value.geo_ordered_rtc_regions, api_code_version: value.api_code_version, + _trace: value._trace, } } } From e0c6fce4b59f748b83e5a16ee95119abb2227e6b Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 29 Sep 2024 15:13:35 +0200 Subject: [PATCH 156/162] Fix PostgreSQL compatibility of READY and some newer enum types --- src/types/entities/user.rs | 23 ++++++++++++----------- src/types/events/ready.rs | 18 ++++++++++-------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index 9c7c3b9d..bd74a8cb 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -7,7 +7,7 @@ use crate::types::utils::Snowflake; use crate::{UInt32, UInt8}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use serde_aux::prelude::{deserialize_option_number_from_string, deserialize_default_from_null}; +use serde_aux::prelude::{deserialize_default_from_null, deserialize_option_number_from_string}; use serde_repr::{Deserialize_repr, Serialize_repr}; use std::array::TryFromSliceError; use std::fmt::Debug; @@ -234,7 +234,8 @@ bitflags::bitflags! { Ord, )] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// **User** premium (Nitro) type /// @@ -258,9 +259,9 @@ pub struct UserProfileMetadata { /// The guild ID this profile applies to, if it is a guild profile. pub guild_id: Option, /// The user's pronouns, up to 40 characters - #[serde(deserialize_with = "deserialize_default_from_null")] - // Note: spacebar will send this is as null, while it should be "" - // See issue 1188 + #[serde(deserialize_with = "deserialize_default_from_null")] + // Note: spacebar will send this is as null, while it should be "" + // See issue 1188 pub pronouns: String, /// The user's bio / description, up to 190 characters pub bio: Option, @@ -847,13 +848,13 @@ pub struct PremiumUsageData { } impl From for usize { - fn from(value: PremiumUsageData) -> Self { - value.value - } + fn from(value: PremiumUsageData) -> Self { + value.value + } } impl From for PremiumUsageData { - fn from(value: usize) -> Self { - PremiumUsageData { value } - } + fn from(value: usize) -> Self { + PremiumUsageData { value } + } } diff --git a/src/types/events/ready.rs b/src/types/events/ready.rs index 98bdaa6c..d8c11de1 100644 --- a/src/types/events/ready.rs +++ b/src/types/events/ready.rs @@ -12,6 +12,7 @@ use crate::types::{ Activity, Channel, ClientStatusObject, GuildMember, PresenceUpdate, Relationship, Snowflake, UserSettings, VoiceState, }; +use crate::{UInt32, UInt64, UInt8}; #[derive(Debug, Deserialize, Serialize, Default, Clone, WebSocketEvent)] /// Received after identifying, provides initial user information and client state. @@ -29,7 +30,7 @@ pub struct GatewayReady { pub country_code: String, #[serde(rename = "v")] /// API version - pub api_version: u8, + pub api_version: UInt8, /// The connected user pub user: User, #[serde(default)] @@ -45,7 +46,7 @@ pub struct GatewayReady { /// WebSocket URL for resuming connections pub resume_gateway_url: String, /// The shard information (shard_id, num_shards) associated with this session, if sharded - pub shard: Option<(u64, u64)>, + pub shard: Option<(UInt64, UInt64)>, /// The client settings for the user pub user_settings: Option, /// The base-64 encoded preloaded user settings for the user, (if missing, defaults are used) @@ -54,7 +55,7 @@ pub struct GatewayReady { /// The relationships the user has with other users pub relationships: Vec, /// The number of friend suggestions the user has - pub friend_suggestion_count: u32, + pub friend_suggestion_count: UInt32, #[serde(default)] /// The DMs and group DMs the user is participating in pub private_channels: Vec, @@ -80,7 +81,7 @@ pub struct GatewayReady { /// TODO: Make tutorial object into object pub tutorial: Option, /// The API code version, used when re-identifying with client state v2 - pub api_code_version: u8, + pub api_code_version: UInt8, #[serde(default)] /// User experiment rollouts for the user /// TODO: Make User Experiments into own struct @@ -101,7 +102,7 @@ pub struct GatewayReadyBot { pub _trace: Vec, #[serde(rename = "v")] /// API version - pub api_version: u8, + pub api_version: UInt8, /// The connected bot user pub user: User, #[serde(default)] @@ -116,7 +117,7 @@ pub struct GatewayReadyBot { /// WebSocket URL for resuming connections pub resume_gateway_url: String, /// The shard information (shard_id, num_shards) associated with this session, if sharded - pub shard: Option<(u64, u64)>, + pub shard: Option<(UInt64, UInt64)>, /// The presences of the user's non-offline friends and implicit relationships (depending on the `NO_AFFINE_USER_IDS` Gateway capability), and any guild presences sent at startup pub merged_presences: Option, #[serde(default)] @@ -129,7 +130,7 @@ pub struct GatewayReadyBot { /// A geo-ordered list of RTC regions that can be used when when setting a voice channel's `rtc_region` or updating the client's voice state pub geo_ordered_rtc_regions: Vec, /// The API code version, used when re-identifying with client state v2 - pub api_code_version: u8, + pub api_code_version: UInt8, } impl From for GatewayReadyBot { @@ -160,7 +161,8 @@ impl GatewayReady { } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash)] -#[repr(u8)] +#[cfg_attr(not(feature = "sqlx"), repr(u8))] +#[cfg_attr(feature = "sqlx", repr(i16))] pub enum AuthenticatorType { WebAuthn = 1, Totp = 2, From 36073f1e24a1158520454acbfdb6e0e1a400e29b Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Mon, 30 Sep 2024 23:12:47 +0200 Subject: [PATCH 157/162] Adjust premium_type field to be of type PremiumType (#563) --- src/types/config/types/subconfigs/defaults/user.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/types/config/types/subconfigs/defaults/user.rs b/src/types/config/types/subconfigs/defaults/user.rs index a533b0ac..982507ea 100644 --- a/src/types/config/types/subconfigs/defaults/user.rs +++ b/src/types/config/types/subconfigs/defaults/user.rs @@ -4,11 +4,13 @@ use serde::{Deserialize, Serialize}; +use crate::types::PremiumType; + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, Hash, PartialOrd, Ord)] #[serde(rename_all = "camelCase")] pub struct UserDefaults { pub premium: bool, - pub premium_type: u8, + pub premium_type: PremiumType, pub verified: bool, } @@ -16,7 +18,7 @@ impl Default for UserDefaults { fn default() -> Self { Self { premium: true, - premium_type: 2, + premium_type: PremiumType::Tier2, verified: true, } } From 9db77fb515c7a18770a9ce7037ec30ce84541278 Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Mon, 7 Oct 2024 21:38:33 +0200 Subject: [PATCH 158/162] Implement custom sqlx::Postgres en-/decoding for PremiumType enum (#565) --- src/types/entities/user.rs | 48 +++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index bd74a8cb..5e761307 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -233,9 +233,7 @@ bitflags::bitflags! { PartialOrd, Ord, )] -#[cfg_attr(feature = "sqlx", derive(sqlx::Type))] -#[cfg_attr(not(feature = "sqlx"), repr(u8))] -#[cfg_attr(feature = "sqlx", repr(i16))] +#[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] /// **User** premium (Nitro) type /// @@ -252,6 +250,50 @@ pub enum PremiumType { Tier3 = 3, } +impl TryFrom for PremiumType { + type Error = ChorusError; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::None), + 1 => Ok(Self::Tier1), + 2 => Ok(Self::Tier2), + 3 => Ok(Self::Tier3), + _ => Err(ChorusError::InvalidArguments { + error: "Value is not a valid PremiumType".to_string(), + }), + } + } +} + +#[cfg(feature = "sqlx")] +impl sqlx::Type for PremiumType { + fn type_info() -> ::TypeInfo { + >::type_info() + } +} + +#[cfg(feature = "sqlx")] +impl<'q> sqlx::Encode<'q, sqlx::Postgres> for PremiumType { + fn encode_by_ref( + &self, + buf: &mut ::ArgumentBuffer<'q>, + ) -> Result { + let sqlx_pg_uint = sqlx_pg_uint::PgU8::from(*self as u8); + sqlx_pg_uint.encode_by_ref(buf) + } +} + +#[cfg(feature = "sqlx")] +impl<'r> sqlx::Decode<'r, sqlx::Postgres> for PremiumType { + fn decode( + value: ::ValueRef<'r>, + ) -> Result { + let sqlx_pg_uint = sqlx_pg_uint::PgU8::decode(value)?; + PremiumType::try_from(sqlx_pg_uint.to_uint()).map_err(|e| e.into()) + } +} + #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] /// # Reference /// See From 7db34f72a2f6bb6b440040d69e4fcf1c60b519c5 Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Tue, 8 Oct 2024 15:37:35 +0200 Subject: [PATCH 159/162] Make Relationship struct sqlx/symfonia-ready (#567) --- src/types/entities/relationship.rs | 60 +++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/types/entities/relationship.rs b/src/types/entities/relationship.rs index 08cb41f1..e6d14f42 100644 --- a/src/types/entities/relationship.rs +++ b/src/types/entities/relationship.rs @@ -6,18 +6,28 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; +use crate::errors::ChorusError; use crate::types::{Shared, Snowflake}; use super::{arc_rwlock_ptr_eq, PublicUser}; #[derive(Debug, Deserialize, Serialize, Clone, Default)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] /// See pub struct Relationship { + /// The ID of the target user + #[cfg_attr(feature = "sqlx", sqlx(rename = "to_id"))] pub id: Snowflake, #[serde(rename = "type")] + #[cfg_attr(feature = "sqlx", sqlx(rename = "type"))] pub relationship_type: RelationshipType, + #[cfg_attr(feature = "sqlx", sqlx(skip))] // Can be derived from the user id + /// The nickname of the user in this relationship pub nickname: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] // Can be derived from the user id + /// The target user pub user: Shared, + /// When the user requested a relationship pub since: Option>, } @@ -45,8 +55,7 @@ impl PartialEq for Relationship { Copy, Hash, )] -#[cfg_attr(not(feature = "sqlx"), repr(u8))] -#[cfg_attr(feature = "sqlx", repr(i16))] +#[repr(u8)] /// See pub enum RelationshipType { Suggestion = 6, @@ -58,3 +67,50 @@ pub enum RelationshipType { Friends = 1, None = 0, } + +#[cfg(feature = "sqlx")] +impl sqlx::Type for RelationshipType { + fn type_info() -> ::TypeInfo { + >::type_info() + } +} + +#[cfg(feature = "sqlx")] +impl<'q> sqlx::Encode<'q, sqlx::Postgres> for RelationshipType { + fn encode_by_ref( + &self, + buf: &mut ::ArgumentBuffer<'q>, + ) -> Result { + let sqlx_pg_uint = sqlx_pg_uint::PgU8::from(*self as u8); + sqlx_pg_uint.encode_by_ref(buf) + } +} + +#[cfg(feature = "sqlx")] +impl<'r> sqlx::Decode<'r, sqlx::Postgres> for RelationshipType { + fn decode( + value: ::ValueRef<'r>, + ) -> Result { + let sqlx_pg_uint = sqlx_pg_uint::PgU8::decode(value)?; + Self::try_from(sqlx_pg_uint.to_uint()).map_err(|e| e.into()) + } +} + +impl TryFrom for RelationshipType { + type Error = ChorusError; + + fn try_from(value: u8) -> Result { + match value { + 6 => Ok(Self::Suggestion), + 5 => Ok(Self::Implicit), + 4 => Ok(Self::Outgoing), + 3 => Ok(Self::Incoming), + 2 => Ok(Self::Blocked), + 1 => Ok(Self::Friends), + 0 => Ok(Self::None), + _ => Err(ChorusError::InvalidArguments { + error: format!("Value {} is not a valid RelationshipType", value), + }), + } + } +} From 720531d93f9b2a41d255b4ad5b88734f5e45378b Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Tue, 8 Oct 2024 17:18:39 +0200 Subject: [PATCH 160/162] #567: Append: Nickname *cannot* be derived from user id --- src/types/entities/relationship.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/types/entities/relationship.rs b/src/types/entities/relationship.rs index e6d14f42..da2a9dc7 100644 --- a/src/types/entities/relationship.rs +++ b/src/types/entities/relationship.rs @@ -21,7 +21,6 @@ pub struct Relationship { #[serde(rename = "type")] #[cfg_attr(feature = "sqlx", sqlx(rename = "type"))] pub relationship_type: RelationshipType, - #[cfg_attr(feature = "sqlx", sqlx(skip))] // Can be derived from the user id /// The nickname of the user in this relationship pub nickname: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] // Can be derived from the user id From dd4e7ae731bf9e89ecadafdf415095d4f4a94f46 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 10 Oct 2024 19:00:01 +0200 Subject: [PATCH 161/162] i dont wanna talk about it --- Cargo.lock | 306 +++++++++++++++------------------- Cargo.toml | 4 +- src/api/auth/login.rs | 10 -- src/api/auth/mod.rs | 6 - src/api/auth/register.rs | 13 +- src/api/users/users.rs | 8 - src/instance.rs | 3 +- src/types/entities/message.rs | 2 - src/types/schema/channel.rs | 23 --- src/types/schema/role.rs | 1 - src/types/utils/serde.rs | 12 +- 11 files changed, 147 insertions(+), 241 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f36d5a4f..067322f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,19 +4,13 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -77,13 +71,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] @@ -114,23 +108,23 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -209,15 +203,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "cc" -version = "1.1.14" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" dependencies = [ "shlex", ] @@ -276,7 +270,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-bindgen-test", "wasmtimer", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", "ws_stream_wasm", ] @@ -286,7 +280,7 @@ version = "0.5.0" dependencies = [ "async-trait", "quote", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] @@ -358,9 +352,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -457,7 +451,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] @@ -468,7 +462,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] @@ -590,19 +584,9 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "flate2" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" -dependencies = [ - "crc32fast", - "miniz_oxide 0.8.0", -] - -[[package]] -name = "flate2" -version = "1.0.30" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "miniz_oxide", @@ -701,7 +685,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] @@ -760,9 +744,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "h2" @@ -776,7 +760,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.4.0", + "indexmap 2.5.0", "slab", "tokio", "tokio-util", @@ -795,7 +779,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.4.0", + "indexmap 2.5.0", "slab", "tokio", "tokio-util", @@ -1035,9 +1019,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", "futures-util", @@ -1050,9 +1034,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1100,9 +1084,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -1120,9 +1104,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" [[package]] name = "ipnetwork" @@ -1173,9 +1157,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libm" @@ -1270,15 +1254,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -1411,9 +1386,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] @@ -1432,9 +1407,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -1454,7 +1429,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.3", + "redox_syscall", "smallvec", "windows-targets 0.52.6", ] @@ -1534,9 +1509,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "pnet_base" @@ -1570,9 +1545,9 @@ dependencies = [ [[package]] name = "poem" -version = "3.0.4" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1ba1c27f8f89e1bccdda0c680f72790545a11a8d8555819472f5839d7a8ca9d" +checksum = "e5419c612a492fce4961c521dca0c2249b5c48dc46eb5c8048063843f37a711d" dependencies = [ "bytes", "futures-util", @@ -1604,14 +1579,14 @@ dependencies = [ [[package]] name = "poem-derive" -version = "3.0.4" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62fea1692d80a000126f9b28d865012a160b80000abb53ccf152b428222c155" +checksum = "cdfed15c1102d2a9a51b9f1aba945628c72ccb52fc5d3e4ad4ffbbd222e11821" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] @@ -1642,9 +1617,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ "toml_edit", ] @@ -1708,18 +1683,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" dependencies = [ "bitflags 2.6.0", ] @@ -1862,18 +1828,18 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -1896,14 +1862,14 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "once_cell", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -1929,9 +1895,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" [[package]] name = "rustls-webpki" @@ -1945,9 +1911,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -2014,9 +1980,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -2034,20 +2000,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -2063,7 +2029,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] @@ -2088,7 +2054,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.4.0", + "indexmap 2.5.0", "serde", "serde_derive", "serde_json", @@ -2105,7 +2071,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] @@ -2223,9 +2189,9 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" dependencies = [ "nom", "unicode_categories", @@ -2233,9 +2199,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcfa89bea9500db4a0d038513d7a060566bfc51d46d1c014847049a45cce85e8" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2246,9 +2212,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06e2f2bd861719b1f3f0c7dbe1d80c30bf59e76cf019f07d9014ed7eefb8e08" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" dependencies = [ "atoi", "bigdecimal", @@ -2267,14 +2233,14 @@ dependencies = [ "hashbrown 0.14.5", "hashlink", "hex", - "indexmap 2.4.0", + "indexmap 2.5.0", "ipnetwork", "log", "memchr", "once_cell", "paste", "percent-encoding", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pemfile 2.1.3", "serde", "serde_json", @@ -2286,27 +2252,27 @@ dependencies = [ "tokio-stream", "tracing", "url", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", ] [[package]] name = "sqlx-macros" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f998a9defdbd48ed005a89362bd40dd2117502f15294f61c8d47034107dbbdc" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] name = "sqlx-macros-core" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d100558134176a2629d46cec0c8891ba0be8910f7896abfdb75ef4ab6f4e7ce" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" dependencies = [ "dotenvy", "either", @@ -2322,7 +2288,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.76", + "syn 2.0.79", "tempfile", "tokio", "url", @@ -2330,9 +2296,9 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cac0ab331b14cb3921c62156d913e4c15b74fb6ec0f3146bd4ef6e4fb3c12" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", "base64 0.22.1", @@ -2374,9 +2340,9 @@ dependencies = [ [[package]] name = "sqlx-pg-uint" -version = "0.5.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1cfe6c40c1cd0053b9029a41729a533ceb32093052df626aa8bfbba45e45f6" +checksum = "60e5ec2fd2d274ebf9ad6b44b3986f9bcdbb554bb162c4b1ac4af05a439c66f2" dependencies = [ "bigdecimal", "serde", @@ -2387,19 +2353,19 @@ dependencies = [ [[package]] name = "sqlx-pg-uint-macros" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ae3447aced07f8bc71d73dc8dd1c6d25c2f4d10ea62a22ceabc12af8410d7e2" +checksum = "0e527060e9f43479e5b386e4237ab320a36fce39394f6ed73c8870f4637f2e5f" dependencies = [ "quote", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] name = "sqlx-postgres" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9734dbce698c67ecf67c442f768a5e90a49b2a4d61a9f1d59f73874bd4cf0710" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", "base64 0.22.1", @@ -2439,9 +2405,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75b419c3c1b1697833dd927bdc4c6545a620bc1bbafabd44e1efbe9afcd337e" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" dependencies = [ "atoi", "chrono", @@ -2497,9 +2463,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.76" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -2544,9 +2510,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -2557,22 +2523,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] @@ -2623,9 +2589,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.3" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -2645,7 +2611,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] @@ -2660,9 +2626,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -2686,9 +2652,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -2705,11 +2671,11 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.5.0", "toml_datetime", "winnow", ] @@ -2740,7 +2706,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] @@ -2810,15 +2776,15 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] @@ -2939,7 +2905,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.79", "wasm-bindgen-shared", ] @@ -2973,7 +2939,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3007,7 +2973,7 @@ checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] @@ -3042,20 +3008,20 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] [[package]] name = "whoami" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.4.1", + "redox_syscall", "wasite", ] @@ -3255,9 +3221,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.40" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -3309,7 +3275,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.79", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 6d4830ed..031aeff1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ jsonwebtoken = "8.3.0" log = "0.4.22" async-trait = "0.1.81" chorus-macros = { path = "./chorus-macros", version = "0" } # Note: version here is used when releasing. This will use the latest release. Make sure to republish the crate when code in macros is changed! -sqlx = { version = "0.8.1", features = [ +sqlx = { version = "0.8.2", features = [ "json", "chrono", "ipnetwork", @@ -67,7 +67,7 @@ rand = "0.8.5" flate2 = { version = "1.0.33", optional = true } webpki-roots = "0.26.3" pubserve = { version = "1.1.0", features = ["async", "send"] } -sqlx-pg-uint = { version = "0.5.0", features = ["serde"], optional = true } +sqlx-pg-uint = { version = "0.7.2", features = ["serde"], optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] rustls = "0.21.12" diff --git a/src/api/auth/login.rs b/src/api/auth/login.rs index 4d8cbce6..ab78a995 100644 --- a/src/api/auth/login.rs +++ b/src/api/auth/login.rs @@ -30,22 +30,12 @@ impl Instance { // We do not have a user yet, and the UserRateLimits will not be affected by a login // request (since login is an instance wide limit), which is why we are just cloning the // instances' limits to pass them on as user_rate_limits later. -<<<<<<< HEAD let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None").await; let login_result = chorus_request .deserialize_response::(&mut user) .await?; user.set_token(&login_result.token); -======= - let mut user = - ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None".to_string()).await; - - let login_result = chorus_request - .deserialize_response::(&mut user) - .await?; - user.set_token(login_result.token); ->>>>>>> 03f1e7d (Refactor / fix login and register (#495)) user.settings = login_result.settings; let object = User::get_current(&mut user).await?; diff --git a/src/api/auth/mod.rs b/src/api/auth/mod.rs index cdc41ba8..96491351 100644 --- a/src/api/auth/mod.rs +++ b/src/api/auth/mod.rs @@ -22,14 +22,8 @@ pub mod register; impl Instance { /// Logs into an existing account on the spacebar server, using only a token. -<<<<<<< HEAD pub async fn login_with_token(&mut self, token: &str) -> ChorusResult { let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await; -======= - pub async fn login_with_token(&mut self, token: String) -> ChorusResult { - let mut user = - ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await; ->>>>>>> 03f1e7d (Refactor / fix login and register (#495)) let object = User::get_current(&mut user).await?; let settings = User::get_settings(&mut user).await?; diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs index 532a65c6..d978e0ff 100644 --- a/src/api/auth/register.rs +++ b/src/api/auth/register.rs @@ -37,25 +37,16 @@ impl Instance { // We do not have a user yet, and the UserRateLimits will not be affected by a login // request (since register is an instance wide limit), which is why we are just cloning // the instances' limits to pass them on as user_rate_limits later. -<<<<<<< HEAD let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None").await; -======= - let mut user = - ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None".to_string()).await; - ->>>>>>> 03f1e7d (Refactor / fix login and register (#495)) let token = chorus_request .deserialize_response::(&mut user) .await? .token; -<<<<<<< HEAD + user.set_token(&token); -======= - user.set_token(token); ->>>>>>> 03f1e7d (Refactor / fix login and register (#495)) - let object = User::get(&mut user, None).await?; + let object = User::get_current(&mut user).await?; let settings = User::get_settings(&mut user).await?; *user.object.write().unwrap() = object; diff --git a/src/api/users/users.rs b/src/api/users/users.rs index b8ab8d6a..483a85c1 100644 --- a/src/api/users/users.rs +++ b/src/api/users/users.rs @@ -82,11 +82,7 @@ impl ChorusUser { /// # Notes /// This function is a wrapper around [`User::get_settings`]. pub async fn get_settings(&mut self) -> ChorusResult { -<<<<<<< HEAD User::get_settings(self).await -======= - User::get_settings(self).await ->>>>>>> 03f1e7d (Refactor / fix login and register (#495)) } /// Modifies the current user's representation. (See [`User`]) @@ -882,7 +878,3 @@ impl User { chorus_request.handle_request_as_result(user).await } } -<<<<<<< HEAD -======= - ->>>>>>> 03f1e7d (Refactor / fix login and register (#495)) diff --git a/src/instance.rs b/src/instance.rs index f0569a99..3956dd06 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -149,8 +149,7 @@ impl Instance { /// Detects which [InstanceSoftware] the instance is running. pub async fn detect_software(&self) -> InstanceSoftware { - - if let Ok(version) = self.get_version().await { + if let Ok(version) = self.get_version().await { match version.server.to_lowercase().as_str() { "symfonia" => return InstanceSoftware::Symfonia, // We can dream this will be implemented one day diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index ef7f392e..b63eb3bf 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -19,8 +19,6 @@ use crate::{UInt32, UInt8}; use super::option_arc_rwlock_ptr_eq; -use super::option_arc_rwlock_ptr_eq; - #[derive(Debug, Serialize, Deserialize, Default, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] /// Represents a message sent in a channel. diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index fea2545a..62b3b53a 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -138,29 +138,6 @@ bitflags! { } } -#[cfg(feature = "sqlx")] -impl sqlx::Type for InviteFlags { - fn type_info() -> sqlx::mysql::MySqlTypeInfo { - u64::type_info() - } -} - -#[cfg(feature = "sqlx")] -impl<'q> sqlx::Encode<'q, sqlx::MySql> for InviteFlags { - fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { - u64::encode_by_ref(&self.0.0, buf) - } -} - -#[cfg(feature = "sqlx")] -impl<'r> sqlx::Decode<'r, sqlx::MySql> for InviteFlags { - fn decode(value: >::ValueRef) -> Result { - let raw = u64::decode(value)?; - - Ok(Self::from_bits(raw).unwrap()) - } -} - #[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] diff --git a/src/types/schema/role.rs b/src/types/schema/role.rs index 17292fea..805d0263 100644 --- a/src/types/schema/role.rs +++ b/src/types/schema/role.rs @@ -4,7 +4,6 @@ use crate::types::{PermissionFlags, Snowflake}; use serde::{Deserialize, Serialize}; -use crate::types::{PermissionFlags, Snowflake}; #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] #[serde(rename_all = "snake_case")] diff --git a/src/types/utils/serde.rs b/src/types/utils/serde.rs index f682bb0b..da41f4ac 100644 --- a/src/types/utils/serde.rs +++ b/src/types/utils/serde.rs @@ -32,7 +32,7 @@ pub struct SecondsStringTimestampVisitor; /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// // Ok::<(), serde_json::Error>(()) +/// # Ok::<(), serde_json::Error>(()) /// ``` pub mod ts_seconds_str { @@ -64,7 +64,7 @@ pub mod ts_seconds_str { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); - /// // Ok::<(), serde_json::Error>(()) + /// # Ok::<(), serde_json::Error>(()) /// ``` pub fn serialize(dt: &DateTime, serializer: S) -> Result where @@ -91,7 +91,7 @@ pub mod ts_seconds_str { /// /// let my_s: S = serde_json::from_str(r#"{ "time": "1431684000" }"#)?; /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).unwrap() }); - /// // Ok::<(), serde_json::Error>(()) + /// # Ok::<(), serde_json::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where @@ -145,7 +145,7 @@ pub mod ts_seconds_str { /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); /// let my_s: S = serde_json::from_str(&as_string)?; /// assert_eq!(my_s.time, time); -/// // Ok::<(), serde_json::Error>(()) +/// # Ok::<(), serde_json::Error>(()) /// ``` pub mod ts_seconds_option_str { use super::SecondsStringTimestampVisitor; @@ -174,7 +174,7 @@ pub mod ts_seconds_option_str { /// }; /// let as_string = serde_json::to_string(&my_s)?; /// assert_eq!(as_string, r#"{"time":"1431684000"}"#); - /// // Ok::<(), serde_json::Error>(()) + /// # Ok::<(), serde_json::Error>(()) /// ``` pub fn serialize(opt: &Option>, serializer: S) -> Result where @@ -204,7 +204,7 @@ pub mod ts_seconds_option_str { /// /// let my_s: S = serde_json::from_str(r#"{ "time": "1431684000" }"#)?; /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).single() }); - /// // Ok::<(), serde_json::Error>(()) + /// # Ok::<(), serde_json::Error>(()) /// ``` pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where From a2f9f9602a9f6efb643bbbd2f661a886620c0fe0 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 10 Oct 2024 19:04:24 +0200 Subject: [PATCH 162/162] Bump version to 0.17.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 067322f9..30d7b2a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -230,7 +230,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chorus" -version = "0.16.0" +version = "0.17.0" dependencies = [ "async-trait", "base64 0.21.7", diff --git a/Cargo.toml b/Cargo.toml index 031aeff1..675a4662 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "chorus" description = "A library for interacting with multiple Spacebar-compatible Instances at once." -version = "0.16.0" +version = "0.17.0" license = "MPL-2.0" edition = "2021" repository = "https://github.com/polyphony-chat/chorus" diff --git a/README.md b/README.md index afed9b2c..cdac65d4 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ To get started with Chorus, import it into your project by adding the following ```toml [dependencies] -chorus = "0.16.0" +chorus = "0.17.0" ``` ### Establishing a Connection