pub mod resumable;
pub use download::*;
pub use upload::*;
pub(crate) mod multipart {
use super::{MediaUpload, MediaUploadStream};
use serde::{Deserialize, Serialize};
#[derive(Debug)]
pub struct MultipartBody {
pub(crate) boundary: String,
pub json_body: String,
pub media_body: MediaUpload<dyn MediaUploadStream>,
pub(crate) state: MultipartState,
}
impl MultipartBody {
pub fn new(
media_body: MediaUpload<dyn MediaUploadStream>,
body: impl Into<String>,
) -> Self {
Self {
boundary: "BOUNDARY".to_string(),
json_body: body.into(),
media_body,
state: MultipartState::NotStarted,
}
}
}
#[derive(Debug, Clone)]
pub(crate) enum MultipartState {
NotStarted,
Polling,
Done,
}
impl MultipartBody {
pub(crate) fn get_body_before_media(&self) -> String {
let json_str = self.json_body.to_string();
let media = &self.media_body;
let body_string = format!(
"--{}\r\n\
Content-Type: application/json; charset=UTF-8\r\n\
Content-Length: {}\r\n\
\r\n\
{}\r\n\
\r\n\
--{}\r\n\
Content-Type: {}\r\n\
Content-Length: {}\r\n\
\r\n",
self.boundary,
json_str.len(),
json_str,
self.boundary,
media.mime_type,
media.length
);
body_string
}
pub(crate) fn get_body_after_media(&self) -> String {
format!("\r\n--{}--\r\n", self.boundary,)
}
}
}
mod upload {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, Default)]
pub enum MediaUploadProtocol {
#[default]
None,
Simple,
Resumable,
}
use crate::media::resumable::LimitedStream;
use bytes::{Buf, Bytes};
use core::fmt::Debug;
use futures_core::Stream;
use futures_util::lock::Mutex;
use futures_util::{AsyncRead, AsyncSeek};
use serde::{Deserialize, Serialize};
use std::error::Error;
use std::pin::Pin;
#[derive(derive_more::Debug)]
pub struct MediaUpload<T: MediaUploadStream + ?Sized> {
pub(crate) mime_type: String,
#[debug(skip)]
pub(crate) body: Pin<Box<T>>,
pub(crate) length: u64,
}
impl<T> MediaUpload<T>
where
T: MediaUploadStream + ?Sized,
{
pub fn new(mime_type: impl Into<String>, body: Pin<Box<T>>, length: u64) -> Self {
Self {
mime_type: mime_type.into(),
body,
length,
}
}
}
#[derive(derive_more::Debug)]
pub struct AsyncMediaUpload<T: AsyncMediaUploadStream + ?Sized> {
pub(crate) mime_type: String,
#[debug(skip)]
pub(crate) body: LimitedStream<T>,
pub(crate) length: u64,
}
impl<T> AsyncMediaUpload<T>
where
T: AsyncMediaUploadStream + ?Sized,
{
pub fn new(mime_type: impl Into<String>, body: LimitedStream<T>, length: u64) -> Self {
Self {
mime_type: mime_type.into(),
body,
length,
}
}
}
pub trait MediaUploadStream:
Stream<Item = Result<Bytes, Box<dyn Error + Send + Sync>>> + Send + Sync + 'static
{
}
impl<T> MediaUploadStream for T where
T: Stream<Item = Result<Bytes, Box<dyn Error + Send + Sync>>> + Send + Sync + 'static
{
}
pub trait AsyncMediaUploadStream:
AsyncRead + AsyncSeek + Debug + Send + Sync + 'static
{
}
impl<T> AsyncMediaUploadStream for T where T: AsyncRead + Debug + AsyncSeek + Send + Sync + 'static {}
}
mod download {
use core::fmt::Debug;
use http_body_util::BodyDataStream;
use hyper::body::Incoming;
use hyper::HeaderMap;
use std::io::Write;
#[derive(Debug)]
pub struct MediaDownload<T: MediaDownloadStream + ?Sized> {
pub(crate) stream: Box<T>,
}
impl<T: MediaDownloadStream + ?Sized> MediaDownload<T> {
pub(crate) fn get_range(&self) -> Option<String> {
None
}
}
impl<T: MediaDownloadStream + ?Sized> MediaDownload<T> {
pub fn new(stream: Box<T>) -> Self {
Self { stream }
}
}
pub trait MediaDownloadStream: Write + Debug + Send + Sync {}
impl<T> MediaDownloadStream for T where T: Write + Debug + Send + Sync {}
pub struct MediaDownloadResponseStream {
pub stream: BodyDataStream<Incoming>,
pub headers: HeaderMap,
}
}