fix: answer an inline query whose media Telegram cannot fetch

Every item was skipped — `needs_media_headers` for pixiv's pximg.net, or a
local ugoira/bsky MP4 that does not parse as a URL — and the function fell
through to `Ok(false)`, which the debounce reads as "retry this query". The
client got no answer at all (a spinner with nothing behind it) and every
keystroke re-ran the fetch, while an unsatisfiable link is the *permanent*
truth for that query: Telegram fetches inline result URLs itself and never
sends a Referer.

It now answers the empty result set with a 300 s window, so the client stops
spinning and the same query is served from Telegram's cache and from the
debounce (which only releases on a failure). A *failed* fetch still releases,
so a retry is not answered from a stale empty answer.

Verified with a real pixiv link through a real `Bot` against the stand-in
API: `AnswerInlineQuery` with `results: []` and `cache_time: 300` (and
`Ok(true)`, so no release).

`cargo fmt --check`, `cargo clippy --workspace --all-targets --locked -- -D
warnings` and `cargo test --workspace --locked` clean.
This commit is contained in:
2026-09-21 13:49:21 +08:00
parent 5ff921222a
commit 670a7bd02b
+16 -2
View File
@@ -135,8 +135,10 @@ pub async fn inline_query_handler(bot: Bot, query: InlineQuery) -> Result<(), Re
}
match answer_inline_query(bot, query).await {
Ok(true) => {}
// No results produced (or nothing to answer): let a repeat of the
// same query retry the fetch.
// The fetch or the answer call failed: release so a repeat of the
// same query may retry it. An *empty* answer is a real answer
// (`Ok(true)`), so a link whose media Telegram cannot fetch is not
// re-fetched on every keystroke.
Ok(false) | Err(_) => INLINE_DEBOUNCE_STATE.lock().release(user_id, &query_text),
}
});
@@ -233,6 +235,18 @@ async fn answer_inline_query(bot: Bot, query: InlineQuery) -> Result<bool, Reque
.await?;
return Ok(true);
}
// Every item was skipped: Telegram fetches an inline result's URL
// itself, so pixiv's hotlink-protected media (and a local ugoira /
// bsky MP4) can never be one. Answer *empty* — the client stops
// spinning, and the same query is not re-fetched on every
// keystroke: an unanswered query releases the debounce below
// (`Ok(false)`), which is what made this re-run the fetch each
// time, and the window lets Telegram serve the repeats itself.
log::debug!("inline: nothing Telegram can fetch for the query; answering empty");
bot.answer_inline_query(query.id, Vec::new())
.cache_time(300)
.await?;
return Ok(true);
}
Ok(None) => {}
Err(e) => log::error!("inline fetch [key={}]: {e}", log_key(&query.query)),