pub struct Http {
pub client: Client,
pub base_url: String,
/* private fields */
}Expand description
HTTP client for making REST API calls.
Created automatically by the client builder. Available as ctx.http in event handlers
or directly if you just need REST calls without a gateway connection:
use fluxer::http::Http;
#[tokio::main]
async fn main() {
let http = Http::new("your-bot-token", "https://api.fluxer.app/v1".to_string());
let me = http.get_me().await.unwrap();
println!("Bot user: {}", me.username);
}Fields§
§client: Client§base_url: StringImplementations§
Source§impl Http
impl Http
Sourcepub fn new(token: &str, base_url: String) -> Self
pub fn new(token: &str, base_url: String) -> Self
Creates a new HTTP client. The token is sent as Bot {token} in the
Authorization header on every request.
pub fn get_token(&self) -> &str
Sourcepub async fn get_gateway(&self) -> Result<String, ClientError>
pub async fn get_gateway(&self) -> Result<String, ClientError>
Fetches the gateway URL. Used internally during connection setup.
Sourcepub async fn get_me(&self) -> Result<User, ClientError>
pub async fn get_me(&self) -> Result<User, ClientError>
Fetches the bot’s own user object.
Sourcepub async fn get_current_user_guilds(&self) -> Result<Vec<Guild>, ClientError>
pub async fn get_current_user_guilds(&self) -> Result<Vec<Guild>, ClientError>
Returns all guilds the bot is in.
Sourcepub async fn get_channel(
&self,
channel_id: &str,
) -> Result<Channel, ClientError>
pub async fn get_channel( &self, channel_id: &str, ) -> Result<Channel, ClientError>
Fetches a channel by ID.
Sourcepub async fn edit_channel(
&self,
channel_id: &str,
payload: &ChannelCreatePayload,
) -> Result<Channel, ClientError>
pub async fn edit_channel( &self, channel_id: &str, payload: &ChannelCreatePayload, ) -> Result<Channel, ClientError>
Edits a channel. Only the fields you set in the payload will change.
Sourcepub async fn delete_channel(&self, channel_id: &str) -> Result<(), ClientError>
pub async fn delete_channel(&self, channel_id: &str) -> Result<(), ClientError>
Permanently deletes a channel. Can’t be undone.
Sourcepub async fn trigger_typing(&self, channel_id: &str) -> Result<(), ClientError>
pub async fn trigger_typing(&self, channel_id: &str) -> Result<(), ClientError>
Triggers the “Bot is typing…” indicator. Lasts ~10 seconds or until the bot sends a message. (I actually haven’t tested this)
Sourcepub async fn get_messages(
&self,
channel_id: &str,
query: GetMessagesQuery,
) -> Result<Vec<Message>, ClientError>
pub async fn get_messages( &self, channel_id: &str, query: GetMessagesQuery, ) -> Result<Vec<Message>, ClientError>
Fetches messages from a channel. Use GetMessagesQuery to paginate.
use fluxer::prelude::*;
let query = GetMessagesQuery {
limit: Some(10),
..Default::default()
};
let messages = http.get_messages("channel_id", query).await.unwrap();Examples found in repository?
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 get_message(
&self,
channel_id: &str,
message_id: &str,
) -> Result<Message, ClientError>
pub async fn get_message( &self, channel_id: &str, message_id: &str, ) -> Result<Message, ClientError>
Fetches a single message by ID.
Sourcepub async fn send_message(
&self,
channel_id: &str,
content: &str,
) -> Result<Message, ClientError>
pub async fn send_message( &self, channel_id: &str, content: &str, ) -> Result<Message, ClientError>
Sends a text message. For embeds or other options, use
send_message_advanced.
Examples found in repository?
27 async fn on_message(&self, ctx: Context, msg: Message) {
28 if msg.author.bot.unwrap_or(false) {
29 return;
30 }
31
32 let content = match msg.content.as_deref() {
33 Some(c) => c,
34 None => return,
35 };
36
37 let channel_id = msg.channel_id.as_deref().unwrap_or_default();
38 let guild_id = match msg.guild_id.as_deref() {
39 Some(id) => id,
40 None => return,
41 };
42
43 let (cmd, args) = match parse_command(content) {
44 Some(v) => v,
45 None => return,
46 };
47
48 match cmd {
49 "join" => {
50 if args.is_empty() {
51 let _ = ctx.http.send_message(channel_id, "`!join <voice_channel_id>`").await;
52 return;
53 }
54
55 match ctx.join_voice(guild_id, args).await {
56 Ok(conn) => {
57 *self.voice.lock().await = Some(conn);
58 let _ = ctx.http.send_message(channel_id, "Joined.").await;
59 }
60 Err(e) => {
61 let _ = ctx.http.send_message(channel_id, &format!("Failed: {}", e)).await;
62 }
63 }
64 }
65
66 "leave" => {
67 if let Some(handle) = self.playback.lock().await.take() {
68 handle.abort();
69 }
70 *self.voice.lock().await = None;
71 let _ = ctx.leave_voice(guild_id).await;
72 let _ = ctx.http.send_message(channel_id, "Left.").await;
73 }
74
75 "play" => {
76 let conn = self.voice.lock().await;
77 let conn = match conn.as_ref() {
78 Some(c) => c,
79 None => {
80 let _ = ctx.http.send_message(channel_id, "Not in a voice channel.").await;
81 return;
82 }
83 };
84
85 if let Some(handle) = self.playback.lock().await.take() {
86 handle.abort();
87 }
88
89 match conn.play_music(AUDIO_FILE, ctx.http.clone(), channel_id.to_string()).await {
90 Ok(handle) => {
91 *self.playback.lock().await = Some(handle);
92 let _ = ctx.http.send_message(channel_id, &format!("Playing `{}`.", AUDIO_FILE)).await;
93 }
94 Err(e) => {
95 let _ = ctx.http.send_message(channel_id, &format!("Failed: {}", e)).await;
96 }
97 }
98 }
99
100 "stop" => {
101 if let Some(handle) = self.playback.lock().await.take() {
102 handle.abort();
103 let _ = ctx.http.send_message(channel_id, "Stopped.").await;
104 } else {
105 let _ = ctx.http.send_message(channel_id, "Nothing is playing.").await;
106 }
107 }
108
109 _ => {}
110 }
111 }More examples
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 send_message_advanced(
&self,
channel_id: &str,
payload: &MessageCreatePayload,
) -> Result<Message, ClientError>
pub async fn send_message_advanced( &self, channel_id: &str, payload: &MessageCreatePayload, ) -> Result<Message, ClientError>
Sends a message with full control over the payload (embeds, TTS, replies, etc).
Sourcepub async fn send_embed(
&self,
channel_id: &str,
content: Option<&str>,
embeds: Vec<Embed>,
) -> Result<Message, ClientError>
pub async fn send_embed( &self, channel_id: &str, content: Option<&str>, embeds: Vec<Embed>, ) -> Result<Message, ClientError>
Shorthand for sending embeds. Wraps send_message_advanced.
Examples found in repository?
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 edit_message(
&self,
channel_id: &str,
message_id: &str,
content: &str,
) -> Result<Message, ClientError>
pub async fn edit_message( &self, channel_id: &str, message_id: &str, content: &str, ) -> Result<Message, ClientError>
Edits a message’s content. Bot must be the author.
Examples found in repository?
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 edit_message_advanced(
&self,
channel_id: &str,
message_id: &str,
payload: &MessageCreatePayload,
) -> Result<Message, ClientError>
pub async fn edit_message_advanced( &self, channel_id: &str, message_id: &str, payload: &MessageCreatePayload, ) -> Result<Message, ClientError>
Edits a message with full control over the payload.
Sourcepub async fn delete_message(
&self,
channel_id: &str,
message_id: &str,
) -> Result<(), ClientError>
pub async fn delete_message( &self, channel_id: &str, message_id: &str, ) -> Result<(), ClientError>
Deletes a message. Bot must be the author, or have Manage Messages.
Examples found in repository?
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 bulk_delete_messages(
&self,
channel_id: &str,
message_ids: Vec<&str>,
) -> Result<(), ClientError>
pub async fn bulk_delete_messages( &self, channel_id: &str, message_ids: Vec<&str>, ) -> Result<(), ClientError>
Deletes multiple messages at once. Way faster than deleting one by one.
Examples found in repository?
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 add_reaction(
&self,
channel_id: &str,
message_id: &str,
emoji: &str,
) -> Result<(), ClientError>
pub async fn add_reaction( &self, channel_id: &str, message_id: &str, emoji: &str, ) -> Result<(), ClientError>
Reacts to a message as the bot. emoji should be a unicode emoji like
"👍" or a custom emoji in name:id format. You can use
Emoji::to_reaction_string to get the right format.
Examples found in repository?
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 remove_own_reaction(
&self,
channel_id: &str,
message_id: &str,
emoji: &str,
) -> Result<(), ClientError>
pub async fn remove_own_reaction( &self, channel_id: &str, message_id: &str, emoji: &str, ) -> Result<(), ClientError>
Removes the bot’s own reaction from a message.
Sourcepub async fn remove_user_reaction(
&self,
channel_id: &str,
message_id: &str,
emoji: &str,
user_id: &str,
) -> Result<(), ClientError>
pub async fn remove_user_reaction( &self, channel_id: &str, message_id: &str, emoji: &str, user_id: &str, ) -> Result<(), ClientError>
Removes someone else’s reaction. Needs Manage Messages permission.
Sourcepub async fn get_reactions(
&self,
channel_id: &str,
message_id: &str,
emoji: &str,
) -> Result<Vec<User>, ClientError>
pub async fn get_reactions( &self, channel_id: &str, message_id: &str, emoji: &str, ) -> Result<Vec<User>, ClientError>
Gets the list of users who reacted with a specific emoji.
Sourcepub async fn clear_reactions(
&self,
channel_id: &str,
message_id: &str,
) -> Result<(), ClientError>
pub async fn clear_reactions( &self, channel_id: &str, message_id: &str, ) -> Result<(), ClientError>
Removes all reactions from a message. Needs Manage Messages.
Sourcepub async fn clear_reactions_for_emoji(
&self,
channel_id: &str,
message_id: &str,
emoji: &str,
) -> Result<(), ClientError>
pub async fn clear_reactions_for_emoji( &self, channel_id: &str, message_id: &str, emoji: &str, ) -> Result<(), ClientError>
Removes all reactions for a specific emoji. Needs Manage Messages.
Sourcepub async fn get_pins(
&self,
channel_id: &str,
) -> Result<PinsResponse, ClientError>
pub async fn get_pins( &self, channel_id: &str, ) -> Result<PinsResponse, ClientError>
Fetches pinned messages in a channel.
Sourcepub async fn pin_message(
&self,
channel_id: &str,
message_id: &str,
) -> Result<(), ClientError>
pub async fn pin_message( &self, channel_id: &str, message_id: &str, ) -> Result<(), ClientError>
Pins a message. Needs Manage Messages.
Sourcepub async fn unpin_message(
&self,
channel_id: &str,
message_id: &str,
) -> Result<(), ClientError>
pub async fn unpin_message( &self, channel_id: &str, message_id: &str, ) -> Result<(), ClientError>
Unpins a message. Needs Manage Messages.
Sourcepub async fn get_invite(&self, invite_code: &str) -> Result<Invite, ClientError>
pub async fn get_invite(&self, invite_code: &str) -> Result<Invite, ClientError>
Fetches an invite by code. Includes approximate member counts.
Sourcepub async fn create_invite(
&self,
channel_id: &str,
payload: &CreateInvitePayload,
) -> Result<Invite, ClientError>
pub async fn create_invite( &self, channel_id: &str, payload: &CreateInvitePayload, ) -> Result<Invite, ClientError>
Creates an invite for a channel.
Sourcepub async fn delete_invite(&self, invite_code: &str) -> Result<(), ClientError>
pub async fn delete_invite(&self, invite_code: &str) -> Result<(), ClientError>
Deletes an invite by code.
Sourcepub async fn get_channel_invites(
&self,
channel_id: &str,
) -> Result<Vec<Invite>, ClientError>
pub async fn get_channel_invites( &self, channel_id: &str, ) -> Result<Vec<Invite>, ClientError>
Returns all active invites for a channel.
Sourcepub async fn get_guild_invites(
&self,
guild_id: &str,
) -> Result<Vec<Invite>, ClientError>
pub async fn get_guild_invites( &self, guild_id: &str, ) -> Result<Vec<Invite>, ClientError>
Returns all active invites for a guild.
Sourcepub async fn get_guild(&self, guild_id: &str) -> Result<Guild, ClientError>
pub async fn get_guild(&self, guild_id: &str) -> Result<Guild, ClientError>
Fetches a guild by ID.
Examples found in repository?
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 edit_guild(
&self,
guild_id: &str,
payload: &EditGuildPayload,
) -> Result<Guild, ClientError>
pub async fn edit_guild( &self, guild_id: &str, payload: &EditGuildPayload, ) -> Result<Guild, ClientError>
Edits guild settings. Only fields you set in the payload will change.
Sourcepub async fn delete_guild(&self, guild_id: &str) -> Result<(), ClientError>
pub async fn delete_guild(&self, guild_id: &str) -> Result<(), ClientError>
Permanently deletes a guild. The bot must be the owner. (not tested)
Sourcepub async fn get_guild_channels(
&self,
guild_id: &str,
) -> Result<Vec<Channel>, ClientError>
pub async fn get_guild_channels( &self, guild_id: &str, ) -> Result<Vec<Channel>, ClientError>
Returns all channels in a guild.
Sourcepub async fn create_channel(
&self,
guild_id: &str,
payload: &ChannelCreatePayload,
) -> Result<Channel, ClientError>
pub async fn create_channel( &self, guild_id: &str, payload: &ChannelCreatePayload, ) -> Result<Channel, ClientError>
Creates a channel in a guild. You need at least name in the payload.
Sourcepub async fn get_guild_member(
&self,
guild_id: &str,
user_id: &str,
) -> Result<Member, ClientError>
pub async fn get_guild_member( &self, guild_id: &str, user_id: &str, ) -> Result<Member, ClientError>
Fetches a single guild member.
Sourcepub async fn get_guild_members(
&self,
guild_id: &str,
limit: Option<u16>,
after: Option<&str>,
) -> Result<Vec<Member>, ClientError>
pub async fn get_guild_members( &self, guild_id: &str, limit: Option<u16>, after: Option<&str>, ) -> Result<Vec<Member>, ClientError>
Fetches guild members. limit caps at 1000, after is a user ID for pagination.
Examples found in repository?
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 kick_member(
&self,
guild_id: &str,
user_id: &str,
) -> Result<(), ClientError>
pub async fn kick_member( &self, guild_id: &str, user_id: &str, ) -> Result<(), ClientError>
Kicks a member from the guild.
Sourcepub async fn edit_member(
&self,
guild_id: &str,
user_id: &str,
payload: &EditMemberPayload,
) -> Result<Member, ClientError>
pub async fn edit_member( &self, guild_id: &str, user_id: &str, payload: &EditMemberPayload, ) -> Result<Member, ClientError>
Edits a member’s properties. To clear a nullable field like nick,
set it to Some(None).
Sourcepub async fn ban_member(
&self,
guild_id: &str,
user_id: &str,
reason: &str,
) -> Result<(), ClientError>
pub async fn ban_member( &self, guild_id: &str, user_id: &str, reason: &str, ) -> Result<(), ClientError>
Bans a member. reason is stored in the audit log.
Sourcepub async fn unban_member(
&self,
guild_id: &str,
user_id: &str,
) -> Result<(), ClientError>
pub async fn unban_member( &self, guild_id: &str, user_id: &str, ) -> Result<(), ClientError>
Removes a ban.
Sourcepub async fn get_guild_bans(
&self,
guild_id: &str,
) -> Result<Vec<Value>, ClientError>
pub async fn get_guild_bans( &self, guild_id: &str, ) -> Result<Vec<Value>, ClientError>
Returns the guild’s ban list.
Sourcepub async fn get_guild_roles(
&self,
guild_id: &str,
) -> Result<Vec<Role>, ClientError>
pub async fn get_guild_roles( &self, guild_id: &str, ) -> Result<Vec<Role>, ClientError>
Returns all roles in a guild.
Sourcepub async fn create_role(
&self,
guild_id: &str,
payload: &CreateRolePayload,
) -> Result<Role, ClientError>
pub async fn create_role( &self, guild_id: &str, payload: &CreateRolePayload, ) -> Result<Role, ClientError>
Creates a new role in a guild.
Sourcepub async fn edit_role(
&self,
guild_id: &str,
role_id: &str,
payload: &EditRolePayload,
) -> Result<Role, ClientError>
pub async fn edit_role( &self, guild_id: &str, role_id: &str, payload: &EditRolePayload, ) -> Result<Role, ClientError>
Edits a role’s properties.
Sourcepub async fn delete_role(
&self,
guild_id: &str,
role_id: &str,
) -> Result<(), ClientError>
pub async fn delete_role( &self, guild_id: &str, role_id: &str, ) -> Result<(), ClientError>
Deletes a role.
Sourcepub async fn get_guild_emojis(
&self,
guild_id: &str,
) -> Result<Vec<Emoji>, ClientError>
pub async fn get_guild_emojis( &self, guild_id: &str, ) -> Result<Vec<Emoji>, ClientError>
Returns all custom emojis in a guild.
Sourcepub async fn delete_guild_emoji(
&self,
guild_id: &str,
emoji_id: &str,
) -> Result<(), ClientError>
pub async fn delete_guild_emoji( &self, guild_id: &str, emoji_id: &str, ) -> Result<(), ClientError>
Deletes a custom emoji from a guild.
Sourcepub async fn get_channel_webhooks(
&self,
channel_id: &str,
) -> Result<Vec<Webhook>, ClientError>
pub async fn get_channel_webhooks( &self, channel_id: &str, ) -> Result<Vec<Webhook>, ClientError>
Returns all webhooks for a channel.
Sourcepub async fn get_guild_webhooks(
&self,
guild_id: &str,
) -> Result<Vec<Webhook>, ClientError>
pub async fn get_guild_webhooks( &self, guild_id: &str, ) -> Result<Vec<Webhook>, ClientError>
Returns all webhooks for a guild.
Sourcepub async fn create_webhook(
&self,
channel_id: &str,
name: &str,
avatar: Option<&str>,
) -> Result<Webhook, ClientError>
pub async fn create_webhook( &self, channel_id: &str, name: &str, avatar: Option<&str>, ) -> Result<Webhook, ClientError>
avatar should be a data URI if provided.
Sourcepub async fn delete_webhook(&self, webhook_id: &str) -> Result<(), ClientError>
pub async fn delete_webhook(&self, webhook_id: &str) -> Result<(), ClientError>
Deletes a webhook.
Sourcepub async fn send_files(
&self,
channel_id: &str,
files: Vec<AttachmentFile>,
content: Option<&str>,
) -> Result<Message, ClientError>
pub async fn send_files( &self, channel_id: &str, files: Vec<AttachmentFile>, content: Option<&str>, ) -> Result<Message, ClientError>
Sends a message with one or more file attachments. content is optional
if you just want to upload files with no text.
Examples found in repository?
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 send_message_with_files(
&self,
channel_id: &str,
payload: &MessageCreatePayload,
files: Vec<AttachmentFile>,
) -> Result<Message, ClientError>
pub async fn send_message_with_files( &self, channel_id: &str, payload: &MessageCreatePayload, files: Vec<AttachmentFile>, ) -> Result<Message, ClientError>
Like send_message_advanced but also uploads files as attachments.
Sourcepub async fn execute_webhook(
&self,
webhook_id: &str,
webhook_token: &str,
payload: &WebhookExecutePayload,
) -> Result<Option<Message>, ClientError>
pub async fn execute_webhook( &self, webhook_id: &str, webhook_token: &str, payload: &WebhookExecutePayload, ) -> Result<Option<Message>, ClientError>
Executes a webhook (sends a message through it). Uses wait=true so
the response includes the full message object.