feat(nextcloud): support exponential backoff with jitter
Some checks failed
Test / build (map[name:nightly]) (push) Successful in 2m21s
Test / build (map[name:stable]) (push) Successful in 2m6s
Release Please / Release-plz (push) Failing after 27s

This commit is contained in:
Paul Campbell 2024-12-22 14:14:53 +00:00
parent 4cdfdaec6f
commit 5d62b7edd0
2 changed files with 51 additions and 67 deletions

View file

@ -5,21 +5,18 @@ use kxio::{
net::{Net, ReqBuilder}, net::{Net, ReqBuilder},
}; };
use reqwest::multipart; use reqwest::multipart;
use serde::de::DeserializeOwned;
use serde_json::json; use serde_json::json;
use crate::nextcloud::model::{
Label, NextcloudCardDescription, NextcloudCardTitle, NextcloudLabelColour, NextcloudLabelTitle,
NextcloudStackTitle,
};
use crate::{ use crate::{
api_result::APIResult, api_result::APIResult,
f, f,
nextcloud::model::{ nextcloud::model::{
Attachment, Board, Card, NextcloudBoardId, NextcloudCardId, NextcloudHostname, Attachment, Board, Card, Label, NextcloudBoardId, NextcloudCardDescription,
NextcloudLabelId, NextcloudPassword, NextcloudStackId, NextcloudUsername, Stack, NextcloudCardId, NextcloudCardTitle, NextcloudHostname, NextcloudLabelColour,
NextcloudLabelId, NextcloudLabelTitle, NextcloudPassword, NextcloudStackId,
NextcloudStackTitle, NextcloudUsername, Stack,
}, },
FullCtx, with_exponential_backoff, FullCtx,
}; };
pub(crate) struct DeckClient<'ctx> { pub(crate) struct DeckClient<'ctx> {
@ -53,13 +50,17 @@ impl<'ctx> DeckClient<'ctx> {
url: impl Into<String>, url: impl Into<String>,
custom: fn(&Net, String) -> ReqBuilder, custom: fn(&Net, String) -> ReqBuilder,
) -> APIResult<T> { ) -> APIResult<T> {
let url = url.into();
APIResult::new( APIResult::new(
custom(&self.ctx.net, self.url(url)) with_exponential_backoff!(
.basic_auth(self.username.as_str(), Some(self.password.as_str())) &self.ctx,
.header("accept", "application/json") custom(&self.ctx.net, self.url(url.clone()))
.header("content-type", "application/json") .basic_auth(self.username.as_str(), Some(self.password.as_str()))
.send() .header("accept", "application/json")
.await, .header("content-type", "application/json")
.send()
.await
),
&self.ctx.prt, &self.ctx.prt,
) )
.await .await
@ -71,49 +72,19 @@ impl<'ctx> DeckClient<'ctx> {
body: impl Into<Bytes>, body: impl Into<Bytes>,
custom: fn(&Net, String) -> ReqBuilder, custom: fn(&Net, String) -> ReqBuilder,
) -> APIResult<T> { ) -> APIResult<T> {
let url = self.url(url.into());
let body = body.into();
APIResult::new( APIResult::new(
custom(&self.ctx.net, self.url(url)) with_exponential_backoff!(
.basic_auth(self.username.as_str(), Some(self.password.as_str())) &self.ctx,
.header("accept", "application/json") custom(&self.ctx.net, url.clone())
.header("content-type", "application/json") .basic_auth(self.username.as_str(), Some(self.password.as_str()))
.body(body) .header("accept", "application/json")
.send() .header("content-type", "application/json")
.await, .body(body.clone())
&self.ctx.prt, .send()
) .await
.await ),
}
async fn request_with_form<T>(
&self,
path: String,
// form_data: HashMap<String, String>,
form: multipart::Form,
) -> APIResult<T>
where
T: DeserializeOwned,
{
// let form: multipart::Form = multipart::Form::new();
// let full_path = self.ctx.fs.base().join(form_data.get("file").expect("file"));
// e!(self.ctx.prt, "Uploading file: {}", full_path.display());
// let form = form.file("file", Path::new(&full_path))
// .await
// .expect("read file");
let request_builder = self
.ctx
.net
.client()
.post(self.url(&path))
.basic_auth(self.username.as_str(), Some(self.password.as_str()))
.header("accept", "application/json")
// .form(&form_data);
.multipart(form);
// let data = request_builder.multipart();
APIResult::new(
match self.ctx.net.send(request_builder).await {
Ok(response) => Ok(response),
Err(err) => Err(err),
},
&self.ctx.prt, &self.ctx.prt,
) )
.await .await
@ -240,16 +211,30 @@ impl<'ctx> DeckClient<'ctx> {
card_id: NextcloudCardId, card_id: NextcloudCardId,
file: &FileHandle, file: &FileHandle,
) -> APIResult<Attachment> { ) -> APIResult<Attachment> {
let form: multipart::Form = multipart::Form::new(); APIResult::new(
let form = form.text("type", "file"); with_exponential_backoff!(&self.ctx, {
let form = form let form: multipart::Form = multipart::Form::new();
.file("file", file.as_pathbuf()) let form = form.text("type", "file");
.await let form = form
.expect("read file"); .file("file", file.as_pathbuf())
self.request_with_form( .await
// f!("apps/deck/cards/{card_id}/attachment"), .expect("read file");
f!("boards/{board_id}/stacks/{stack_id}/cards/{card_id}/attachments"), self.ctx
form, .net
.send(
self.ctx
.net
.client()
.post(self.url(f!(
"boards/{board_id}/stacks/{stack_id}/cards/{card_id}/attachments"
)))
.basic_auth(self.username.as_str(), Some(self.password.as_str()))
.header("accept", "application/json")
.multipart(form),
)
.await
}),
&self.ctx.prt,
) )
.await .await
} }

View file

@ -18,7 +18,6 @@ use crate::{
pub(crate) struct TrelloClient<'ctx> { pub(crate) struct TrelloClient<'ctx> {
ctx: &'ctx FullCtx, ctx: &'ctx FullCtx,
// 300 requests per 10 seconds for each API key and 100 requests per 10 second interval for each token
} }
impl<'ctx> TrelloClient<'ctx> { impl<'ctx> TrelloClient<'ctx> {