Skip to content

Commit

Permalink
Multipart upload separate module
Browse files Browse the repository at this point in the history
  • Loading branch information
abdolence committed Jan 27, 2024
1 parent 8943cc9 commit e46118b
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 97 deletions.
8 changes: 6 additions & 2 deletions src/api/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize, Serializer};
use serde_with::skip_serializing_none;

use crate::models::*;
use crate::multipart_form::FileMultipartData;
use crate::ratectl::*;
use crate::SlackClientSession;
use crate::{ClientResult, SlackClientHttpConnector};
Expand All @@ -29,11 +30,14 @@ where
let file_mime = mime_guess::MimeGuess::from_path(&filename).first_or_octet_stream();
file_mime.to_string()
});
let file = FileMultipartData {
name: filename.as_str(),
content_type: file_content_type.as_str(),
data: file.as_slice(),
};
self.http_session_api
.http_post_multipart_form(
"files.upload",
filename,
file_content_type,
file,
&vec![
(
Expand Down
31 changes: 6 additions & 25 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::token::*;

use crate::errors::SlackClientError;
use crate::models::*;
use crate::multipart_form::FileMultipartData;
use crate::ratectl::SlackApiMethodRateControlConfig;
use futures_util::future::BoxFuture;
use lazy_static::*;
Expand Down Expand Up @@ -149,9 +150,7 @@ pub trait SlackClientHttpConnector {
fn http_post_uri_multipart_form<'a, 'p, RS, PT, TS>(
&'a self,
full_uri: Url,
file_name: String,
file_content_type: String,
file_content: &'p [u8],
file: FileMultipartData<'p>,
params: &'p PT,
context: SlackClientApiCallContext<'a>,
) -> BoxFuture<'a, ClientResult<RS>>
Expand All @@ -163,9 +162,7 @@ pub trait SlackClientHttpConnector {
fn http_post_multipart_form<'a, 'p, RS, PT, TS>(
&'a self,
method_relative_uri: &str,
file_name: String,
file_content_type: String,
file_content: &'p [u8],
file: FileMultipartData<'p>,
params: &'p PT,
context: SlackClientApiCallContext<'a>,
) -> BoxFuture<'a, ClientResult<RS>>
Expand All @@ -178,14 +175,7 @@ pub trait SlackClientHttpConnector {
&SlackClientHttpApiUri::create_method_uri_path(method_relative_uri),
);

self.http_post_uri_multipart_form(
full_uri,
file_name,
file_content_type,
file_content,
params,
context,
)
self.http_post_uri_multipart_form(full_uri, file, params, context)
}
}

Expand Down Expand Up @@ -420,9 +410,7 @@ where
pub async fn http_post_multipart_form<'p, RS, PT, TS>(
&self,
method_relative_uri: &str,
file_name: String,
file_content_type: String,
file_content: &'p [u8],
file: FileMultipartData<'p>,
params: &'p PT,
rate_control_params: Option<&'a SlackApiMethodRateControlConfig>,
) -> ClientResult<RS>
Expand All @@ -441,14 +429,7 @@ where
self.client
.http_api
.connector
.http_post_multipart_form(
method_relative_uri,
file_name,
file_content_type,
file_content,
params,
context,
)
.http_post_multipart_form(method_relative_uri, file, params, context)
.await
}
}
18 changes: 7 additions & 11 deletions src/hyper_tokio/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ use hyper_util::client::legacy::*;
use hyper_util::rt::TokioExecutor;
use rvstruct::ValueStruct;

use crate::hyper_tokio::multipart_form::{
create_multipart_file_content, generate_multipart_boundary,
};
use crate::multipart_form::FileMultipartData;
use crate::prelude::hyper_ext::HyperExtensions;
use crate::ratectl::SlackApiRateControlConfig;
use std::hash::Hash;
Expand Down Expand Up @@ -434,9 +438,7 @@ impl<H: 'static + Send + Sync + Clone + connect::Connect> SlackClientHttpConnect
fn http_post_uri_multipart_form<'a, 'p, RS, PT, TS>(
&'a self,
full_uri: Url,
file_name: String,
file_content_type: String,
file_content: &'p [u8],
file: FileMultipartData<'p>,
params: &'p PT,
context: SlackClientApiCallContext<'a>,
) -> BoxFuture<'a, ClientResult<RS>>
Expand All @@ -446,14 +448,8 @@ impl<H: 'static + Send + Sync + Clone + connect::Connect> SlackClientHttpConnect
TS: AsRef<str> + 'p + Send,
{
let context_token = context.token;
let boundary = HyperExtensions::generate_multipart_boundary();
match HyperExtensions::create_multipart_file_content(
params,
boundary.as_str(),
file_name.as_str(),
file_content_type.as_str(),
file_content,
) {
let boundary = generate_multipart_boundary();
match create_multipart_file_content(params, boundary.as_str(), file) {
Ok(file_bytes) => self
.send_rate_controlled_request(
move || {
Expand Down
59 changes: 0 additions & 59 deletions src/hyper_tokio/hyper_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,63 +125,4 @@ impl HyperExtensions {
_ => Err(Box::new(SlackEventAbsentSignatureError::new())),
}
}

pub fn generate_multipart_boundary() -> String {
format!(
"----WebKitFormBoundarySlackMorphismRust{}",
chrono::Utc::now().timestamp()
)
}

pub fn create_multipart_file_content<'p, PT, TS>(
fields: &'p PT,
multipart_boundary: &str,
file_name: &str,
file_content_type: &str,
file_content: &[u8],
) -> AnyStdResult<Bytes>
where
PT: std::iter::IntoIterator<Item = (&'p str, Option<TS>)> + Clone,
TS: AsRef<str> + 'p + Send,
{
let mut output = BytesMut::with_capacity(file_content.len() + 512);
output.write_str("\r\n")?;
output.write_str("\r\n")?;
output.write_str("--")?;
output.write_str(multipart_boundary)?;
output.write_str("\r\n")?;
output.write_str(&format!(
"Content-Disposition: form-data; name=\"file\"; filename=\"{}\"",
file_name
))?;
output.write_str("\r\n")?;
output.write_str(&format!("Content-Type: {}", file_content_type))?;
output.write_str("\r\n")?;
output.write_str(&format!("Content-Length: {}", file_content.len()))?;
output.write_str("\r\n")?;
output.write_str("\r\n")?;
output.put_slice(file_content);

for (k, mv) in fields.clone().into_iter() {
if let Some(v) = mv {
let vs = v.as_ref();
output.write_str("\r\n")?;
output.write_str("--")?;
output.write_str(multipart_boundary)?;
output.write_str("\r\n")?;
output.write_str(&format!("Content-Disposition: form-data; name=\"{}\"", k))?;
output.write_str("\r\n")?;
output.write_str(&format!("Content-Length: {}", vs.len()))?;
output.write_str("\r\n")?;
output.write_str("\r\n")?;
output.write_str(vs)?;
}
}

output.write_str("\r\n")?;
output.write_str("--")?;
output.write_str(multipart_boundary)?;

Ok(output.freeze())
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ mod scroller;
pub mod signature_verifier;
pub mod socket_mode;

mod multipart_form;
mod token;

#[cfg(feature = "hyper")]
Expand Down
66 changes: 66 additions & 0 deletions src/multipart_form.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use crate::AnyStdResult;
use bytes::{BufMut, Bytes, BytesMut};
use std::fmt::Write;

pub fn generate_multipart_boundary() -> String {
format!(
"----WebKitFormBoundarySlackMorphismRust{}",
chrono::Utc::now().timestamp()
)
}

pub struct FileMultipartData<'a> {
pub name: &'a str,
pub content_type: &'a str,
pub data: &'a [u8],
}

pub fn create_multipart_file_content<'p, PT, TS>(
fields: &'p PT,
multipart_boundary: &str,
file: FileMultipartData<'p>,
) -> AnyStdResult<Bytes>
where
PT: std::iter::IntoIterator<Item = (&'p str, Option<TS>)> + Clone,
TS: AsRef<str> + 'p + Send,
{
let mut output = BytesMut::with_capacity(file.data.len() + 512);
output.write_str("\r\n")?;
output.write_str("\r\n")?;
output.write_str("--")?;
output.write_str(multipart_boundary)?;
output.write_str("\r\n")?;
output.write_str(&format!(
"Content-Disposition: form-data; name=\"file\"; filename=\"{}\"",
file.name
))?;
output.write_str("\r\n")?;
output.write_str(&format!("Content-Type: {}", file.content_type))?;
output.write_str("\r\n")?;
output.write_str(&format!("Content-Length: {}", file.data.len()))?;
output.write_str("\r\n")?;
output.write_str("\r\n")?;
output.put_slice(file.data);

for (k, mv) in fields.clone().into_iter() {
if let Some(v) = mv {
let vs = v.as_ref();
output.write_str("\r\n")?;
output.write_str("--")?;
output.write_str(multipart_boundary)?;
output.write_str("\r\n")?;
output.write_str(&format!("Content-Disposition: form-data; name=\"{}\"", k))?;
output.write_str("\r\n")?;
output.write_str(&format!("Content-Length: {}", vs.len()))?;
output.write_str("\r\n")?;
output.write_str("\r\n")?;
output.write_str(vs)?;
}
}

output.write_str("\r\n")?;
output.write_str("--")?;
output.write_str(multipart_boundary)?;

Ok(output.freeze())
}

0 comments on commit e46118b

Please sign in to comment.