Skip to content

Commit

Permalink
[Telegram] Wait then retry if rate limited
Browse files Browse the repository at this point in the history
  • Loading branch information
SpriteOvO committed Nov 14, 2024
1 parent 0aff506 commit 7dcf174
Showing 1 changed file with 37 additions and 3 deletions.
40 changes: 37 additions & 3 deletions src/notify/platform/telegram/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,35 @@ impl<'a> Request<'a> {
method: &str,
body: &json::Value,
) -> anyhow::Result<Response<T>> {
Self::send_request_with_files(self, method, body, None as Option<[FileUrl; 0]>).await
self.send_request_inner(method, body, None as Option<[&FileUrl; 0]>, true)
.await
}

async fn send_request_with_files<T: DeserializeOwned>(
&self,
method: &str,
body: &json::Value,
file_urls: Option<impl IntoIterator<Item = FileUrl<'_>>>,
) -> anyhow::Result<Response<T>> {
let file_urls = file_urls.map(|f| f.into_iter().collect::<Vec<_>>());
self.send_request_inner(method, body, file_urls.as_ref().map(|f| f.iter()), true)
.await
}

async fn send_request_inner<'b, T: DeserializeOwned>(
&self,
method: &str,
body: &json::Value,
// If `file_urls` specified, the media fields in body should be replaced with
// "attach://{index}"
file_urls: Option<impl IntoIterator<Item = FileUrl<'_>>>,
file_urls: Option<impl IntoIterator<Item = &'b FileUrl<'b>> + Clone>,
retry: bool,
) -> anyhow::Result<Response<T>> {
let url = format!("https://api.telegram.org/bot{}/{}", self.token, method);

let mut client = helper::reqwest_client()?.post(url);

if let Some(file_urls) = file_urls {
if let Some(file_urls) = file_urls.clone() {
let form = form_append_json(Form::new(), body.as_object().unwrap());
let form = futures::stream::iter(file_urls)
.enumerate()
Expand Down Expand Up @@ -103,6 +116,27 @@ impl<'a> Request<'a> {
let resp: Response<T> = json::from_str(&text).map_err(|err| {
anyhow!("failed to deserialize response: {err}, status: {status}, text: '{text}', request '{body}'")
})?;

if retry {
if !resp.ok && resp.description.is_some() {
if let Some(after) = resp
.description
.as_deref()
.unwrap()
.strip_prefix("Too Many Requests: retry after ")
{
warn!("Telegram rate limited, retry after '{}' + 1 seconds", after);

let after = after
.parse::<u64>()
.map_err(|err| anyhow!("failed to parse rate limit duration: {err}"))?;
tokio::time::sleep(tokio::time::Duration::from_secs(after + 1)).await;

return Box::pin(self.send_request_inner(method, body, file_urls, false)).await;
}
}
}

Ok(resp)
}

Expand Down

0 comments on commit 7dcf174

Please sign in to comment.