Skip to content
This repository was archived by the owner on Jun 17, 2025. It is now read-only.

Commit 9cdcf21

Browse files
committed
Merge remote-tracking branch 'origin/master'
# Conflicts: # scripty_bot_utils/Cargo.toml
2 parents 102d170 + 32bdea6 commit 9cdcf21

File tree

9 files changed

+235
-132
lines changed

9 files changed

+235
-132
lines changed

Cargo.lock

Lines changed: 64 additions & 63 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripty_bot_utils/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ repository.workspace = true
88

99
[dependencies]
1010
uuid.workspace = true
11+
http.workspace = true
1112
time.workspace = true
1213
sqlx.workspace = true
1314
tokio.workspace = true

scripty_bot_utils/src/dm_support.rs

Lines changed: 67 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![forbid(clippy::expect_used, clippy::unwrap_used)]
2+
13
use base64::{Engine, prelude::BASE64_STANDARD};
24
use dashmap::DashMap;
35
use reqwest::header::CONTENT_TYPE;
@@ -22,6 +24,8 @@ use serenity::{
2224
},
2325
};
2426

27+
use crate::Error;
28+
2529
pub struct DmSupportStatus {
2630
webhook_cache: DashMap<ChannelId, Webhook>,
2731
}
@@ -50,16 +54,22 @@ impl DmSupportStatus {
5054
return;
5155
}
5256

53-
if message.guild_id.is_none() {
54-
self.handle_dm_message(ctx, message).await;
57+
let msg_id = message.id;
58+
59+
let res = if message.guild_id.is_none() {
60+
self.handle_dm_message(ctx, message).await
5561
} else {
56-
self.handle_guild_message(ctx, message).await;
62+
self.handle_guild_message(ctx, message).await
63+
};
64+
65+
if let Err(e) = res {
66+
error!(%msg_id, "got error while handing DM support: {}", e);
5767
}
5868
}
5969

60-
async fn handle_dm_message(&self, ctx: Context, message: Message) {
61-
let channel = self.get_or_create_channel(&ctx, &message.author).await;
62-
let hook = self.get_webhook(&ctx, &channel.id).await;
70+
async fn handle_dm_message(&self, ctx: Context, message: Message) -> Result<(), Error> {
71+
let channel = self.get_or_create_channel(&ctx, &message.author).await?;
72+
let hook = self.get_webhook(&ctx, &channel.id).await?;
6373

6474
let mut webhook_execute = ExecuteWebhook::default()
6575
.avatar_url(message.author.face())
@@ -81,8 +91,7 @@ impl DmSupportStatus {
8191
attachment.url.as_str(),
8292
attachment.filename.to_string(),
8393
)
84-
.await
85-
.expect("failed to handle message attachments"),
94+
.await?,
8695
);
8796
}
8897
webhook_execute = webhook_execute.files(attachments);
@@ -100,34 +109,35 @@ impl DmSupportStatus {
100109

101110
if let Err(e) = resp {
102111
warn!("failed to send message to webhook: {:?}", e);
103-
let _ = message
112+
message
104113
.reply(&ctx.http, format!("failed to send message: {}", e))
105-
.await;
114+
.await?;
106115
}
116+
117+
Ok(())
107118
}
108119

109-
async fn handle_guild_message(&self, ctx: Context, message: Message) {
120+
async fn handle_guild_message(&self, ctx: Context, message: Message) -> Result<(), Error> {
110121
let config = scripty_config::get_config();
111122
if message.guild_id != Some(GuildId::new(config.dm_support.guild_id)) {
112-
return;
123+
return Ok(());
113124
}
114125
let message_channel = message
115126
.channel(&ctx)
116-
.await
117-
.expect("failed to get message channel")
127+
.await?
118128
.guild()
119-
.expect("should be in guild");
129+
.ok_or_else(Error::expected_guild)?;
120130

121-
let category = get_forwarding_category(&ctx).await;
131+
let category = get_forwarding_category(&ctx).await?;
122132
if message_channel.parent_id != Some(category.id) {
123-
return;
133+
return Ok(());
124134
}
125135

126136
let user_id = match message_channel.base.name.parse::<u64>() {
127137
Ok(id) => id,
128138
Err(e) => {
129139
warn!("failed to parse user id from channel name: {:?}", e);
130-
return;
140+
return Ok(());
131141
}
132142
};
133143

@@ -163,27 +173,33 @@ impl DmSupportStatus {
163173
)
164174
.await;
165175
}
176+
177+
Ok(())
166178
}
167179

168-
async fn get_or_create_channel(&self, ctx: &Context, user: &User) -> GuildChannel {
180+
async fn get_or_create_channel(
181+
&self,
182+
ctx: &Context,
183+
user: &User,
184+
) -> Result<GuildChannel, Error> {
169185
let config = scripty_config::get_config();
170-
let category = get_forwarding_category(ctx).await;
186+
let category = get_forwarding_category(ctx).await?;
171187
let guild_id = GuildId::new(config.dm_support.guild_id);
172188

173189
let user_id_str = user.id.to_string();
174190

175191
let channel = {
176192
ctx.cache
177193
.guild(guild_id)
178-
.expect("failed to get guild")
194+
.ok_or_else(Error::expected_guild)?
179195
.channels
180196
.iter()
181197
.find(|c| c.parent_id == Some(category.id) && c.base.name == user_id_str)
182198
.cloned()
183199
};
184200

185201
if let Some(channel) = channel {
186-
return channel;
202+
return Ok(channel);
187203
}
188204

189205
let channel = guild_id
@@ -193,35 +209,26 @@ impl DmSupportStatus {
193209
.category(category.id)
194210
.kind(ChannelType::Text),
195211
)
196-
.await
197-
.expect("failed to create channel");
212+
.await?;
198213

199214
let user_face_url = user.face();
200-
let resp = reqwest::get(user_face_url)
201-
.await
202-
.expect("failed to fetch url");
215+
let resp = reqwest::get(user_face_url).await?;
203216
let content_type = resp
204217
.headers()
205218
.get(CONTENT_TYPE)
206-
.expect("expected Content-Type header")
207-
.to_str()
208-
.expect("not ASCII string");
219+
.ok_or_else(|| Error::custom("expected Content-Type header".to_string()))?
220+
.to_str()?;
209221

210222
let hook = channel
211223
.create_webhook(
212224
&ctx.http,
213-
CreateWebhook::new(user.tag()).avatar(
214-
ImageData::from_base64(format!(
215-
"data:{};base64,{}",
216-
content_type.to_ascii_lowercase(),
217-
BASE64_STANDARD
218-
.encode(resp.bytes().await.expect("failed to download image bytes"))
219-
))
220-
.expect("should always be valid image data"),
221-
),
225+
CreateWebhook::new(user.tag()).avatar(ImageData::from_base64(format!(
226+
"data:{};base64,{}",
227+
content_type.to_ascii_lowercase(),
228+
BASE64_STANDARD.encode(resp.bytes().await?)
229+
))?),
222230
)
223-
.await
224-
.expect("failed to create webhook");
231+
.await?;
225232
self.webhook_cache.insert(channel.id, hook);
226233

227234
if let Err(e) = self.handle_opening(ctx, user.id).await {
@@ -231,11 +238,10 @@ impl DmSupportStatus {
231238
&ctx.http,
232239
CreateMessage::default().content(format!("failed to handle opening: {}", e)),
233240
)
234-
.await
235-
.expect("failed to send message");
241+
.await?;
236242
}
237243

238-
channel
244+
Ok(channel)
239245
}
240246

241247
async fn handle_opening(&self, ctx: &Context, user: UserId) -> serenity::Result<()> {
@@ -254,45 +260,39 @@ impl DmSupportStatus {
254260
.map(|_| ())
255261
}
256262

257-
async fn get_webhook(&self, ctx: &Context, channel: &ChannelId) -> Webhook {
263+
async fn get_webhook(&self, ctx: &Context, channel: &ChannelId) -> Result<Webhook, Error> {
258264
let hook = self.webhook_cache.get(channel).map(|x| x.clone());
259265
if let Some(hook) = hook {
260-
return hook;
266+
return Ok(hook);
261267
}
262268

263-
if let Some(hook) = channel
264-
.webhooks(&ctx.http)
265-
.await
266-
.expect("error fetching hooks")
267-
.pop()
268-
{
269-
return hook;
269+
if let Some(hook) = channel.webhooks(&ctx.http).await?.pop() {
270+
return Ok(hook);
270271
}
271272

272273
let hook = channel
273274
.create_webhook(&ctx.http, CreateWebhook::new("Scripty"))
274-
.await
275-
.expect("failed to create webhook");
275+
.await?;
276276
self.webhook_cache.insert(*channel, hook.clone());
277-
hook
277+
Ok(hook)
278278
}
279279

280-
pub async fn close_ticket(&self, ctx: &Context, channel: GuildChannel) {
280+
pub async fn close_ticket(&self, ctx: &Context, channel: GuildChannel) -> Result<(), Error> {
281281
let config = scripty_config::get_config();
282282
if channel.base.guild_id != GuildId::new(config.dm_support.guild_id) {
283-
return;
283+
return Ok(());
284284
}
285285

286-
let category = get_forwarding_category(ctx).await;
286+
let category = get_forwarding_category(ctx).await?;
287287
if channel.parent_id != Some(category.id) {
288-
return;
288+
return Ok(());
289289
}
290290

291291
let user_id = match channel.base.name.parse::<u64>() {
292292
Ok(id) => UserId::new(id),
293293
Err(e) => {
294294
warn!("failed to parse user id from channel name: {:?}", e);
295-
return;
295+
return Ok(());
296296
}
297297
};
298298

@@ -313,15 +313,17 @@ impl DmSupportStatus {
313313

314314
self.webhook_cache.remove(&channel.id);
315315

316-
let _ = channel
316+
channel
317317
.delete(&ctx.http, Some("DM support ticket closed"))
318-
.await;
318+
.await?;
319+
320+
Ok(())
319321
}
320322
}
321323

322-
async fn get_forwarding_category(ctx: &Context) -> GuildChannel {
324+
async fn get_forwarding_category(ctx: &Context) -> Result<GuildChannel, Error> {
323325
ChannelId::new(scripty_config::get_config().dm_support.forwarding_category)
324326
.to_guild_channel(&ctx, None)
325327
.await
326-
.expect("failed to get forwarding category")
328+
.map_err(Error::from)
327329
}

scripty_bot_utils/src/error/error_type.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::{
55
};
66

77
use backtrace::Backtrace;
8+
use http::header::ToStrError;
89
use scripty_stt::{ModelError, OpusSourceError};
910
use serenity::{http::JsonErrorCode, model::channel::ChannelType, prelude::SerenityError};
1011

@@ -35,6 +36,8 @@ pub enum ErrorEnum {
3536
ExpectedGuild,
3637
ExpectedChannel,
3738
Join(scripty_audio_handler::JoinError),
39+
Reqwest(reqwest::Error),
40+
ToStr(ToStrError),
3841
ManualError,
3942
Redis(scripty_redis::redis::RedisError),
4043
RedisPool(scripty_redis::PoolError),
@@ -100,6 +103,20 @@ impl Error {
100103
}
101104
}
102105

106+
pub fn reqwest(err: reqwest::Error) -> Self {
107+
Error {
108+
bt: Backtrace::new_unresolved(),
109+
err: ErrorEnum::Reqwest(err),
110+
}
111+
}
112+
113+
pub fn to_str(err: ToStrError) -> Self {
114+
Error {
115+
bt: Backtrace::new_unresolved(),
116+
err: ErrorEnum::ToStr(err),
117+
}
118+
}
119+
103120
#[inline]
104121
pub fn manual() -> Self {
105122
Error {
@@ -245,6 +262,8 @@ impl Display for Error {
245262
ExpectedGuild => "expected this to be in a guild".into(),
246263
ExpectedChannel => "expected this to be in a channel".into(),
247264
Join(e) => format!("failed to join VC: {}", e).into(),
265+
Reqwest(e) => format!("error while sending http request: {}", e).into(),
266+
ToStr(e) => format!("error decoding http headers into string: {}", e).into(),
248267
ManualError => "manual error".into(),
249268
Redis(e) => format!("Redis returned an error: {}", e).into(),
250269
RedisPool(e) => format!("Redis pool returned an error: {}", e).into(),
@@ -283,6 +302,8 @@ impl StdError for Error {
283302
ExpectedGuild => None,
284303
ExpectedChannel => None,
285304
Join(e) => Some(e),
305+
Reqwest(e) => Some(e),
306+
ToStr(e) => Some(e),
286307
ManualError => None,
287308
Redis(e) => Some(e),
288309
RedisPool(e) => Some(e),
@@ -356,6 +377,24 @@ impl From<scripty_audio_handler::JoinError> for Error {
356377
}
357378
}
358379

380+
impl From<reqwest::Error> for Error {
381+
fn from(e: reqwest::Error) -> Self {
382+
Self {
383+
err: ErrorEnum::Reqwest(e),
384+
bt: Backtrace::new_unresolved(),
385+
}
386+
}
387+
}
388+
389+
impl From<ToStrError> for Error {
390+
fn from(e: ToStrError) -> Self {
391+
Self {
392+
err: ErrorEnum::ToStr(e),
393+
bt: Backtrace::new_unresolved(),
394+
}
395+
}
396+
}
397+
359398
impl From<scripty_redis::redis::RedisError> for Error {
360399
#[inline]
361400
fn from(e: scripty_redis::redis::RedisError) -> Self {

scripty_bot_utils/src/file_transcripts/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,5 +265,17 @@ fn format_transcript_msg<'a>(
265265

266266
msg
267267
}
268+
269+
TranscriptResultEnum::DiscordError { error } => {
270+
msg_content.push('\n');
271+
msg_content.push_str(&format_message!(
272+
resolved_language,
273+
"transcribe-message-discord-error",
274+
filename: filename.to_string(),
275+
error: format!("{:?}", error)
276+
));
277+
278+
msg
279+
}
268280
}
269281
}

0 commit comments

Comments
 (0)