tulpje_cache/models/
guild.rs

1use std::{hash::Hash, mem};
2
3use serde::{Deserialize, Serialize, de::DeserializeOwned};
4use twilight_model::{
5    gateway::payload::incoming::GuildUpdate,
6    guild::{
7        AfkTimeout, DefaultMessageNotificationLevel, ExplicitContentFilter, Guild, GuildFeature,
8        MfaLevel, NSFWLevel, Permissions, PremiumTier, SystemChannelFlags, VerificationLevel,
9    },
10    id::{
11        Id,
12        marker::{ApplicationMarker, ChannelMarker, GuildMarker, UserMarker},
13    },
14    util::{ImageHash, Timestamp},
15};
16
17use crate::{
18    Cache, Error,
19    repository::{MappedSetRepository, Repository},
20};
21
22#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
23pub struct CachedGuild {
24    pub afk_channel_id: Option<Id<ChannelMarker>>,
25    pub afk_timeout: AfkTimeout,
26    pub application_id: Option<Id<ApplicationMarker>>,
27    pub banner: Option<ImageHash>,
28    pub default_message_notifications: DefaultMessageNotificationLevel,
29    pub description: Option<String>,
30    pub discovery_splash: Option<ImageHash>,
31    pub explicit_content_filter: ExplicitContentFilter,
32    pub features: Vec<GuildFeature>,
33    pub icon: Option<ImageHash>,
34    pub id: Id<GuildMarker>,
35    pub joined_at: Option<Timestamp>,
36    pub large: bool,
37    pub max_members: Option<u64>,
38    pub max_presences: Option<u64>,
39    pub max_video_channel_users: Option<u64>,
40    pub member_count: Option<u64>,
41    pub mfa_level: MfaLevel,
42    pub name: String,
43    pub nsfw_level: NSFWLevel,
44    pub owner_id: Id<UserMarker>,
45    pub owner: Option<bool>,
46    pub permissions: Option<Permissions>,
47    pub preferred_locale: String,
48    pub premium_progress_bar_enabled: bool,
49    pub premium_subscription_count: Option<u64>,
50    pub premium_tier: PremiumTier,
51    pub public_updates_channel_id: Option<Id<ChannelMarker>>,
52    pub rules_channel_id: Option<Id<ChannelMarker>>,
53    pub safety_alerts_channel_id: Option<Id<ChannelMarker>>,
54    pub splash: Option<ImageHash>,
55    pub system_channel_id: Option<Id<ChannelMarker>>,
56    pub system_channel_flags: SystemChannelFlags,
57    pub unavailable: Option<bool>,
58    pub vanity_url_code: Option<String>,
59    pub verification_level: VerificationLevel,
60    pub widget_channel_id: Option<Id<ChannelMarker>>,
61    pub widget_enabled: Option<bool>,
62}
63
64impl CachedGuild {
65    pub(crate) fn update_with_guild_update(&mut self, guild_update: &GuildUpdate) {
66        self.afk_channel_id = guild_update.afk_channel_id;
67        self.afk_timeout = guild_update.afk_timeout;
68        self.banner = guild_update.banner;
69        self.default_message_notifications = guild_update.default_message_notifications;
70        self.description = guild_update.description.clone();
71        self.features = guild_update.features.clone();
72        self.icon = guild_update.icon;
73        self.max_members = guild_update.max_members;
74        self.max_presences = Some(guild_update.max_presences.unwrap_or(25000));
75        self.mfa_level = guild_update.mfa_level;
76        self.name = guild_update.name.clone();
77        self.nsfw_level = guild_update.nsfw_level;
78        self.owner = guild_update.owner;
79        self.owner_id = guild_update.owner_id;
80        self.permissions = guild_update.permissions;
81        self.preferred_locale = guild_update.preferred_locale.clone();
82        self.premium_tier = guild_update.premium_tier;
83        self.premium_subscription_count
84            .replace(guild_update.premium_subscription_count.unwrap_or_default());
85        self.splash = guild_update.splash;
86        self.system_channel_id = guild_update.system_channel_id;
87        self.verification_level = guild_update.verification_level;
88        self.vanity_url_code = guild_update.vanity_url_code.clone();
89        self.widget_channel_id = guild_update.widget_channel_id;
90        self.widget_enabled = guild_update.widget_enabled;
91    }
92}
93
94impl From<Guild> for CachedGuild {
95    fn from(guild: Guild) -> Self {
96        let Guild {
97            afk_channel_id,
98            afk_timeout,
99            application_id,
100            banner,
101            default_message_notifications,
102            description,
103            discovery_splash,
104            explicit_content_filter,
105            features,
106            icon,
107            id,
108            joined_at,
109            large,
110            max_members,
111            max_presences,
112            max_video_channel_users,
113            member_count,
114            mfa_level,
115            name,
116            nsfw_level,
117            owner_id,
118            owner,
119            permissions,
120            preferred_locale,
121            premium_progress_bar_enabled,
122            premium_subscription_count,
123            premium_tier,
124            public_updates_channel_id,
125            rules_channel_id,
126            safety_alerts_channel_id,
127            splash,
128            system_channel_flags,
129            system_channel_id,
130            unavailable,
131            vanity_url_code,
132            verification_level,
133            widget_channel_id,
134            widget_enabled,
135            ..
136        } = guild;
137
138        Self {
139            afk_channel_id,
140            afk_timeout,
141            application_id,
142            banner,
143            default_message_notifications,
144            description,
145            discovery_splash,
146            explicit_content_filter,
147            features,
148            icon,
149            id,
150            joined_at,
151            large,
152            max_members,
153            max_presences,
154            max_video_channel_users,
155            member_count,
156            mfa_level,
157            name,
158            nsfw_level,
159            owner_id,
160            owner,
161            permissions,
162            preferred_locale,
163            premium_progress_bar_enabled,
164            premium_subscription_count,
165            premium_tier,
166            public_updates_channel_id,
167            rules_channel_id,
168            safety_alerts_channel_id,
169            splash,
170            system_channel_id,
171            system_channel_flags,
172            unavailable,
173            vanity_url_code,
174            verification_level,
175            widget_channel_id,
176            widget_enabled,
177        }
178    }
179}
180
181impl PartialEq<Guild> for CachedGuild {
182    fn eq(&self, other: &Guild) -> bool {
183        self.afk_channel_id == other.afk_channel_id
184            && self.afk_timeout == other.afk_timeout
185            && self.application_id == other.application_id
186            && self.banner == other.banner
187            && self.default_message_notifications == other.default_message_notifications
188            && self.description == other.description
189            && self.discovery_splash == other.discovery_splash
190            && self.explicit_content_filter == other.explicit_content_filter
191            && self.features == other.features
192            && self.icon == other.icon
193            && self.joined_at == other.joined_at
194            && self.large == other.large
195            && self.max_members == other.max_members
196            && self.max_presences == other.max_presences
197            && self.max_video_channel_users == other.max_video_channel_users
198            && self.member_count == other.member_count
199            && self.mfa_level == other.mfa_level
200            && self.name == other.name
201            && self.nsfw_level == other.nsfw_level
202            && self.owner_id == other.owner_id
203            && self.owner == other.owner
204            && self.permissions == other.permissions
205            && self.preferred_locale == other.preferred_locale
206            && self.premium_progress_bar_enabled == other.premium_progress_bar_enabled
207            && self.premium_subscription_count == other.premium_subscription_count
208            && self.premium_tier == other.premium_tier
209            && self.public_updates_channel_id == other.public_updates_channel_id
210            && self.rules_channel_id == other.rules_channel_id
211            && self.safety_alerts_channel_id == other.safety_alerts_channel_id
212            && self.splash == other.splash
213            && self.system_channel_id == other.system_channel_id
214            && self.system_channel_flags == other.system_channel_flags
215            && self.unavailable == other.unavailable
216            && self.vanity_url_code == other.vanity_url_code
217            && self.verification_level == other.verification_level
218            && self.widget_channel_id == other.widget_channel_id
219            && self.widget_enabled == other.widget_enabled
220    }
221}
222
223impl Cache {
224    pub(crate) async fn unavailable_guild(&self, guild_id: Id<GuildMarker>) -> Result<(), Error> {
225        self.unavailable_guilds.insert(&guild_id).await?;
226        self.delete_guild(guild_id, true).await?;
227
228        Ok(())
229    }
230
231    pub(crate) async fn cache_guild(&self, mut guild: Guild) -> Result<(), Error> {
232        for channel in &mut guild.channels {
233            channel.guild_id = Some(guild.id);
234        }
235        for thread in &mut guild.threads {
236            thread.guild_id = Some(guild.id);
237        }
238
239        self.cache_channels(mem::take(&mut guild.channels)).await?;
240        self.cache_channels(mem::take(&mut guild.threads)).await?;
241        self.cache_emojis(guild.id, mem::take(&mut guild.emojis))
242            .await?;
243        self.cache_members(guild.id, mem::take(&mut guild.members))
244            .await?;
245        self.cache_presences(guild.id, mem::take(&mut guild.presences))
246            .await?;
247        self.cache_roles(guild.id, mem::take(&mut guild.roles))
248            .await?;
249        self.cache_stickers(guild.id, mem::take(&mut guild.stickers))
250            .await?;
251        self.cache_voice_states(mem::take(&mut guild.voice_states))
252            .await?;
253        self.cache_stage_instances(guild.id, mem::take(&mut guild.stage_instances))
254            .await?;
255        self.cache_guild_scheduled_events(guild.id, mem::take(&mut guild.guild_scheduled_events))
256            .await?;
257
258        self.unavailable_guilds.remove(&guild.id).await?;
259        self.guilds
260            .insert(&guild.id, &CachedGuild::from(guild.clone()))
261            .await?;
262
263        Ok(())
264    }
265
266    pub(crate) async fn delete_guild(
267        &self,
268        guild_id: Id<GuildMarker>,
269        unavailable: bool,
270    ) -> Result<(), Error> {
271        async fn remove_ids<
272            T: Eq + Hash + Serialize + DeserializeOwned,
273            U: Serialize + DeserializeOwned,
274        >(
275            guild_map: &MappedSetRepository<Id<GuildMarker>, T>,
276            container: &Repository<T, U>,
277            guild_id: Id<GuildMarker>,
278        ) -> Result<(), Error> {
279            let ids = guild_map.members(&guild_id).await?;
280            container.remove_multi(&ids).await?;
281            Ok(())
282        }
283
284        if unavailable {
285            if let Some(mut guild) = self.guilds.get(&guild_id).await? {
286                guild.unavailable = Some(true);
287                self.guilds.insert(&guild_id, &guild).await?;
288            }
289        } else {
290            self.guilds.remove(&guild_id).await?;
291        }
292
293        remove_ids(&self.guild_channels, &self.channels, guild_id).await?;
294        remove_ids(&self.guild_emojis, &self.emojis, guild_id).await?;
295        remove_ids(&self.guild_roles, &self.roles, guild_id).await?;
296        remove_ids(&self.guild_stickers, &self.stickers, guild_id).await?;
297
298        self.voice_state_guilds.clear(&guild_id).await?;
299
300        let members_to_remove: Vec<_> = self
301            .guild_members
302            .members(&guild_id)
303            .await?
304            .into_iter()
305            .map(|user_id| (guild_id, user_id))
306            .collect();
307        self.members.remove_multi(members_to_remove.iter()).await?;
308        self.guild_members.clear(&guild_id).await?;
309
310        let presences_to_remove: Vec<_> = self
311            .guild_presences
312            .members(&guild_id)
313            .await?
314            .into_iter()
315            .map(|user_id| (guild_id, user_id))
316            .collect();
317        self.presences
318            .remove_multi(presences_to_remove.iter())
319            .await?;
320        self.guild_presences.clear(&guild_id).await?;
321
322        Ok(())
323    }
324
325    pub(crate) async fn update_guild(&self, guild_update: &GuildUpdate) -> Result<(), Error> {
326        let Some(mut guild) = self.guilds.get(&guild_update.id).await? else {
327            return Ok(());
328        };
329
330        guild.update_with_guild_update(guild_update);
331        self.guilds.insert(&guild.id, &guild).await?;
332
333        Ok(())
334    }
335}