feat(nextcloud): support exponential backoff with jitter
This commit is contained in:
parent
4cdfdaec6f
commit
5d62b7edd0
2 changed files with 51 additions and 67 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
Loading…
Reference in a new issue