mirror of
https://github.com/TheFunny/TelegramTwitterMediaBot.git
synced 2026-09-26 23:52:05 +00:00
refactor(x-media): share the HTTP-status error mapping
twitter, twitter auth and bsky carried the same 404/410 -> NotFound, 401/403 -> Blocked, else Transient block (comments included). site::status_error holds it once. bilibili and misskey keep their own matches: neither maps 404/410 and each has a status the others do not (412 risk control, 400 + NO_SUCH_NOTE), so routing them through the shared block would have reclassified those statuses for the user.
This commit is contained in:
@@ -321,13 +321,7 @@ pub async fn fetch(handle: &str, rkey: &str) -> Result<Post, FetchError> {
|
|||||||
// 404/410 = gone (permanent); 429/5xx = transient and retried by fetch.
|
// 404/410 = gone (permanent); 429/5xx = transient and retried by fetch.
|
||||||
let status = response.status();
|
let status = response.status();
|
||||||
if !status.is_success() {
|
if !status.is_success() {
|
||||||
return match status.as_u16() {
|
return Err(crate::site::status_error("bsky", status));
|
||||||
404 | 410 => Err(FetchError::NotFound),
|
|
||||||
// A refusal or an auth demand is not a bad moment: retrying it
|
|
||||||
// three times only delays an error the user has to see.
|
|
||||||
401 | 403 => Err(FetchError::Blocked),
|
|
||||||
_ => Err(FetchError::Transient(format!("bsky status {status}"))),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
let text = response.text().await?;
|
let text = response.text().await?;
|
||||||
Post::from_json(&text, rkey.to_string())
|
Post::from_json(&text, rkey.to_string())
|
||||||
|
|||||||
@@ -281,6 +281,21 @@ pub enum FetchError {
|
|||||||
Io(std::io::Error),
|
Io(std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The error class for a non-success HTTP status, as the site adapters that
|
||||||
|
/// share this mapping classify it: 404/410 mean the post is gone and 401/403 a
|
||||||
|
/// refusal or an auth demand — both permanent, since retrying cannot change
|
||||||
|
/// either — while everything else (429, 5xx) is transient and retried by
|
||||||
|
/// [`fetch`]. `site` only names the adapter in the transient message; a site
|
||||||
|
/// whose statuses mean something else (bilibili's 412 risk control, misskey's
|
||||||
|
/// 400 with `NO_SUCH_NOTE`) maps those before falling back here.
|
||||||
|
pub fn status_error(site: &'static str, status: reqwest::StatusCode) -> FetchError {
|
||||||
|
match status.as_u16() {
|
||||||
|
404 | 410 => FetchError::NotFound,
|
||||||
|
401 | 403 => FetchError::Blocked,
|
||||||
|
_ => FetchError::Transient(format!("{site} status {status}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// How long a download may make no progress: the response head, and then each
|
/// How long a download may make no progress: the response head, and then each
|
||||||
/// individual chunk, must arrive within this window. Not a total timeout — see
|
/// individual chunk, must arrive within this window. Not a total timeout — see
|
||||||
/// [`DOWNLOAD_TOTAL_TIMEOUT`].
|
/// [`DOWNLOAD_TOTAL_TIMEOUT`].
|
||||||
|
|||||||
@@ -130,15 +130,7 @@ pub async fn fetch(id: &str) -> Result<Tweet, FetchError> {
|
|||||||
let status = response.status();
|
let status = response.status();
|
||||||
if !status.is_success() {
|
if !status.is_success() {
|
||||||
log::warn!("twitter auth fetch {id}: HTTP {status}");
|
log::warn!("twitter auth fetch {id}: HTTP {status}");
|
||||||
return match status.as_u16() {
|
return Err(crate::site::status_error("twitter auth", status));
|
||||||
404 | 410 => Err(FetchError::NotFound),
|
|
||||||
// A stale/refused `auth_token` is not a bad moment: retrying it
|
|
||||||
// three times only delays the report.
|
|
||||||
401 | 403 => Err(FetchError::Blocked),
|
|
||||||
_ => Err(FetchError::Transient(format!(
|
|
||||||
"twitter auth status {status}"
|
|
||||||
))),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
let text = response.text().await?;
|
let text = response.text().await?;
|
||||||
let json: Value = serde_json::from_str(&text)?;
|
let json: Value = serde_json::from_str(&text)?;
|
||||||
|
|||||||
@@ -103,13 +103,7 @@ pub async fn fetch(id: &str) -> Result<Tweet, FetchError> {
|
|||||||
// 404/410 = gone (permanent); 429/5xx = transient and retried by fetch.
|
// 404/410 = gone (permanent); 429/5xx = transient and retried by fetch.
|
||||||
let status = response.status();
|
let status = response.status();
|
||||||
if !status.is_success() {
|
if !status.is_success() {
|
||||||
return match status.as_u16() {
|
return Err(crate::site::status_error("twitter", status));
|
||||||
404 | 410 => Err(FetchError::NotFound),
|
|
||||||
// A refusal or an auth demand is not a bad moment: retrying it
|
|
||||||
// three times only delays an error the user has to see.
|
|
||||||
401 | 403 => Err(FetchError::Blocked),
|
|
||||||
_ => Err(FetchError::Transient(format!("twitter status {status}"))),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
let text = response.text().await?;
|
let text = response.text().await?;
|
||||||
// Classify before building the tweet (see [`parse_syndication_body`]), and
|
// Classify before building the tweet (see [`parse_syndication_body`]), and
|
||||||
|
|||||||
Reference in New Issue
Block a user