gapirs_common/api/client/
media.rs1pub mod resumable;
2pub use download::*;
3pub use upload::*;
4pub(crate) mod multipart {
5 use super::{MediaUpload, MediaUploadStream};
6 use serde::{Deserialize, Serialize};
7 #[derive(Debug)]
8 pub struct MultipartBody {
9 pub(crate) boundary: String,
10 pub json_body: String,
11 pub media_body: MediaUpload<dyn MediaUploadStream>,
12 pub(crate) state: MultipartState,
13 }
14 impl MultipartBody {
15 pub fn new(
16 media_body: MediaUpload<dyn MediaUploadStream>,
17 body: impl Into<String>,
18 ) -> Self {
19 Self {
20 boundary: "BOUNDARY".to_string(),
21 json_body: body.into(),
22 media_body,
23 state: MultipartState::NotStarted,
24 }
25 }
26 }
27
28 #[derive(Debug, Clone)]
29 pub(crate) enum MultipartState {
30 NotStarted,
31 Polling,
32 Done,
33 }
34 impl MultipartBody {
35 pub(crate) fn get_body_before_media(&self) -> String {
36 let json_str = self.json_body.to_string();
37 let media = &self.media_body;
38
39 let body_string = format!(
40 "--{}\r\n\
41 Content-Type: application/json; charset=UTF-8\r\n\
42 Content-Length: {}\r\n\
43 \r\n\
44 {}\r\n\
45 \r\n\
46 --{}\r\n\
47 Content-Type: {}\r\n\
48 Content-Length: {}\r\n\
49 \r\n",
50 self.boundary,
51 json_str.len(),
52 json_str,
53 self.boundary,
54 media.mime_type,
55 media.length
56 );
57 body_string
58 }
59 pub(crate) fn get_body_after_media(&self) -> String {
60 format!("\r\n--{}--\r\n", self.boundary,)
61 }
62 }
63}
64mod upload {
65 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, Default)]
66 pub enum MediaUploadProtocol {
67 #[default]
68 None,
69 Simple,
70 Resumable,
71 }
72
73 use crate::media::resumable::LimitedStream;
74 use bytes::{Buf, Bytes};
75 use core::fmt::Debug;
76 use futures_core::Stream;
77 use futures_util::lock::Mutex;
78 use futures_util::{AsyncRead, AsyncSeek};
79 use serde::{Deserialize, Serialize};
80 use std::error::Error;
81 use std::pin::Pin;
82 #[derive(derive_more::Debug)]
83 pub struct MediaUpload<T: MediaUploadStream + ?Sized> {
84 pub(crate) mime_type: String,
85 #[debug(skip)]
86 pub(crate) body: Pin<Box<T>>,
87 pub(crate) length: u64,
88 }
89 impl<T> MediaUpload<T>
90 where
91 T: MediaUploadStream + ?Sized,
92 {
93 pub fn new(mime_type: impl Into<String>, body: Pin<Box<T>>, length: u64) -> Self {
94 Self {
95 mime_type: mime_type.into(),
96 body,
97 length,
98 }
99 }
100 }
101 #[derive(derive_more::Debug)]
102 pub struct AsyncMediaUpload<T: AsyncMediaUploadStream + ?Sized> {
103 pub(crate) mime_type: String,
104 #[debug(skip)]
105 pub(crate) body: LimitedStream<T>,
106 pub(crate) length: u64,
107 }
108 impl<T> AsyncMediaUpload<T>
109 where
110 T: AsyncMediaUploadStream + ?Sized,
111 {
112 pub fn new(mime_type: impl Into<String>, body: LimitedStream<T>, length: u64) -> Self {
113 Self {
114 mime_type: mime_type.into(),
115 body,
116 length,
117 }
118 }
119 }
120 pub trait MediaUploadStream:
121 Stream<Item = Result<Bytes, Box<dyn Error + Send + Sync>>> + Send + Sync + 'static
122 {
123 }
124 impl<T> MediaUploadStream for T where
125 T: Stream<Item = Result<Bytes, Box<dyn Error + Send + Sync>>> + Send + Sync + 'static
126 {
127 }
128
129 pub trait AsyncMediaUploadStream:
130 AsyncRead + AsyncSeek + Debug + Send + Sync + 'static
131 {
132 }
133 impl<T> AsyncMediaUploadStream for T where T: AsyncRead + Debug + AsyncSeek + Send + Sync + 'static {}
134}
135mod download {
136 use core::fmt::Debug;
137 use http_body_util::BodyDataStream;
138 use hyper::body::Incoming;
139 use hyper::HeaderMap;
140 use std::io::Write;
141
142 #[derive(Debug)]
143 pub struct MediaDownload<T: MediaDownloadStream + ?Sized> {
144 pub(crate) stream: Box<T>,
145 }
146
147 impl<T: MediaDownloadStream + ?Sized> MediaDownload<T> {
148 pub(crate) fn get_range(&self) -> Option<String> {
149 None
151 }
152 }
153
154 impl<T: MediaDownloadStream + ?Sized> MediaDownload<T> {
155 pub fn new(stream: Box<T>) -> Self {
156 Self { stream }
157 }
158 }
159
160 pub trait MediaDownloadStream: Write + Debug + Send + Sync {}
161 impl<T> MediaDownloadStream for T where T: Write + Debug + Send + Sync {}
162
163 pub struct MediaDownloadResponseStream {
164 pub stream: BodyDataStream<Incoming>,
165 pub headers: HeaderMap,
166 }
167}