Private
Public Access
1
0

Implements attachment uploading

This commit is contained in:
2025-06-12 17:58:03 -07:00
parent 4ddc0dca39
commit 2f4e9b7c07
14 changed files with 268 additions and 8 deletions

View File

@@ -13,6 +13,7 @@ use async_trait::async_trait;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use tokio::net::TcpStream;
use tokio_util::io::ReaderStream;
use futures_util::stream::{BoxStream, Stream};
use futures_util::task::Context;
@@ -289,6 +290,40 @@ impl<K: AuthenticationStore + Send + Sync> APIInterface for HTTPAPIClient<K> {
.map(ResponseStream::from)
}
async fn upload_attachment<R>(
&mut self,
data: tokio::io::BufReader<R>,
filename: &str,
) -> Result<String, Self::Error>
where
R: tokio::io::AsyncRead + Unpin + Send + Sync + 'static,
{
#[derive(Deserialize, Debug)]
struct UploadAttachmentResponse {
#[serde(rename = "fileTransferGUID")]
guid: String,
}
let endpoint = format!("uploadAttachment?filename={}", filename);
let mut data_opt = Some(data);
let response: UploadAttachmentResponse = self
.deserialized_response_with_body_retry(
&endpoint,
Method::POST,
move || {
let stream = ReaderStream::new(
data_opt.take().expect("Stream already consumed during retry"),
);
Body::wrap_stream(stream)
},
false, // don't retry auth for streaming body
)
.await?;
Ok(response.guid)
}
async fn open_event_socket(
&mut self,
update_seq: Option<u64>,
@@ -406,7 +441,7 @@ impl<K: AuthenticationStore + Send + Sync> HTTPAPIClient<K> {
&mut self,
endpoint: &str,
method: Method,
body_fn: impl Fn() -> Body,
body_fn: impl FnMut() -> Body,
) -> Result<T, Error>
where
T: DeserializeOwned,
@@ -419,7 +454,7 @@ impl<K: AuthenticationStore + Send + Sync> HTTPAPIClient<K> {
&mut self,
endpoint: &str,
method: Method,
body_fn: impl Fn() -> Body,
body_fn: impl FnMut() -> Body,
retry_auth: bool,
) -> Result<T, Error>
where
@@ -451,7 +486,7 @@ impl<K: AuthenticationStore + Send + Sync> HTTPAPIClient<K> {
&mut self,
endpoint: &str,
method: Method,
body_fn: impl Fn() -> Body,
mut body_fn: impl FnMut() -> Body,
retry_auth: bool,
) -> Result<hyper::Response<Body>, Error> {
use hyper::StatusCode;
@@ -459,7 +494,7 @@ impl<K: AuthenticationStore + Send + Sync> HTTPAPIClient<K> {
let uri = self.uri_for_endpoint(endpoint, None);
log::debug!("Requesting {:?} {:?}", method, uri);
let build_request = move |auth: &Option<String>| {
let mut build_request = |auth: &Option<String>| {
let body = body_fn();
Request::builder()
.method(&method)

View File

@@ -51,6 +51,15 @@ pub trait APIInterface {
preview: bool,
) -> Result<Self::ResponseStream, Self::Error>;
// (POST) /uploadAttachment
async fn upload_attachment<R>(
&mut self,
data: tokio::io::BufReader<R>,
filename: &str,
) -> Result<String, Self::Error>
where
R: tokio::io::AsyncRead + Unpin + Send + Sync + 'static;
// (POST) /authenticate
async fn authenticate(&mut self, credentials: Credentials) -> Result<JwtToken, Self::Error>;

View File

@@ -127,4 +127,15 @@ impl APIInterface for TestClient {
) -> Result<Self::ResponseStream, Self::Error> {
Ok(futures_util::stream::iter(vec![Ok(Bytes::from_static(b"test"))]).boxed())
}
async fn upload_attachment<R>(
&mut self,
data: tokio::io::BufReader<R>,
filename: &str,
) -> Result<String, Self::Error>
where
R: tokio::io::AsyncRead + Unpin + Send + Sync + 'static,
{
Ok(String::from("test"))
}
}