serenity/cache/
event.rs

1use std::collections::HashSet;
2
3use super::{Cache, CacheUpdate};
4use crate::model::channel::{GuildChannel, Message};
5use crate::model::event::{
6    ChannelCreateEvent,
7    ChannelDeleteEvent,
8    ChannelPinsUpdateEvent,
9    ChannelUpdateEvent,
10    GuildCreateEvent,
11    GuildDeleteEvent,
12    GuildEmojisUpdateEvent,
13    GuildMemberAddEvent,
14    GuildMemberRemoveEvent,
15    GuildMemberUpdateEvent,
16    GuildMembersChunkEvent,
17    GuildRoleCreateEvent,
18    GuildRoleDeleteEvent,
19    GuildRoleUpdateEvent,
20    GuildStickersUpdateEvent,
21    GuildUpdateEvent,
22    MessageCreateEvent,
23    MessageUpdateEvent,
24    PresenceUpdateEvent,
25    ReadyEvent,
26    ThreadCreateEvent,
27    ThreadDeleteEvent,
28    ThreadUpdateEvent,
29    UserUpdateEvent,
30    VoiceChannelStatusUpdateEvent,
31    VoiceStateUpdateEvent,
32};
33use crate::model::gateway::ShardInfo;
34use crate::model::guild::{Guild, GuildMemberFlags, Member, Role};
35use crate::model::id::ShardId;
36use crate::model::user::{CurrentUser, OnlineStatus};
37use crate::model::voice::VoiceState;
38
39impl CacheUpdate for ChannelCreateEvent {
40    type Output = GuildChannel;
41
42    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
43        let old_channel = cache
44            .guilds
45            .get_mut(&self.channel.guild_id)
46            .and_then(|mut g| g.channels.insert(self.channel.id, self.channel.clone()));
47
48        cache.channels.insert(self.channel.id, self.channel.guild_id);
49        old_channel
50    }
51}
52
53impl CacheUpdate for ChannelDeleteEvent {
54    type Output = Vec<Message>;
55
56    fn update(&mut self, cache: &Cache) -> Option<Vec<Message>> {
57        let (channel_id, guild_id) = (self.channel.id, self.channel.guild_id);
58
59        cache.channels.remove(&channel_id);
60        cache.guilds.get_mut(&guild_id).map(|mut g| g.channels.remove(&channel_id));
61
62        // Remove the cached messages for the channel.
63        cache.messages.remove(&channel_id).map(|(_, messages)| messages.into_values().collect())
64    }
65}
66
67impl CacheUpdate for ChannelUpdateEvent {
68    type Output = GuildChannel;
69
70    fn update(&mut self, cache: &Cache) -> Option<GuildChannel> {
71        cache.channels.insert(self.channel.id, self.channel.guild_id);
72
73        cache
74            .guilds
75            .get_mut(&self.channel.guild_id)
76            .and_then(|mut g| g.channels.insert(self.channel.id, self.channel.clone()))
77    }
78}
79
80impl CacheUpdate for ChannelPinsUpdateEvent {
81    type Output = ();
82
83    fn update(&mut self, cache: &Cache) -> Option<()> {
84        if let Some(guild_id) = self.guild_id {
85            if let Some(mut guild) = cache.guilds.get_mut(&guild_id) {
86                if let Some(channel) = guild.channels.get_mut(&self.channel_id) {
87                    channel.last_pin_timestamp = self.last_pin_timestamp;
88                }
89            }
90        }
91
92        None
93    }
94}
95
96impl CacheUpdate for GuildCreateEvent {
97    type Output = ();
98
99    fn update(&mut self, cache: &Cache) -> Option<()> {
100        cache.unavailable_guilds.remove(&self.guild.id);
101        let mut guild = self.guild.clone();
102
103        for (user_id, member) in &mut guild.members {
104            cache.update_user_entry(&member.user);
105            if let Some(u) = cache.user(user_id) {
106                member.user = u.clone();
107            }
108        }
109
110        cache.guilds.insert(self.guild.id, guild);
111        for channel_id in self.guild.channels.keys() {
112            cache.channels.insert(*channel_id, self.guild.id);
113        }
114
115        None
116    }
117}
118
119impl CacheUpdate for GuildDeleteEvent {
120    type Output = Guild;
121
122    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
123        if self.guild.unavailable {
124            cache.unavailable_guilds.insert(self.guild.id, ());
125            cache.guilds.remove(&self.guild.id);
126
127            return None;
128        }
129
130        match cache.guilds.remove(&self.guild.id) {
131            Some(guild) => {
132                for channel_id in guild.1.channels.keys() {
133                    // Remove the channel from the cache.
134                    cache.channels.remove(channel_id);
135
136                    // Remove the channel's cached messages.
137                    cache.messages.remove(channel_id);
138                }
139
140                Some(guild.1)
141            },
142            None => None,
143        }
144    }
145}
146
147impl CacheUpdate for GuildEmojisUpdateEvent {
148    type Output = ();
149
150    fn update(&mut self, cache: &Cache) -> Option<()> {
151        if let Some(mut guild) = cache.guilds.get_mut(&self.guild_id) {
152            guild.emojis.clone_from(&self.emojis);
153        }
154
155        None
156    }
157}
158
159impl CacheUpdate for GuildMemberAddEvent {
160    type Output = ();
161
162    fn update(&mut self, cache: &Cache) -> Option<()> {
163        let user_id = self.member.user.id;
164        cache.update_user_entry(&self.member.user);
165        if let Some(u) = cache.user(user_id) {
166            self.member.user = u.clone();
167        }
168
169        if let Some(mut guild) = cache.guilds.get_mut(&self.member.guild_id) {
170            guild.member_count += 1;
171            guild.members.insert(user_id, self.member.clone());
172        }
173
174        None
175    }
176}
177
178impl CacheUpdate for GuildMemberRemoveEvent {
179    type Output = Member;
180
181    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
182        if let Some(mut guild) = cache.guilds.get_mut(&self.guild_id) {
183            guild.member_count -= 1;
184            return guild.members.remove(&self.user.id);
185        }
186
187        None
188    }
189}
190
191impl CacheUpdate for GuildMemberUpdateEvent {
192    type Output = Member;
193
194    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
195        cache.update_user_entry(&self.user);
196
197        if let Some(mut guild) = cache.guilds.get_mut(&self.guild_id) {
198            let item = if let Some(member) = guild.members.get_mut(&self.user.id) {
199                let item = Some(member.clone());
200
201                member.joined_at.clone_from(&Some(self.joined_at));
202                member.nick.clone_from(&self.nick);
203                member.roles.clone_from(&self.roles);
204                member.user.clone_from(&self.user);
205                member.pending.clone_from(&self.pending);
206                member.premium_since.clone_from(&self.premium_since);
207                member.deaf.clone_from(&self.deaf);
208                member.mute.clone_from(&self.mute);
209                member.avatar.clone_from(&self.avatar);
210                member.communication_disabled_until.clone_from(&self.communication_disabled_until);
211                member.unusual_dm_activity_until.clone_from(&self.unusual_dm_activity_until);
212
213                item
214            } else {
215                None
216            };
217
218            if item.is_none() {
219                guild.members.insert(self.user.id, Member {
220                    deaf: false,
221                    guild_id: self.guild_id,
222                    joined_at: Some(self.joined_at),
223                    mute: false,
224                    nick: self.nick.clone(),
225                    roles: self.roles.clone(),
226                    user: self.user.clone(),
227                    pending: self.pending,
228                    premium_since: self.premium_since,
229                    permissions: None,
230                    avatar: self.avatar,
231                    communication_disabled_until: self.communication_disabled_until,
232                    flags: GuildMemberFlags::default(),
233                    unusual_dm_activity_until: self.unusual_dm_activity_until,
234                });
235            }
236
237            item
238        } else {
239            None
240        }
241    }
242}
243
244impl CacheUpdate for GuildMembersChunkEvent {
245    type Output = ();
246
247    fn update(&mut self, cache: &Cache) -> Option<()> {
248        for member in self.members.values() {
249            cache.update_user_entry(&member.user);
250        }
251
252        if let Some(mut g) = cache.guilds.get_mut(&self.guild_id) {
253            g.members.extend(self.members.clone());
254        }
255
256        None
257    }
258}
259
260impl CacheUpdate for GuildRoleCreateEvent {
261    type Output = ();
262
263    fn update(&mut self, cache: &Cache) -> Option<()> {
264        cache
265            .guilds
266            .get_mut(&self.role.guild_id)
267            .map(|mut g| g.roles.insert(self.role.id, self.role.clone()));
268
269        None
270    }
271}
272
273impl CacheUpdate for GuildRoleDeleteEvent {
274    type Output = Role;
275
276    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
277        cache.guilds.get_mut(&self.guild_id).and_then(|mut g| g.roles.remove(&self.role_id))
278    }
279}
280
281impl CacheUpdate for GuildRoleUpdateEvent {
282    type Output = Role;
283
284    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
285        if let Some(mut guild) = cache.guilds.get_mut(&self.role.guild_id) {
286            if let Some(role) = guild.roles.get_mut(&self.role.id) {
287                return Some(std::mem::replace(role, self.role.clone()));
288            }
289        }
290
291        None
292    }
293}
294
295impl CacheUpdate for GuildStickersUpdateEvent {
296    type Output = ();
297
298    fn update(&mut self, cache: &Cache) -> Option<()> {
299        if let Some(mut guild) = cache.guilds.get_mut(&self.guild_id) {
300            guild.stickers.clone_from(&self.stickers);
301        }
302
303        None
304    }
305}
306
307impl CacheUpdate for GuildUpdateEvent {
308    type Output = ();
309
310    fn update(&mut self, cache: &Cache) -> Option<()> {
311        if let Some(mut guild) = cache.guilds.get_mut(&self.guild.id) {
312            guild.afk_metadata.clone_from(&self.guild.afk_metadata);
313            guild.banner.clone_from(&self.guild.banner);
314            guild.discovery_splash.clone_from(&self.guild.discovery_splash);
315            guild.features.clone_from(&self.guild.features);
316            guild.icon.clone_from(&self.guild.icon);
317            guild.name.clone_from(&self.guild.name);
318            guild.owner_id.clone_from(&self.guild.owner_id);
319            guild.roles.clone_from(&self.guild.roles);
320            guild.splash.clone_from(&self.guild.splash);
321            guild.vanity_url_code.clone_from(&self.guild.vanity_url_code);
322            guild.welcome_screen.clone_from(&self.guild.welcome_screen);
323            guild.default_message_notifications = self.guild.default_message_notifications;
324            guild.max_members = self.guild.max_members;
325            guild.max_presences = self.guild.max_presences;
326            guild.max_video_channel_users = self.guild.max_video_channel_users;
327            guild.mfa_level = self.guild.mfa_level;
328            guild.nsfw_level = self.guild.nsfw_level;
329            guild.premium_subscription_count = self.guild.premium_subscription_count;
330            guild.premium_tier = self.guild.premium_tier;
331            guild.public_updates_channel_id = self.guild.public_updates_channel_id;
332            guild.rules_channel_id = self.guild.rules_channel_id;
333            guild.system_channel_flags = self.guild.system_channel_flags;
334            guild.system_channel_id = self.guild.system_channel_id;
335            guild.verification_level = self.guild.verification_level;
336            guild.widget_channel_id = self.guild.widget_channel_id;
337            guild.widget_enabled = self.guild.widget_enabled;
338        }
339
340        None
341    }
342}
343
344impl CacheUpdate for MessageCreateEvent {
345    /// The oldest message, if the channel's message cache was already full.
346    type Output = Message;
347
348    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
349        // Update the relevant channel object with the new latest message if this message is newer
350        let guild = self.message.guild_id.and_then(|g_id| cache.guilds.get_mut(&g_id));
351
352        if let Some(mut guild) = guild {
353            if let Some(channel) = guild.channels.get_mut(&self.message.channel_id) {
354                update_channel_last_message_id(&self.message, channel, cache);
355            } else {
356                // This may be a thread.
357                let thread =
358                    guild.threads.iter_mut().find(|thread| thread.id == self.message.channel_id);
359                if let Some(thread) = thread {
360                    update_channel_last_message_id(&self.message, thread, cache);
361                }
362            }
363        }
364
365        // Add the new message to the cache and remove the oldest cached message.
366        let max = cache.settings().max_messages;
367
368        if max == 0 {
369            return None;
370        }
371
372        let mut messages = cache.messages.entry(self.message.channel_id).or_default();
373        let mut queue = cache.message_queue.entry(self.message.channel_id).or_default();
374
375        let mut removed_msg = None;
376
377        if messages.len() == max {
378            if let Some(id) = queue.pop_front() {
379                removed_msg = messages.remove(&id);
380            }
381        }
382
383        queue.push_back(self.message.id);
384        messages.insert(self.message.id, self.message.clone());
385
386        removed_msg
387    }
388}
389
390fn update_channel_last_message_id(message: &Message, channel: &mut GuildChannel, cache: &Cache) {
391    if let Some(last_message_id) = channel.last_message_id {
392        let most_recent_timestamp = cache.message(channel.id, last_message_id).map(|m| m.timestamp);
393        if let Some(most_recent_timestamp) = most_recent_timestamp {
394            if message.timestamp > most_recent_timestamp {
395                channel.last_message_id = Some(message.id);
396            }
397        } else {
398            channel.last_message_id = Some(message.id);
399        }
400    } else {
401        channel.last_message_id = Some(message.id);
402    }
403}
404
405impl CacheUpdate for MessageUpdateEvent {
406    type Output = Message;
407
408    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
409        let mut messages = cache.messages.get_mut(&self.channel_id)?;
410        let message = messages.get_mut(&self.id)?;
411        let old_message = message.clone();
412
413        self.apply_to_message(message);
414
415        Some(old_message)
416    }
417}
418
419impl CacheUpdate for PresenceUpdateEvent {
420    type Output = ();
421
422    fn update(&mut self, cache: &Cache) -> Option<()> {
423        if let Some(user) = self.presence.user.to_user() {
424            cache.update_user_entry(&user);
425        }
426
427        if let Some(user) = cache.user(self.presence.user.id) {
428            self.presence.user.update_with_user(&user);
429        }
430
431        if let Some(guild_id) = self.presence.guild_id {
432            if let Some(mut guild) = cache.guilds.get_mut(&guild_id) {
433                // If the member went offline, remove them from the presence list.
434                if self.presence.status == OnlineStatus::Offline {
435                    guild.presences.remove(&self.presence.user.id);
436                } else {
437                    guild.presences.insert(self.presence.user.id, self.presence.clone());
438                }
439
440                // Create a partial member instance out of the presence update data.
441                if let Some(user) = self.presence.user.to_user() {
442                    guild.members.entry(self.presence.user.id).or_insert_with(|| Member {
443                        deaf: false,
444                        guild_id,
445                        joined_at: None,
446                        mute: false,
447                        nick: None,
448                        user,
449                        roles: vec![],
450                        pending: false,
451                        premium_since: None,
452                        permissions: None,
453                        avatar: None,
454                        communication_disabled_until: None,
455                        flags: GuildMemberFlags::default(),
456                        unusual_dm_activity_until: None,
457                    });
458                }
459            }
460        }
461
462        None
463    }
464}
465
466impl CacheUpdate for ReadyEvent {
467    type Output = ();
468
469    fn update(&mut self, cache: &Cache) -> Option<()> {
470        let ready = self.ready.clone();
471
472        for unavailable in ready.guilds {
473            cache.guilds.remove(&unavailable.id);
474            cache.unavailable_guilds.insert(unavailable.id, ());
475        }
476
477        // We may be removed from some guilds between disconnect and ready, so handle that.
478        let mut guilds_to_remove = vec![];
479        let ready_guilds_hashset =
480            self.ready.guilds.iter().map(|status| status.id).collect::<HashSet<_>>();
481        let shard_data = self.ready.shard.unwrap_or_else(|| ShardInfo::new(ShardId(1), 1));
482
483        for guild_entry in cache.guilds.iter() {
484            let guild = guild_entry.key();
485            // Only handle data for our shard.
486            if crate::utils::shard_id(*guild, shard_data.total) == shard_data.id.0
487                && !ready_guilds_hashset.contains(guild)
488            {
489                guilds_to_remove.push(*guild);
490            }
491        }
492        if !guilds_to_remove.is_empty() {
493            for guild in guilds_to_remove {
494                cache.guilds.remove(&guild);
495            }
496        }
497
498        {
499            let mut cached_shard_data = cache.shard_data.write();
500            cached_shard_data.total = shard_data.total;
501            cached_shard_data.connected.insert(shard_data.id);
502        }
503        *cache.user.write() = ready.user;
504
505        None
506    }
507}
508
509impl CacheUpdate for ThreadCreateEvent {
510    type Output = GuildChannel;
511
512    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
513        let (guild_id, thread_id) = (self.thread.guild_id, self.thread.id);
514
515        cache.guilds.get_mut(&guild_id).and_then(|mut g| {
516            if let Some(i) = g.threads.iter().position(|e| e.id == thread_id) {
517                Some(std::mem::replace(&mut g.threads[i], self.thread.clone()))
518            } else {
519                g.threads.push(self.thread.clone());
520                None
521            }
522        })
523    }
524}
525
526impl CacheUpdate for ThreadUpdateEvent {
527    type Output = GuildChannel;
528
529    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
530        let (guild_id, thread_id) = (self.thread.guild_id, self.thread.id);
531
532        cache.guilds.get_mut(&guild_id).and_then(|mut g| {
533            if let Some(i) = g.threads.iter().position(|e| e.id == thread_id) {
534                Some(std::mem::replace(&mut g.threads[i], self.thread.clone()))
535            } else {
536                g.threads.push(self.thread.clone());
537                None
538            }
539        })
540    }
541}
542
543impl CacheUpdate for ThreadDeleteEvent {
544    type Output = GuildChannel;
545
546    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
547        let (guild_id, thread_id) = (self.thread.guild_id, self.thread.id);
548
549        cache.guilds.get_mut(&guild_id).and_then(|mut g| {
550            g.threads.iter().position(|e| e.id == thread_id).map(|i| g.threads.remove(i))
551        })
552    }
553}
554
555impl CacheUpdate for UserUpdateEvent {
556    type Output = CurrentUser;
557
558    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
559        let mut user = cache.user.write();
560        Some(std::mem::replace(&mut user, self.current_user.clone()))
561    }
562}
563
564impl CacheUpdate for VoiceStateUpdateEvent {
565    type Output = VoiceState;
566
567    fn update(&mut self, cache: &Cache) -> Option<VoiceState> {
568        if let Some(guild_id) = self.voice_state.guild_id {
569            if let Some(mut guild) = cache.guilds.get_mut(&guild_id) {
570                if let Some(member) = &self.voice_state.member {
571                    guild.members.insert(member.user.id, member.clone());
572                }
573
574                if self.voice_state.channel_id.is_some() {
575                    // Update or add to the voice state list
576                    guild.voice_states.insert(self.voice_state.user_id, self.voice_state.clone())
577                } else {
578                    // Remove the user from the voice state list
579                    guild.voice_states.remove(&self.voice_state.user_id)
580                }
581            } else {
582                None
583            }
584        } else {
585            None
586        }
587    }
588}
589
590impl CacheUpdate for VoiceChannelStatusUpdateEvent {
591    type Output = String;
592
593    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
594        let mut guild = cache.guilds.get_mut(&self.guild_id)?;
595        let channel = guild.channels.get_mut(&self.id)?;
596
597        let old = channel.status.clone();
598        channel.status.clone_from(&self.status);
599        old
600    }
601}