Skip to content

Commit fcfd9f4

Browse files
committed
Add better multipart file uploading
1 parent 0856f3f commit fcfd9f4

10 files changed

Lines changed: 108 additions & 101 deletions

File tree

generate.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ find src -type f -exec sed -i '/^\s*\/\/\/\s*$/d' {} \;
3535
printf "\n[dev-dependencies]\ntokio = { version = '1', features = ['macros', 'rt-multi-thread'] }" >> Cargo.toml
3636

3737
find src/ -type f -name "*.rs" -exec sed -i 's/models::models/models/g' {} +
38+
find src/ -type f -name "*.rs" -exec sed -i -E "s/(::)?std::path::PathBuf/crate::patches::better_file_upload::File<'_>/g" {} +
39+
40+
rm -r src/patches
41+
cp -r patches src/patches
42+
printf "\npub mod patches;" >> src/lib.rs
3843

3944
cargo fmt
4045
cargo build

patches/better_file_upload.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#[derive(Debug)]
2+
#[non_exhaustive]
3+
pub enum File<'a> {
4+
Path(::std::path::PathBuf),
5+
Buf{filename: ::std::borrow::Cow<'static, str>, file: reqwest::Body, length: Option<u64>, mime_type: ::std::borrow::Cow<'a, str>}
6+
}
7+
8+
impl File<'_> {
9+
pub(crate) async fn get_multipart<T>(self) -> Result<::reqwest::multipart::Part, crate::apis::Error<T>> {
10+
match self {
11+
//The generator likes to generate this in 7.20.0. Why? Let's not?
12+
// let file = TokioFile::open(&p_form_file).await?;
13+
// let stream = FramedRead::new(file, BytesCodec::new());
14+
// let file_name = p_form_file
15+
// .file_name()
16+
// .map(|n| n.to_string_lossy().to_string())
17+
// .unwrap_or_default();
18+
// let file_part =
19+
// reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
20+
File::Path(path) => Ok(reqwest::multipart::Part::file(path).await?),
21+
File::Buf{filename, file, length, mime_type} => {
22+
let part = if let Some(length) = length {
23+
reqwest::multipart::Part::stream_with_length(file, length)
24+
} else {
25+
reqwest::multipart::Part::stream(file)
26+
}
27+
.file_name(filename)
28+
.mime_str(&*mime_type)?;
29+
Ok(part)
30+
}
31+
}
32+
}
33+
}

patches/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod better_file_upload;

src/apis/files_api.rs

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,7 +1083,7 @@ pub async fn update_asset_review_notes(
10831083
/// Upload a gallery image
10841084
pub async fn upload_gallery_image(
10851085
configuration: &configuration::Configuration,
1086-
file: std::path::PathBuf,
1086+
file: crate::patches::better_file_upload::File<'_>,
10871087
) -> Result<models::File, Error<UploadGalleryImageError>> {
10881088
// add a prefix to parameters to efficiently prevent name collisions
10891089
let p_form_file = file;
@@ -1097,15 +1097,7 @@ pub async fn upload_gallery_image(
10971097
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
10981098
}
10991099
let mut multipart_form = reqwest::multipart::Form::new();
1100-
let file = TokioFile::open(&p_form_file).await?;
1101-
let stream = FramedRead::new(file, BytesCodec::new());
1102-
let file_name = p_form_file
1103-
.file_name()
1104-
.map(|n| n.to_string_lossy().to_string())
1105-
.unwrap_or_default();
1106-
let file_part =
1107-
reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
1108-
multipart_form = multipart_form.part("file", file_part);
1100+
multipart_form = multipart_form.part("file", p_form_file.get_multipart().await?);
11091101
req_builder = req_builder.multipart(multipart_form);
11101102

11111103
let req = req_builder.build()?;
@@ -1140,7 +1132,7 @@ pub async fn upload_gallery_image(
11401132
/// Upload an icon
11411133
pub async fn upload_icon(
11421134
configuration: &configuration::Configuration,
1143-
file: std::path::PathBuf,
1135+
file: crate::patches::better_file_upload::File<'_>,
11441136
) -> Result<models::File, Error<UploadIconError>> {
11451137
// add a prefix to parameters to efficiently prevent name collisions
11461138
let p_form_file = file;
@@ -1154,15 +1146,7 @@ pub async fn upload_icon(
11541146
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
11551147
}
11561148
let mut multipart_form = reqwest::multipart::Form::new();
1157-
let file = TokioFile::open(&p_form_file).await?;
1158-
let stream = FramedRead::new(file, BytesCodec::new());
1159-
let file_name = p_form_file
1160-
.file_name()
1161-
.map(|n| n.to_string_lossy().to_string())
1162-
.unwrap_or_default();
1163-
let file_part =
1164-
reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
1165-
multipart_form = multipart_form.part("file", file_part);
1149+
multipart_form = multipart_form.part("file", p_form_file.get_multipart().await?);
11661150
req_builder = req_builder.multipart(multipart_form);
11671151

11681152
let req = req_builder.build()?;
@@ -1197,7 +1181,7 @@ pub async fn upload_icon(
11971181
/// Upload an image, which can be an icon, gallery image, sticker or emoji
11981182
pub async fn upload_image(
11991183
configuration: &configuration::Configuration,
1200-
file: std::path::PathBuf,
1184+
file: crate::patches::better_file_upload::File<'_>,
12011185
tag: models::ImagePurpose,
12021186
animation_style: Option<models::ImageAnimationStyle>,
12031187
frames: Option<i32>,
@@ -1227,15 +1211,7 @@ pub async fn upload_image(
12271211
multipart_form =
12281212
multipart_form.text("animationStyle", serde_json::to_string(&param_value)?);
12291213
}
1230-
let file = TokioFile::open(&p_form_file).await?;
1231-
let stream = FramedRead::new(file, BytesCodec::new());
1232-
let file_name = p_form_file
1233-
.file_name()
1234-
.map(|n| n.to_string_lossy().to_string())
1235-
.unwrap_or_default();
1236-
let file_part =
1237-
reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
1238-
multipart_form = multipart_form.part("file", file_part);
1214+
multipart_form = multipart_form.part("file", p_form_file.get_multipart().await?);
12391215
if let Some(param_value) = p_form_frames {
12401216
multipart_form = multipart_form.text("frames", param_value.to_string());
12411217
}

src/apis/invite_api.rs

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ pub async fn invite_user_with_photo(
326326
configuration: &configuration::Configuration,
327327
user_id: &str,
328328
data: models::InviteRequest,
329-
image: std::path::PathBuf,
329+
image: crate::patches::better_file_upload::File<'_>,
330330
) -> Result<models::SentNotification, Error<InviteUserWithPhotoError>> {
331331
// add a prefix to parameters to efficiently prevent name collisions
332332
let p_path_user_id = user_id;
@@ -355,15 +355,7 @@ pub async fn invite_user_with_photo(
355355
};
356356
}
357357
serialize!(multipart_form, data, p_form_data);
358-
let file = TokioFile::open(&p_form_image).await?;
359-
let stream = FramedRead::new(file, BytesCodec::new());
360-
let file_name = p_form_image
361-
.file_name()
362-
.map(|n| n.to_string_lossy().to_string())
363-
.unwrap_or_default();
364-
let file_part =
365-
reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
366-
multipart_form = multipart_form.part("image", file_part);
358+
multipart_form = multipart_form.part("image", p_form_image.get_multipart().await?);
367359
req_builder = req_builder.multipart(multipart_form);
368360

369361
let req = req_builder.build()?;
@@ -453,7 +445,7 @@ pub async fn request_invite_with_photo(
453445
configuration: &configuration::Configuration,
454446
user_id: &str,
455447
data: models::RequestInviteRequest,
456-
image: std::path::PathBuf,
448+
image: crate::patches::better_file_upload::File<'_>,
457449
) -> Result<models::Notification, Error<RequestInviteWithPhotoError>> {
458450
// add a prefix to parameters to efficiently prevent name collisions
459451
let p_path_user_id = user_id;
@@ -482,15 +474,7 @@ pub async fn request_invite_with_photo(
482474
};
483475
}
484476
serialize!(multipart_form, data, p_form_data);
485-
let file = TokioFile::open(&p_form_image).await?;
486-
let stream = FramedRead::new(file, BytesCodec::new());
487-
let file_name = p_form_image
488-
.file_name()
489-
.map(|n| n.to_string_lossy().to_string())
490-
.unwrap_or_default();
491-
let file_part =
492-
reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
493-
multipart_form = multipart_form.part("image", file_part);
477+
multipart_form = multipart_form.part("image", p_form_image.get_multipart().await?);
494478
req_builder = req_builder.multipart(multipart_form);
495479

496480
let req = req_builder.build()?;
@@ -636,7 +620,7 @@ pub async fn respond_invite_with_photo(
636620
configuration: &configuration::Configuration,
637621
notification_id: &str,
638622
data: models::InviteResponse,
639-
image: std::path::PathBuf,
623+
image: crate::patches::better_file_upload::File<'_>,
640624
) -> Result<models::Notification, Error<RespondInviteWithPhotoError>> {
641625
// add a prefix to parameters to efficiently prevent name collisions
642626
let p_path_notification_id = notification_id;
@@ -665,15 +649,7 @@ pub async fn respond_invite_with_photo(
665649
};
666650
}
667651
serialize!(multipart_form, data, p_form_data);
668-
let file = TokioFile::open(&p_form_image).await?;
669-
let stream = FramedRead::new(file, BytesCodec::new());
670-
let file_name = p_form_image
671-
.file_name()
672-
.map(|n| n.to_string_lossy().to_string())
673-
.unwrap_or_default();
674-
let file_part =
675-
reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
676-
multipart_form = multipart_form.part("image", file_part);
652+
multipart_form = multipart_form.part("image", p_form_image.get_multipart().await?);
677653
req_builder = req_builder.multipart(multipart_form);
678654

679655
let req = req_builder.build()?;

src/apis/prints_api.rs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ pub async fn delete_print(
9797
pub async fn edit_print(
9898
configuration: &configuration::Configuration,
9999
print_id: &str,
100-
image: std::path::PathBuf,
100+
image: crate::patches::better_file_upload::File<'_>,
101101
note: Option<&str>,
102102
) -> Result<models::Print, Error<EditPrintError>> {
103103
// add a prefix to parameters to efficiently prevent name collisions
@@ -118,15 +118,7 @@ pub async fn edit_print(
118118
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
119119
}
120120
let mut multipart_form = reqwest::multipart::Form::new();
121-
let file = TokioFile::open(&p_form_image).await?;
122-
let stream = FramedRead::new(file, BytesCodec::new());
123-
let file_name = p_form_image
124-
.file_name()
125-
.map(|n| n.to_string_lossy().to_string())
126-
.unwrap_or_default();
127-
let file_part =
128-
reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
129-
multipart_form = multipart_form.part("image", file_part);
121+
multipart_form = multipart_form.part("image", p_form_image.get_multipart().await?);
130122
if let Some(param_value) = p_form_note {
131123
multipart_form = multipart_form.text("note", param_value.to_string());
132124
}
@@ -260,7 +252,7 @@ pub async fn get_user_prints(
260252
/// Uploads and creates a print.
261253
pub async fn upload_print(
262254
configuration: &configuration::Configuration,
263-
image: std::path::PathBuf,
255+
image: crate::patches::better_file_upload::File<'_>,
264256
timestamp: String,
265257
note: Option<&str>,
266258
world_id: Option<&str>,
@@ -282,15 +274,7 @@ pub async fn upload_print(
282274
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
283275
}
284276
let mut multipart_form = reqwest::multipart::Form::new();
285-
let file = TokioFile::open(&p_form_image).await?;
286-
let stream = FramedRead::new(file, BytesCodec::new());
287-
let file_name = p_form_image
288-
.file_name()
289-
.map(|n| n.to_string_lossy().to_string())
290-
.unwrap_or_default();
291-
let file_part =
292-
reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
293-
multipart_form = multipart_form.part("image", file_part);
277+
multipart_form = multipart_form.part("image", p_form_image.get_multipart().await?);
294278
if let Some(param_value) = p_form_note {
295279
multipart_form = multipart_form.text("note", param_value.to_string());
296280
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ extern crate url;
1010

1111
pub mod apis;
1212
pub mod models;
13+
14+
pub mod patches;

src/patches/better_file_upload.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#[derive(Debug)]
2+
#[non_exhaustive]
3+
pub enum File<'a> {
4+
Path(::std::path::PathBuf),
5+
Buf {
6+
filename: ::std::borrow::Cow<'static, str>,
7+
file: reqwest::Body,
8+
length: Option<u64>,
9+
mime_type: ::std::borrow::Cow<'a, str>,
10+
},
11+
}
12+
13+
impl File<'_> {
14+
pub(crate) async fn get_multipart<T>(
15+
self,
16+
) -> Result<::reqwest::multipart::Part, crate::apis::Error<T>> {
17+
match self {
18+
//The generator likes to generate this in 7.20.0. Why? Let's not?
19+
// let file = TokioFile::open(&p_form_file).await?;
20+
// let stream = FramedRead::new(file, BytesCodec::new());
21+
// let file_name = p_form_file
22+
// .file_name()
23+
// .map(|n| n.to_string_lossy().to_string())
24+
// .unwrap_or_default();
25+
// let file_part =
26+
// reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
27+
File::Path(path) => Ok(reqwest::multipart::Part::file(path).await?),
28+
File::Buf {
29+
filename,
30+
file,
31+
length,
32+
mime_type,
33+
} => {
34+
let part = if let Some(length) = length {
35+
reqwest::multipart::Part::stream_with_length(file, length)
36+
} else {
37+
reqwest::multipart::Part::stream(file)
38+
}
39+
.file_name(filename)
40+
.mime_str(&*mime_type)?;
41+
Ok(part)
42+
}
43+
}
44+
}
45+
}

src/patches/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod better_file_upload;

templates/reqwest/api.mustache

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -444,38 +444,22 @@ pub {{#supportAsync}}async {{/supportAsync}}fn {{{operationId}}}(configuration:
444444
if let Some(ref param_value) = {{{vendorExtensions.x-rust-param-identifier}}} {
445445
{{#isArray}}
446446
for value in param_value {
447-
let file = TokioFile::open(value).await?;
448-
let stream = FramedRead::new(file, BytesCodec::new());
449-
let file_name = value.file_name().map(|n| n.to_string_lossy().to_string()).unwrap_or_default();
450-
let file_part = reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
451-
multipart_form = multipart_form.part("{{{baseName}}}", file_part);
447+
multipart_form = multipart_form.part("{{{baseName}}}", value.get_multipart().await?);
452448
}
453449
{{/isArray}}
454450
{{^isArray}}
455-
let file = TokioFile::open(param_value).await?;
456-
let stream = FramedRead::new(file, BytesCodec::new());
457-
let file_name = param_value.file_name().map(|n| n.to_string_lossy().to_string()).unwrap_or_default();
458-
let file_part = reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
459-
multipart_form = multipart_form.part("{{{baseName}}}", file_part);
451+
multipart_form = multipart_form.part("{{{baseName}}}", param_value.get_multipart().await?);
460452
{{/isArray}}
461453
}
462454
{{/required}}
463455
{{#required}}
464456
{{#isArray}}
465-
for value in &{{{vendorExtensions.x-rust-param-identifier}}} {
466-
let file = TokioFile::open(value).await?;
467-
let stream = FramedRead::new(file, BytesCodec::new());
468-
let file_name = value.file_name().map(|n| n.to_string_lossy().to_string()).unwrap_or_default();
469-
let file_part = reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
470-
multipart_form = multipart_form.part("{{{baseName}}}", file_part);
457+
for value in {{{vendorExtensions.x-rust-param-identifier}}} {
458+
multipart_form = multipart_form.part("{{{baseName}}}", value.get_multipart().await?);
471459
}
472460
{{/isArray}}
473461
{{^isArray}}
474-
let file = TokioFile::open(&{{{vendorExtensions.x-rust-param-identifier}}}).await?;
475-
let stream = FramedRead::new(file, BytesCodec::new());
476-
let file_name = {{{vendorExtensions.x-rust-param-identifier}}}.file_name().map(|n| n.to_string_lossy().to_string()).unwrap_or_default();
477-
let file_part = reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
478-
multipart_form = multipart_form.part("{{{baseName}}}", file_part);
462+
multipart_form = multipart_form.part("{{{baseName}}}", {{{vendorExtensions.x-rust-param-identifier}}}.get_multipart().await?);
479463
{{/isArray}}
480464
{{/required}}
481465
{{/supportAsync}}

0 commit comments

Comments
 (0)