aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-04 01:11:50 +0100
committersalmonik <salmonik@tuta.io>2026-11-04 01:11:50 +0100
commitfd93334a21907f959018e1b1f5df747a98d186c8 (patch)
tree259e595a570b42a5ea082f596e1cb97e5011cfba
parenthttp: add connect and request timeouts (diff)
downloadsenator-sperma-fd93334a21907f959018e1b1f5df747a98d186c8.tar.gz
senator-sperma-fd93334a21907f959018e1b1f5df747a98d186c8.zip
processes: add timeouts and keep decoding off the runtime
-rw-r--r--src/commands/math.rs19
-rw-r--r--src/commands/qr.rs12
-rw-r--r--src/commands/utilities.rs15
-rw-r--r--src/voice/mod.rs36
4 files changed, 53 insertions, 29 deletions
diff --git a/src/commands/math.rs b/src/commands/math.rs
index 43a7de8..25ddaab 100644
--- a/src/commands/math.rs
+++ b/src/commands/math.rs
@@ -57,11 +57,20 @@ pub async fn math(
57 return Ok(()); 57 return Ok(());
58 } 58 }
59 59
60 let output = tokio::process::Command::new("qalc") 60 let output = match tokio::time::timeout(
61 .arg(&equation) 61 std::time::Duration::from_secs(5),
62 .output() 62 tokio::process::Command::new("qalc")
63 .await 63 .arg(&equation)
64 .map_err(|e| Error::Custom(lang::fmt_math_qalc_err(&e)))?; 64 .output(),
65 )
66 .await
67 {
68 Ok(result) => result.map_err(|e| Error::Custom(lang::fmt_math_qalc_err(&e)))?,
69 Err(_) => {
70 ctx.say(lang::L_MATH_NO_RESULT).await?;
71 return Ok(());
72 }
73 };
65 74
66 let result = String::from_utf8_lossy(&output.stdout).trim().to_string(); 75 let result = String::from_utf8_lossy(&output.stdout).trim().to_string();
67 if result.is_empty() { 76 if result.is_empty() {
diff --git a/src/commands/qr.rs b/src/commands/qr.rs
index 26232ee..c0b8af0 100644
--- a/src/commands/qr.rs
+++ b/src/commands/qr.rs
@@ -61,10 +61,14 @@ pub async fn dekodowanie(
61 .await? 61 .await?
62 .bytes() 62 .bytes()
63 .await?; 63 .await?;
64 let img = image::load_from_memory(&img_data)?; 64 // Decoding is CPU-heavy: keep it off the async runtime.
65 let gray = img.to_luma8(); 65 let img_data = img_data.to_vec();
66 66 let decoded = tokio::task::spawn_blocking(move || {
67 let decoded = decode_qr_simple(&gray); 67 let img = image::load_from_memory(&img_data).ok()?;
68 let gray = img.to_luma8();
69 decode_qr_simple(&gray)
70 })
71 .await?;
68 match decoded { 72 match decoded {
69 Some(text) => { 73 Some(text) => {
70 ctx.say(lang::fmt_qr_decoded(&text)).await?; 74 ctx.say(lang::fmt_qr_decoded(&text)).await?;
diff --git a/src/commands/utilities.rs b/src/commands/utilities.rs
index bf93491..c26fd0e 100644
--- a/src/commands/utilities.rs
+++ b/src/commands/utilities.rs
@@ -1,3 +1,5 @@
1use std::time::Duration;
2
1use poise::serenity_prelude as serenity; 3use poise::serenity_prelude as serenity;
2use tracing::warn; 4use tracing::warn;
3 5
@@ -524,10 +526,15 @@ async fn run_download(
524 } 526 }
525 cmd.arg("--").arg(sanitize_yt_url(url)); 527 cmd.arg("--").arg(sanitize_yt_url(url));
526 528
527 let output = cmd 529 let output = match tokio::time::timeout(Duration::from_secs(600), cmd.output()).await {
528 .output() 530 Ok(result) => result.map_err(|e| Error::Custom(lang::fmt_ytdlp_err(&e)))?,
529 .await 531 Err(_) => {
530 .map_err(|e| Error::Custom(lang::fmt_ytdlp_err(&e)))?; 532 let _ = tokio::fs::remove_dir_all(&dl_dir).await;
533 ctx.say(lang::fmt_download_failed("download timed out after 10 minutes"))
534 .await?;
535 return Ok(());
536 }
537 };
531 if !output.status.success() { 538 if !output.status.success() {
532 let stderr = String::from_utf8_lossy(&output.stderr); 539 let stderr = String::from_utf8_lossy(&output.stderr);
533 // Keep the full yt-dlp trace in the logs; the user only sees the 540 // Keep the full yt-dlp trace in the logs; the user only sees the
diff --git a/src/voice/mod.rs b/src/voice/mod.rs
index a6baa64..5043508 100644
--- a/src/voice/mod.rs
+++ b/src/voice/mod.rs
@@ -237,22 +237,26 @@ fn decode_stream(mss: MediaSourceStream) -> Result<songbird::input::Input> {
237/// Download audio via yt-dlp, collect stdout into memory, return the raw bytes. 237/// Download audio via yt-dlp, collect stdout into memory, return the raw bytes.
238/// Works for both finite media and live streams (yt-dlp handles the difference). 238/// Works for both finite media and live streams (yt-dlp handles the difference).
239pub async fn ytdlp_download(url: &str) -> Result<Vec<u8>> { 239pub async fn ytdlp_download(url: &str) -> Result<Vec<u8>> {
240 let output = tokio::process::Command::new("yt-dlp") 240 let output = tokio::time::timeout(
241 .args([ 241 Duration::from_secs(600),
242 "--ignore-config", 242 tokio::process::Command::new("yt-dlp")
243 "-f", 243 .args([
244 "bestaudio", 244 "--ignore-config",
245 "-o", 245 "-f",
246 "-", 246 "bestaudio",
247 "--no-playlist", 247 "-o",
248 "--", 248 "-",
249 url, 249 "--no-playlist",
250 ]) 250 "--",
251 .stdout(std::process::Stdio::piped()) 251 url,
252 .stderr(std::process::Stdio::piped()) 252 ])
253 .output() 253 .stdout(std::process::Stdio::piped())
254 .await 254 .stderr(std::process::Stdio::piped())
255 .map_err(|e| Error::Custom(lang::fmt_voice_ytdlp_launch(&e)))?; 255 .output(),
256 )
257 .await
258 .map_err(|_| Error::Custom("yt-dlp timed out after 10 minutes".into()))?
259 .map_err(|e| Error::Custom(lang::fmt_voice_ytdlp_launch(&e)))?;
256 260
257 if !output.status.success() { 261 if !output.status.success() {
258 let stderr = String::from_utf8_lossy(&output.stderr); 262 let stderr = String::from_utf8_lossy(&output.stderr);