Skip to main content

serenity/cache/
event.rs

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