pub struct Cache {
pub guilds: RwLock<HashMap<Snowflake, Guild>>,
pub channels: RwLock<HashMap<Snowflake, Channel>>,
pub users: RwLock<HashMap<Snowflake, User>>,
pub current_user: RwLock<Option<User>>,
}Expand description
In-memory gateway cache.
Fields§
§guilds: RwLock<HashMap<Snowflake, Guild>>§channels: RwLock<HashMap<Snowflake, Channel>>§users: RwLock<HashMap<Snowflake, User>>§current_user: RwLock<Option<User>>Implementations§
Source§impl Cache
impl Cache
pub fn new() -> Arc<Self>
Sourcepub async fn guild(&self, id: &str) -> Option<Guild>
pub async fn guild(&self, id: &str) -> Option<Guild>
Looks up a guild by ID. Populated from GUILD_CREATE / GUILD_UPDATE events.
Sourcepub async fn channel(&self, id: &str) -> Option<Channel>
pub async fn channel(&self, id: &str) -> Option<Channel>
Looks up a channel by ID. Populated from GUILD_CREATE and CHANNEL_CREATE / CHANNEL_UPDATE events.
Examples found in repository?
examples/bot.rs (line 29)
27 async fn on_message(&self, ctx: Context, msg: Message) {
28 let user_cached = ctx.cache.user(&msg.author.id).await.is_some();
29 let ch_cached = ctx.cache.channel(msg.channel_id.as_deref().unwrap_or("")).await.is_some();
30 let content_preview = msg.content.as_deref().unwrap_or("").chars().take(60).collect::<String>();
31 let attachments = msg.attachments.as_ref().map(|a| a.len()).unwrap_or(0);
32 let embeds = msg.embeds.as_ref().map(|e| e.len()).unwrap_or(0);
33 println!(
34 "[msg] author={}#{} channel={} guild={} | \"{}\" | attach={} embeds={} | cache: user={} ch={}",
35 msg.author.username,
36 msg.author.discriminator.as_deref().unwrap_or("0"),
37 msg.channel_id.as_deref().unwrap_or("?"),
38 msg.guild_id.as_deref().unwrap_or("DM"),
39 content_preview,
40 attachments,
41 embeds,
42 user_cached,
43 ch_cached,
44 );
45
46 if msg.author.bot.unwrap_or(false) {
47 return;
48 }
49
50 let content = match msg.content.as_deref() {
51 Some(c) => c,
52 None => return,
53 };
54
55 let channel_id = msg.channel_id.as_deref().unwrap_or_default();
56
57 let (cmd, args) = match parse_command(content) {
58 Some(v) => v,
59 None => return,
60 };
61
62 match cmd {
63 "ping" => {
64 let start = Instant::now();
65 let sent = ctx.http.send_message(channel_id, "Pong!").await;
66 let elapsed = start.elapsed().as_millis();
67
68 if let Ok(sent) = sent {
69 let _ = ctx.http.edit_message(
70 channel_id,
71 &sent.id,
72 &format!("Pong! {}ms", elapsed),
73 ).await;
74 }
75 }
76
77 "say" => {
78 if args.is_empty() {
79 let _ = ctx.http.send_message(channel_id, "Say what?").await;
80 return;
81 }
82 let _ = ctx.http.delete_message(channel_id, &msg.id).await;
83 let _ = ctx.http.send_message(channel_id, args).await;
84 }
85
86 "embed" => {
87 let (title, desc) = match args.split_once('|') {
88 Some((t, d)) => (t.trim(), d.trim()),
89 None => {
90 let _ = ctx.http.send_message(channel_id, "`!embed title | description`").await;
91 return;
92 }
93 };
94
95 let embed = EmbedBuilder::new()
96 .title(title)
97 .description(desc)
98 .color(0x5865F2)
99 .build();
100
101 let _ = ctx.http.send_embed(channel_id, None, vec![embed]).await;
102 }
103
104 "react" => {
105 let _ = ctx.http.add_reaction(channel_id, &msg.id, "❤️").await;
106 }
107
108 "purge" => {
109 let count: u8 = args.parse().unwrap_or(0);
110 if count == 0 || count > 100 {
111 let _ = ctx.http.send_message(channel_id, "1-100.").await;
112 return;
113 }
114
115 let query = GetMessagesQuery {
116 limit: Some(count),
117 ..Default::default()
118 };
119
120 if let Ok(messages) = ctx.http.get_messages(channel_id, query).await {
121 let ids: Vec<&str> = messages.iter().map(|m| m.id.as_str()).collect();
122 let _ = ctx.http.bulk_delete_messages(channel_id, ids).await;
123 }
124 }
125
126 "serverinfo" => {
127 let guild_id = match &msg.guild_id {
128 Some(id) => id.as_str(),
129 None => return,
130 };
131
132 if let Ok(guild) = ctx.http.get_guild(guild_id).await {
133 let name = guild.name.as_deref().unwrap_or("Unknown");
134
135 let members = ctx.http.get_guild_members(guild_id, Some(1000), None).await
136 .map(|m| m.len().to_string())
137 .unwrap_or("?".into());
138
139 let embed = EmbedBuilder::new()
140 .title(name)
141 .field("Members", &members, true)
142 .color(0x5865F2)
143 .build();
144
145 let _ = ctx.http.send_embed(channel_id, None, vec![embed]).await;
146 }
147 }
148
149 "attach" => {
150 if args.is_empty() {
151 let _ = ctx.http.send_message(channel_id, "Usage: `!attach <file path>`").await;
152 return;
153 }
154 let path = std::path::Path::new(args);
155 let filename = path
156 .file_name()
157 .and_then(|n| n.to_str())
158 .unwrap_or("file")
159 .to_string();
160 let content_type = match path.extension().and_then(|e| e.to_str()) {
161 Some("mp3") => "audio/mpeg",
162 Some("mp4") => "video/mp4",
163 Some("mov") => "video/quicktime",
164 Some("webm") => "video/webm",
165 Some("png") => "image/png",
166 Some("jpg") | Some("jpeg") => "image/jpeg",
167 Some("gif") => "image/gif",
168 Some("webp") => "image/webp",
169 Some("txt") => "text/plain",
170 Some("pdf") => "application/pdf",
171 _ => "application/octet-stream",
172 };
173 match tokio::fs::read(path).await {
174 Ok(data) => {
175 let file = AttachmentFile {
176 filename,
177 data,
178 content_type: Some(content_type.to_string()),
179 };
180 match ctx.http.send_files(channel_id, vec![file], None).await {
181 Ok(msg) => println!("[attach] sent message {}", msg.id),
182 Err(e) => eprintln!("[attach] error: {}", e),
183 }
184 }
185 Err(e) => {
186 eprintln!("[attach] failed to read file: {}", e);
187 let _ = ctx.http.send_message(channel_id, &format!("Failed to read file: {}", e)).await;
188 }
189 }
190 }
191
192 _ => {}
193 }
194 }Sourcepub async fn user(&self, id: &str) -> Option<User>
pub async fn user(&self, id: &str) -> Option<User>
Looks up a user by ID. Populated from GUILD_CREATE member lists and MESSAGE_CREATE authors.
Examples found in repository?
examples/bot.rs (line 28)
27 async fn on_message(&self, ctx: Context, msg: Message) {
28 let user_cached = ctx.cache.user(&msg.author.id).await.is_some();
29 let ch_cached = ctx.cache.channel(msg.channel_id.as_deref().unwrap_or("")).await.is_some();
30 let content_preview = msg.content.as_deref().unwrap_or("").chars().take(60).collect::<String>();
31 let attachments = msg.attachments.as_ref().map(|a| a.len()).unwrap_or(0);
32 let embeds = msg.embeds.as_ref().map(|e| e.len()).unwrap_or(0);
33 println!(
34 "[msg] author={}#{} channel={} guild={} | \"{}\" | attach={} embeds={} | cache: user={} ch={}",
35 msg.author.username,
36 msg.author.discriminator.as_deref().unwrap_or("0"),
37 msg.channel_id.as_deref().unwrap_or("?"),
38 msg.guild_id.as_deref().unwrap_or("DM"),
39 content_preview,
40 attachments,
41 embeds,
42 user_cached,
43 ch_cached,
44 );
45
46 if msg.author.bot.unwrap_or(false) {
47 return;
48 }
49
50 let content = match msg.content.as_deref() {
51 Some(c) => c,
52 None => return,
53 };
54
55 let channel_id = msg.channel_id.as_deref().unwrap_or_default();
56
57 let (cmd, args) = match parse_command(content) {
58 Some(v) => v,
59 None => return,
60 };
61
62 match cmd {
63 "ping" => {
64 let start = Instant::now();
65 let sent = ctx.http.send_message(channel_id, "Pong!").await;
66 let elapsed = start.elapsed().as_millis();
67
68 if let Ok(sent) = sent {
69 let _ = ctx.http.edit_message(
70 channel_id,
71 &sent.id,
72 &format!("Pong! {}ms", elapsed),
73 ).await;
74 }
75 }
76
77 "say" => {
78 if args.is_empty() {
79 let _ = ctx.http.send_message(channel_id, "Say what?").await;
80 return;
81 }
82 let _ = ctx.http.delete_message(channel_id, &msg.id).await;
83 let _ = ctx.http.send_message(channel_id, args).await;
84 }
85
86 "embed" => {
87 let (title, desc) = match args.split_once('|') {
88 Some((t, d)) => (t.trim(), d.trim()),
89 None => {
90 let _ = ctx.http.send_message(channel_id, "`!embed title | description`").await;
91 return;
92 }
93 };
94
95 let embed = EmbedBuilder::new()
96 .title(title)
97 .description(desc)
98 .color(0x5865F2)
99 .build();
100
101 let _ = ctx.http.send_embed(channel_id, None, vec![embed]).await;
102 }
103
104 "react" => {
105 let _ = ctx.http.add_reaction(channel_id, &msg.id, "❤️").await;
106 }
107
108 "purge" => {
109 let count: u8 = args.parse().unwrap_or(0);
110 if count == 0 || count > 100 {
111 let _ = ctx.http.send_message(channel_id, "1-100.").await;
112 return;
113 }
114
115 let query = GetMessagesQuery {
116 limit: Some(count),
117 ..Default::default()
118 };
119
120 if let Ok(messages) = ctx.http.get_messages(channel_id, query).await {
121 let ids: Vec<&str> = messages.iter().map(|m| m.id.as_str()).collect();
122 let _ = ctx.http.bulk_delete_messages(channel_id, ids).await;
123 }
124 }
125
126 "serverinfo" => {
127 let guild_id = match &msg.guild_id {
128 Some(id) => id.as_str(),
129 None => return,
130 };
131
132 if let Ok(guild) = ctx.http.get_guild(guild_id).await {
133 let name = guild.name.as_deref().unwrap_or("Unknown");
134
135 let members = ctx.http.get_guild_members(guild_id, Some(1000), None).await
136 .map(|m| m.len().to_string())
137 .unwrap_or("?".into());
138
139 let embed = EmbedBuilder::new()
140 .title(name)
141 .field("Members", &members, true)
142 .color(0x5865F2)
143 .build();
144
145 let _ = ctx.http.send_embed(channel_id, None, vec![embed]).await;
146 }
147 }
148
149 "attach" => {
150 if args.is_empty() {
151 let _ = ctx.http.send_message(channel_id, "Usage: `!attach <file path>`").await;
152 return;
153 }
154 let path = std::path::Path::new(args);
155 let filename = path
156 .file_name()
157 .and_then(|n| n.to_str())
158 .unwrap_or("file")
159 .to_string();
160 let content_type = match path.extension().and_then(|e| e.to_str()) {
161 Some("mp3") => "audio/mpeg",
162 Some("mp4") => "video/mp4",
163 Some("mov") => "video/quicktime",
164 Some("webm") => "video/webm",
165 Some("png") => "image/png",
166 Some("jpg") | Some("jpeg") => "image/jpeg",
167 Some("gif") => "image/gif",
168 Some("webp") => "image/webp",
169 Some("txt") => "text/plain",
170 Some("pdf") => "application/pdf",
171 _ => "application/octet-stream",
172 };
173 match tokio::fs::read(path).await {
174 Ok(data) => {
175 let file = AttachmentFile {
176 filename,
177 data,
178 content_type: Some(content_type.to_string()),
179 };
180 match ctx.http.send_files(channel_id, vec![file], None).await {
181 Ok(msg) => println!("[attach] sent message {}", msg.id),
182 Err(e) => eprintln!("[attach] error: {}", e),
183 }
184 }
185 Err(e) => {
186 eprintln!("[attach] failed to read file: {}", e);
187 let _ = ctx.http.send_message(channel_id, &format!("Failed to read file: {}", e)).await;
188 }
189 }
190 }
191
192 _ => {}
193 }
194 }Sourcepub async fn current_user(&self) -> Option<User>
pub async fn current_user(&self) -> Option<User>
Returns the bot’s own User object, populated from the READY event.
Sourcepub async fn guild_count(&self) -> usize
pub async fn guild_count(&self) -> usize
Returns the number of guilds currently in cache.
Auto Trait Implementations§
impl !Freeze for Cache
impl !RefUnwindSafe for Cache
impl Send for Cache
impl Sync for Cache
impl Unpin for Cache
impl UnsafeUnpin for Cache
impl !UnwindSafe for Cache
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more