twilight_cache_inmemory/event/
message.rs1use crate::{config::ResourceType, CacheableModels, InMemoryCache, UpdateCache};
2use std::borrow::Cow;
3use twilight_model::gateway::payload::incoming::{
4 MessageCreate, MessageDelete, MessageDeleteBulk, MessageUpdate,
5};
6
7impl<CacheModels: CacheableModels> UpdateCache<CacheModels> for MessageCreate {
8 fn update(&self, cache: &InMemoryCache<CacheModels>) {
9 if cache.wants(ResourceType::USER) {
10 cache.cache_user(Cow::Borrowed(&self.author), self.guild_id);
11 }
12
13 if let (Some(member), Some(guild_id), true) = (
14 &self.member,
15 self.guild_id,
16 cache.wants(ResourceType::MEMBER),
17 ) {
18 cache.cache_borrowed_partial_member(guild_id, member, self.author.id);
19 }
20
21 if !cache.wants(ResourceType::MESSAGE) {
22 return;
23 }
24
25 let mut channel_messages = cache.channel_messages.entry(self.0.channel_id).or_default();
26
27 if channel_messages.len() >= cache.config.message_cache_size() {
32 if let Some(popped_id) = channel_messages.pop_back() {
33 cache.messages.remove(&popped_id);
34 }
35 }
36
37 channel_messages.push_front(self.0.id);
38 cache
39 .messages
40 .insert(self.0.id, CacheModels::Message::from(self.0.clone()));
41 }
42}
43
44impl<CacheModels: CacheableModels> UpdateCache<CacheModels> for MessageDelete {
45 fn update(&self, cache: &InMemoryCache<CacheModels>) {
46 if !cache.wants(ResourceType::MESSAGE) {
47 return;
48 }
49
50 cache.messages.remove(&self.id);
51
52 let mut channel_messages = cache.channel_messages.entry(self.channel_id).or_default();
53
54 if let Some(idx) = channel_messages.iter().position(|id| *id == self.id) {
55 channel_messages.remove(idx);
56 }
57 }
58}
59
60impl<CacheModels: CacheableModels> UpdateCache<CacheModels> for MessageDeleteBulk {
61 fn update(&self, cache: &InMemoryCache<CacheModels>) {
62 if !cache.wants(ResourceType::MESSAGE) {
63 return;
64 }
65
66 let mut channel_messages = cache.channel_messages.entry(self.channel_id).or_default();
67
68 for id in &self.ids {
69 cache.messages.remove(id);
70
71 if let Some(idx) = channel_messages
72 .iter()
73 .position(|message_id| message_id == id)
74 {
75 channel_messages.remove(idx);
76 }
77 }
78 }
79}
80
81impl<CacheModels: CacheableModels> UpdateCache<CacheModels> for MessageUpdate {
82 fn update(&self, cache: &InMemoryCache<CacheModels>) {
83 if cache.wants(ResourceType::USER) {
84 cache.cache_user(Cow::Borrowed(&self.author), self.guild_id);
85 }
86
87 if let (Some(member), Some(guild_id), true) = (
88 &self.member,
89 self.guild_id,
90 cache.wants(ResourceType::MEMBER),
91 ) {
92 cache.cache_borrowed_partial_member(guild_id, member, self.author.id);
93 }
94
95 if !cache.wants(ResourceType::MESSAGE) {
96 return;
97 }
98
99 if cache
104 .messages
105 .insert(self.id, CacheModels::Message::from(self.0.clone()))
106 .is_some()
107 {
108 return;
109 }
110
111 let mut channel_messages = cache.channel_messages.entry(self.0.channel_id).or_default();
112
113 if channel_messages.len() >= cache.config.message_cache_size() {
116 if let Some(popped_id) = channel_messages.pop_back() {
117 cache.messages.remove(&popped_id);
118 }
119 }
120
121 channel_messages.push_front(self.0.id);
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use crate::{DefaultInMemoryCache, ResourceType};
128 use twilight_model::{
129 channel::message::{Message, MessageFlags, MessageType},
130 gateway::payload::incoming::MessageCreate,
131 guild::{MemberFlags, PartialMember},
132 id::Id,
133 user::User,
134 util::{image_hash::ImageHashParseError, ImageHash, Timestamp},
135 };
136
137 #[allow(deprecated)]
138 #[test]
139 fn message_create() -> Result<(), ImageHashParseError> {
140 let joined_at = Some(Timestamp::from_secs(1_632_072_645).expect("non zero"));
141 let cache = DefaultInMemoryCache::builder()
142 .resource_types(ResourceType::MESSAGE | ResourceType::MEMBER | ResourceType::USER)
143 .message_cache_size(2)
144 .build();
145
146 let avatar = ImageHash::parse(b"e91c75bc7656063cc745f4e79d0b7664")?;
147 let flags = MemberFlags::BYPASSES_VERIFICATION | MemberFlags::DID_REJOIN;
148 let mut msg = Message {
149 activity: None,
150 application: None,
151 application_id: None,
152 attachments: Vec::new(),
153 author: User {
154 accent_color: None,
155 avatar: Some(avatar),
156 avatar_decoration: None,
157 avatar_decoration_data: None,
158 banner: None,
159 bot: false,
160 discriminator: 1,
161 email: None,
162 flags: None,
163 global_name: Some("test".to_owned()),
164 id: Id::new(3),
165 locale: None,
166 mfa_enabled: None,
167 name: "test".to_owned(),
168 premium_type: None,
169 public_flags: None,
170 system: None,
171 verified: None,
172 },
173 call: None,
174 channel_id: Id::new(2),
175 components: Vec::new(),
176 content: "ping".to_owned(),
177 edited_timestamp: None,
178 embeds: Vec::new(),
179 flags: Some(MessageFlags::empty()),
180 guild_id: Some(Id::new(1)),
181 id: Id::new(4),
182 interaction: None,
183 interaction_metadata: None,
184 kind: MessageType::Regular,
185 member: Some(PartialMember {
186 avatar: None,
187 communication_disabled_until: None,
188 deaf: false,
189 flags,
190 joined_at,
191 mute: false,
192 nick: Some("member nick".to_owned()),
193 permissions: None,
194 premium_since: None,
195 roles: Vec::new(),
196 user: None,
197 }),
198 mention_channels: Vec::new(),
199 mention_everyone: false,
200 mention_roles: Vec::new(),
201 mentions: Vec::new(),
202 message_snapshots: Vec::new(),
203 pinned: false,
204 poll: None,
205 reactions: Vec::new(),
206 reference: None,
207 referenced_message: None,
208 role_subscription_data: None,
209 sticker_items: Vec::new(),
210 timestamp: Timestamp::from_secs(1_632_072_645).expect("non zero"),
211 thread: None,
212 tts: false,
213 webhook_id: None,
214 };
215
216 cache.update(&MessageCreate(msg.clone()));
217 msg.id = Id::new(5);
218 cache.update(&MessageCreate(msg));
219
220 {
221 let entry = cache.user_guilds(Id::new(3)).unwrap();
222 assert_eq!(entry.value().len(), 1);
223 }
224 assert_eq!(
225 cache.member(Id::new(1), Id::new(3)).unwrap().user_id,
226 Id::new(3),
227 );
228 {
229 let entry = cache.channel_messages.get(&Id::new(2)).unwrap();
230 assert_eq!(entry.value().len(), 2);
231 }
232
233 let messages = cache
234 .channel_messages(Id::new(2))
235 .expect("channel is in cache");
236
237 let mut iter = messages.iter();
238 assert_eq!(Some(&Id::new(5)), iter.next());
240 assert_eq!(Some(&Id::new(4)), iter.next());
241 assert!(iter.next().is_none());
242
243 Ok(())
244 }
245}