1use super::*;
2use crate::errors::ApiCallError::Call;
3use crate::errors::CallError;
4use crate::errors::GetUrlError;
5use crate::errors::NonSuccessStatusCodeError;
6use crate::errors::StdResult;
7use crate::errors::{ApiCallError, ResumableUploadError};
8use crate::media::resumable::{LimitedStream, PendingChunks};
9use crate::media::{AsyncMediaUpload, MediaDownloadResponseStream};
10use crate::utils::vec_helper::SortTupleIteratorBySortKeys;
11pub use client::media;
12pub use client::media::resumable::ResumableBody;
13pub use client::media::resumable::ResumableMediaUpload;
14use client::media::resumable::ResumableState;
15pub use client::media::AsyncMediaUploadStream;
16pub use client::media::MediaDownload;
17pub use client::media::MediaDownloadStream;
18pub use client::media::MediaUpload;
19pub use client::media::MediaUploadProtocol;
20pub use client::media::MediaUploadStream;
21pub use client::OutgoingBodyContent;
22use core::fmt::Debug;
23use futures_util::lock::Mutex;
24use futures_util::{AsyncSeekExt, StreamExt};
25use http_body_util::{BodyExt, Full, StreamBody};
26use hyper::body::Frame;
27use hyper::body::{Bytes, Incoming};
28use hyper::header::CONTENT_LENGTH;
29use hyper::header::CONTENT_RANGE;
30use hyper::header::CONTENT_TYPE;
31use hyper::header::{AUTHORIZATION, RANGE};
32use hyper::Request;
33use hyper::Response;
34use hyper::{Method, StatusCode};
35use hyper_util::client::legacy::connect::Connect;
36use hyper_util::client::legacy::Client;
37use serde::de::DeserializeOwned;
38use serde::Deserialize;
39use std::collections::HashMap;
40use std::io::{SeekFrom, Write};
41use std::pin::Pin;
42use std::str::FromStr;
43use std::task::Context;
44use std::task::Poll;
45use url::Url;
46
47mod client;
48
49type Result<T> = StdResult<T, ApiCallError>;
50
51async fn call_no_parse_response<'a, H: Hub, R2, A: ApiCall<'a, R2, H>>(
52 call: &mut A,
53) -> Result<Response<Incoming>> {
54 let mut url: Url = call.get_url()?; let media_upload = call.take_media_upload();
56 let outgoing_body = call.take_body();
57 let resumable_media = call.take_resumable_media_upload();
58 let incoming_body = call.get_media_download().and_then(|x| x.get_range());
59 let hub = call.get_hub()?;
60 let mut outgoing_body = OutgoingBodyContent::from_body_and_media(outgoing_body, media_upload);
61
62 let is_resuming_upload;
63 if let Some(resumable) = &resumable_media {
64 match resumable.state {
65 ResumableState::Resuming => {
66 if let Some(resume_url) = &resumable.url {
67 url = resume_url.clone();
68 is_resuming_upload = true;
69 outgoing_body = OutgoingBodyContent::Empty; } else {
71 is_resuming_upload = false;
72 }
73 }
74 _ => {
75 is_resuming_upload = false;
76 }
77 }
78 } else {
79 is_resuming_upload = false;
80 }
81
82 let url = url.as_str();
83 println!("url: '{}'", url);
84 let body_len = outgoing_body.get_length();
85 dbg!(&outgoing_body, &body_len, url);
86 let mut req = hyper::Request::builder()
87 .method(A::get_request_method())
88 .uri(url)
89 .header(CONTENT_LENGTH, body_len);
90
91 if let Some(range) = incoming_body {
92 dbg!("Setting range header", &range);
93 req = req.header(RANGE, format!("bytes={}", range));
94 }
95 if is_resuming_upload {
96 let total_range = resumable_media
97 .as_ref()
98 .and_then(|x| x.media_body.as_ref())
99 .and_then(|x| x.length)
100 .map(|x| x.to_string())
101 .unwrap_or("*".to_string());
102 req = req.header(CONTENT_RANGE, format!("bytes */{}", total_range));
103 }
104 if let Some(content_type) = outgoing_body.get_content_type() {
105 req = req.header(CONTENT_TYPE, content_type);
106 }
107 dbg!(&req);
108 let scopes = A::get_scopes();
109 if !scopes.is_empty() {
110 req = req.header(
111 AUTHORIZATION,
112 format!("Bearer {}", hub.get_token(&scopes).await?),
113 );
114 }
115
116 let req = req.body(outgoing_body).map_err(CallError::InvalidRequest)?;
117 let client = hub.get_client();
119 let mut response = client.request(req).await.map_err(CallError::Request)?;
120
121 let status_code = response.status();
123 dbg!(&status_code);
124 let resume_incompleted_upload = is_resuming_upload && status_code == 308;
125 if status_code.is_success() || resume_incompleted_upload {
126 if let Some(mut resumable) = resumable_media {
127 dbg!("Resumable upload", &resumable, &response);
128 if is_resuming_upload {
129 handle_resumable_upload_resume_response(&response, &mut resumable)?;
130 } else {
131 handle_resumable_upload_init_response(&response, &mut resumable)?;
132 }
133
134 while let ResumableState::Sending(_) = &resumable.state {
135 dbg!("Looping through resumable upload");
136 response = resumable_upload_chunk(&mut resumable, hub).await?;
137 }
138 dbg!(&resumable, &response);
139 }
140
141 Ok(response)
142 } else {
145 let body = response.into_body();
146 let body = body.collect().await.map_err(CallError::GetBody)?.to_bytes();
147 dbg!(&body);
148 Err(CallError::NonSuccessStatusCode(
149 NonSuccessStatusCodeError::from((
150 status_code,
151 String::from_utf8_lossy(&body).to_string(),
152 )),
153 ))?
154 }
155}
156
157async fn call<'a, R, H: Hub, R2, A: ApiCall<'a, R2, H>>(call: &mut A) -> Result<R>
158where
159 R: Debug + DeserializeOwned,
160{
161 if call.is_media_download() {
162 return Err(CallError::DownloadSetInNotDownloadCall.into());
163 }
164 let body = call_no_parse_response(call).await?;
165 let body = body
166 .into_body()
167 .collect()
168 .await
169 .map_err(CallError::GetBody)?
170 .to_bytes();
171 dbg!(&body);
172 let response: R = serde_json::from_slice(&body).map_err(CallError::ParseResponse)?;
173 Ok(response)
174}
175async fn call_download<'a, H: Hub, R2, A: ApiCall<'a, R2, H>>(call: &mut A) -> Result<()> {
176 if !call.is_media_download() {
177 return Err(CallError::NoDownloadTarget.into());
178 }
179 let mut download_stream = call_get_download_response_stream(call).await?;
180
181 let Some(mut writer) = call.take_media_download() else {
182 return Err(CallError::NoDownloadTarget.into());
183 };
184 while let Some(frame) = download_stream.stream.next().await {
185 let frame_data = match frame {
186 Err(e) => {
187 return Err(CallError::GetBody(e).into());
188 }
189 Ok(frame_data) => frame_data,
190 };
191 writer
192 .stream
193 .write_all(&frame_data)
194 .map_err(CallError::WriteBodyToStream)?;
195 }
196 Ok(())
197}
198
199async fn call_get_download_response_stream<'a, H: Hub, R2, A: ApiCall<'a, R2, H>>(
200 call: &mut A,
201) -> Result<MediaDownloadResponseStream> {
202 let response = call_no_parse_response(call).await?;
203 let content_headers = response.headers().to_owned();
204 let body = response.into_body();
205 let stream = body.into_data_stream();
206 let download_stream = MediaDownloadResponseStream {
207 stream,
208 headers: content_headers,
209 };
210 Ok(download_stream)
211}
212
213async fn resumable_upload_chunk(
214 resumable: &mut ResumableBody,
215 hub: &impl Hub,
216) -> Result<Response<Incoming>> {
217 println!("Uploading chunk");
218 let single_chunk = resumable.is_single_chunk_upload().unwrap_or(true);
219 let url = resumable.url.as_ref().ok_or(ResumableUploadError::NoUrl)?;
220
221 let media = resumable
222 .media_body
223 .as_mut()
224 .ok_or(ResumableUploadError::NoMediaBody)?;
225 let total_length = media.length;
226 if let ResumableState::Sending(ranges) = &resumable.state {
227 if let Some(range) = ranges.ranges.first() {
228 let range = range.resolve_range(total_length)?;
229 println!("Chunk range {}/{}", range.start, range.end);
230 {
231 let mut stream = media.body.lock().await;
232 stream
233 .seek(SeekFrom::Start(range.start))
234 .await
235 .map_err(ResumableUploadError::SeekPosition)?;
236 }
237 let body_len = range.end - range.start + 1; let mut req_builder = hyper::Request::builder()
239 .method(Method::PUT)
240 .uri(url.as_str())
241 .header(CONTENT_LENGTH, body_len);
242
243 req_builder = req_builder.header(CONTENT_TYPE, &media.mime_type);
244 let chunk_length = if single_chunk {
245 total_length.unwrap()
246 } else {
247 body_len
248 };
249 dbg!(&chunk_length);
250 let stream = LimitedStream::new(media.body.clone(), chunk_length)
251 .await
252 .unwrap();
253 let body = OutgoingBodyContent::AsyncStream(AsyncMediaUpload::new(
254 &media.mime_type,
255 stream,
256 chunk_length,
257 ));
258
259 let req = req_builder.body(body).unwrap();
260 let client = hub.get_client();
261 dbg!("sending request");
262 let response = client.request(req).await.map_err(CallError::Request)?;
263 dbg!(&response);
264 handle_resumable_upload_resume_response(&response, resumable)?;
265 dbg!("done with chunk");
266 return Ok(response);
267 } else {
268 dbg!("missing ranges");
269 }
270 } else {
271 dbg!("wrong state", &resumable.state);
272 }
273
274 todo!()
275}
276
277fn handle_resumable_upload_init_response(
278 response: &Response<Incoming>,
279 resumable: &mut ResumableBody,
280) -> StdResult<(), ResumableUploadError> {
281 let x = response
282 .headers()
283 .get("Location")
284 .ok_or(ResumableUploadError::NoOrInvalidLocationHeader)?
285 .to_str()
286 .map_err(|_| ResumableUploadError::NoOrInvalidLocationHeader)?;
287 let x = Url::from_str(x)?;
288 resumable.url = Some(x.clone());
289 resumable.call_save_url(x);
290 resumable.state = ResumableState::Sending(PendingChunks::full(
291 resumable
292 .media_body
293 .as_ref()
294 .ok_or(ResumableUploadError::NoMediaBody)?
295 .length
296 .ok_or(ResumableUploadError::NoMediaBody)?,
297 ));
298 Ok(())
299}
300
301fn handle_resumable_upload_resume_response(
302 response: &Response<Incoming>,
303 resumable: &mut ResumableBody,
304) -> StdResult<(), ResumableUploadError> {
305 let status = response.status();
306 if status.is_success() {
307 resumable.state = ResumableState::Done;
308 } else {
309 let x = response
310 .headers()
311 .get("Range")
312 .map(|x| x.to_str().unwrap_or_default().to_string());
313 let range = if let Some(x) = x {
314 PendingChunks::from_ranges(x)?
315 } else {
316 PendingChunks::full(
317 resumable
318 .media_body
319 .as_ref()
320 .ok_or(ResumableUploadError::NoMediaBody)?
321 .length
322 .ok_or(ResumableUploadError::NoMediaBody)?,
323 )
324 };
325 resumable.state = ResumableState::Sending(range);
326 }
327 Ok(())
328}
329
330pub trait ApiCall<'a, R, H: Hub>: ApiCallBase<'a, H, R> + Sized {
331 fn call(&mut self) -> impl Future<Output = Result<R>>
332 where
333 R: Debug + DeserializeOwned,
334 {
335 call(self)
336 }
337 fn call_custom<R2>(&mut self) -> impl Future<Output = Result<R2>>
338 where
339 R2: Debug + DeserializeOwned,
340 {
341 call(self)
342 }
343 fn call_download(&mut self) -> impl Future<Output = Result<()>> {
344 call_download(self)
345 }
346 fn get_url(&self) -> Result<Url> {
347 let hub = self.get_hub()?;
348 let base_url = &hub.get_base_url();
349 let url = match self.get_protocol()? {
350 MediaUploadProtocol::None => {
351 let service_path = hub.get_service_path();
352 self.get_normal_url(&format!("{}{}", base_url, service_path))?
353 }
354 MediaUploadProtocol::Simple => self.get_url_media_upload_simple(base_url)?,
355 MediaUploadProtocol::Resumable => self.get_url_media_upload_resumable(base_url)?,
356 };
357 Ok(url)
358 }
359 fn get_protocol(&self) -> Result<MediaUploadProtocol> {
360 Ok(
361 match (self.has_media_upload(), self.has_resumable_media_upload()) {
362 (true, false) => MediaUploadProtocol::Simple,
363 (false, true) => MediaUploadProtocol::Resumable,
364 (false, false) => MediaUploadProtocol::None,
365 (true, true) => return Err(ApiCallError::MultipleMediaUploads),
366 },
367 )
368 }
369 fn get_url_media_upload_simple(&self, base_url: &str) -> StdResult<Url, GetUrlError> {
370 let path = self
371 .get_media_upload_path_simple()
372 .ok_or(GetUrlError::NoMediaPath)?;
373 self.get_url_with_path(base_url, path, Some("multipart"), false)
374 }
375 fn get_url_media_upload_resumable(&self, base_url: &str) -> StdResult<Url, GetUrlError> {
376 let path = self
377 .get_media_upload_path_resumable()
378 .ok_or(GetUrlError::NoMediaPath)?;
379 self.get_url_with_path(base_url, path, Some("resumable"), false)
380 }
381 fn get_normal_url(&self, base_url: &str) -> StdResult<Url, GetUrlError> {
382 let path = self.get_method_path();
383 let is_download = self.is_media_download();
384 self.get_url_with_path(base_url, path, None, is_download)
385 }
386
387 fn get_url_with_path(
388 &self,
389 base_url: &str,
390 path: impl Into<String>,
391 upload_type_param: Option<&'static str>,
392 download: bool,
393 ) -> StdResult<Url, GetUrlError> {
394 let mut path = path.into();
395 let mut query_params = self.get_query_params();
396 if download {
397 query_params.push(("alt", "media".to_string()));
398 }
399 if let Some(upload_type_param) = upload_type_param {
400 query_params.push(("uploadType", upload_type_param.to_string()));
401 }
402 let query_params = query_params;
403 let mut remaining_parameters = vec![];
404 for (name, value) in query_params.into_iter() {
406 if path.contains(&format!("{{{}}}", &name)) {
407 path = path.replace(
408 &format!("{{{}}}", name),
409 &url::form_urlencoded::byte_serialize(value.as_bytes()).collect::<String>(),
410 );
411 } else {
412 remaining_parameters.push((name, value));
413 }
414 }
415
416 let query_param_order = self.get_query_param_order();
417 let remaining_parameters = remaining_parameters.sort_by_other(&query_param_order);
418
419 let path = path.trim_start_matches('/').trim_end_matches('/');
420 let base_url = base_url.trim_end_matches('/');
421 dbg!(&path, &base_url);
422 let url = format!("{}/{}", base_url, path);
423 let url = Url::parse_with_params(&url, remaining_parameters)?;
424
425 Ok(url)
426 }
427
428 fn with_hub(&mut self, hub: &'a H) -> &mut Self {
429 ApiCallBase::set_hub(self, hub);
430 self
431 }
432}
433impl<'a, T, R: DeserializeOwned + Debug, H: Hub> ApiCall<'a, R, H> for T where
434 T: ApiCallBase<'a, H, R>
435{
436}
437pub trait ApiCallBase<'a, HUB, RETURN> {
438 fn get_method_path(&self) -> &str;
439
440 fn get_media_upload_path_simple(&self) -> Option<&str>;
441 fn get_media_upload_path_resumable(&self) -> Option<&str>;
442
443 fn get_query_params(&self) -> Vec<(&str, String)>;
444 fn get_query_param_order(&self) -> Vec<&str>;
445 fn get_scopes() -> Vec<impl Scope>;
446 fn get_hub(&self) -> Result<&impl Hub>;
447 fn set_hub<'b>(&mut self, hub: &'b HUB)
448 where
449 'b: 'a;
450
451 fn has_body(&self) -> bool;
452 fn take_body(&mut self) -> Option<String>;
453 fn has_media_upload(&self) -> bool;
454 fn is_media_download(&self) -> bool;
455 fn take_media_upload(&mut self) -> Option<MediaUpload<dyn MediaUploadStream>>;
456 fn take_media_download(&mut self) -> Option<MediaDownload<dyn MediaDownloadStream>>;
457 fn get_media_download(&mut self) -> Option<&MediaDownload<dyn MediaDownloadStream>>;
458 fn has_resumable_media_upload(&self) -> bool;
459 fn take_resumable_media_upload(&mut self) -> Option<ResumableBody>;
460 fn get_request_method() -> Method;
461}
462pub trait ApiCallBuilder<'a, H: Hub> {
463 fn new(hub: &'a H) -> Self;
464}
465
466pub trait ConnectRequirements: Connect + Clone + Send + Sync + Debug + 'static {}
467impl<T> ConnectRequirements for T where T: Connect + Clone + Send + Sync + Debug + 'static {}
468
469pub trait Hub: HubBase + Debug + Clone {
470 fn call<'a, 'b, T>(
471 &'a self,
472 api_call: impl ApiCall<'b, T, Self> + 'b,
473 ) -> impl Future<Output = Result<T>>
474 where
475 T: Debug + DeserializeOwned,
476 Self: Sized,
477 'a: 'b,
478 {
479 call_with_hub(api_call, self)
480 }
481 fn get_base_url(&self) -> &str {
482 match self.get_region() {
483 None => self.get_global_url(),
484 Some(region) => self.get_url_for_region(region),
485 }
486 }
487 fn get_url_for_region(&self, region: &str) -> &str {
488 let endpoints = Self::get_endpoints();
489 match endpoints.get(region) {
490 None => self.get_global_url(),
491 Some(url) => url,
492 }
493 }
494}
495async fn call_with_hub<'a, T: Debug + DeserializeOwned, H: Hub + 'a>(
496 mut call: impl ApiCall<'a, T, H>,
497 hub: &'a H,
498) -> Result<T> {
499 let x = {
500 call.set_hub(hub);
501 call.call().await?
502 };
503 Ok(x)
504}
505impl<T: HubBase + Debug + Clone> Hub for T {}
506pub trait HubBase {
507 type Connector: ConnectRequirements;
508 type ConnectorAuth: ConnectRequirements;
509 fn new(
510 client: Client<Self::Connector, OutgoingBodyContent>,
511 auth: Authenticator<Self::ConnectorAuth>,
512 ) -> Self
513 where
514 Self: Sized;
515 fn get_client(&self) -> &Client<Self::Connector, OutgoingBodyContent>;
516 fn get_global_url(&self) -> &str;
517 fn get_service_path(&self) -> &str;
518 fn get_endpoints() -> &'static phf::Map<&'static str, &'static str>;
519 fn get_token(&self, scopes: &[impl Scope]) -> impl Future<Output = Result<String>>;
520 fn set_region(&mut self, region: impl Into<String>);
521 fn get_region(&self) -> Option<&String>;
522}
523
524pub trait Scope: AsRef<str> {}
525impl<T: AsRef<str>> Scope for T {}