From 190eb50ed956f86bbc9fedbc35399d75f4127598 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Fri, 1 May 2026 18:56:03 -0400 Subject: [PATCH] telegram: bound photo download to 60s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HttpClient::request_timeout only covers send_request, not body collect, so a stuck download would otherwise stall the entire long-poll loop indefinitely. tokio::time::timeout at the call site keeps the failure contained — a slow/dead download surfaces as the same [image: download failed: ...] marker as any other error. 60s is generous for the 1-5MB photos Kent typically sends; Telegram's bot getFile cap is 20MB, which would still complete on most connections. Co-Authored-By: Proof of Concept --- channels/telegram/src/main.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/channels/telegram/src/main.rs b/channels/telegram/src/main.rs index 837a044..ec7aa66 100644 --- a/channels/telegram/src/main.rs +++ b/channels/telegram/src/main.rs @@ -221,7 +221,15 @@ async fn get_updates( error!("telegram photo: missing file_id in update {update_id}"); (caption, None) } else { - match download_telegram_file(client, token, file_id).await { + // Bound the download — HttpClient::request_timeout only covers + // send_request, not body collect, so an indefinitely-slow body + // would otherwise stall every subsequent poll. + let dl = tokio::time::timeout( + std::time::Duration::from_secs(60), + download_telegram_file(client, token, file_id), + ).await + .unwrap_or_else(|_| Err("download timed out after 60s".into())); + match dl { Ok(path) => (caption, Some(path)), Err(e) => { error!("telegram photo download failed (file_id={file_id}): {e}");