use std::path::{Path, PathBuf};
use crate::pager::{BackwardPager, BoxPager, PagerStream};
use crate::Error;
#[cfg(feature = "12-48-0")]
use futures::stream::TryStreamExt;
use mime::Mime;
use misskey_api::model::drive::{DriveFile, DriveFolder};
#[cfg(feature = "12-48-0")]
use misskey_api::streaming::channel;
use misskey_api::{endpoint, EntityRef};
#[cfg(feature = "12-48-0")]
use misskey_core::streaming::StreamingClient;
use misskey_core::{Client, UploadFileClient};
#[cfg(feature = "12-48-0")]
use ulid_crate::Ulid;
use url::Url;
pub struct DriveFileUrlBuilder<C> {
client: C,
#[cfg(feature = "12-48-0")]
marker: String,
request: endpoint::drive::files::upload_from_url::Request,
}
impl<C> DriveFileUrlBuilder<C> {
pub fn with_url(client: C, url: Url) -> Self {
#[cfg(feature = "12-48-0")]
let marker = Ulid::new().to_string();
let request = endpoint::drive::files::upload_from_url::Request {
url,
folder_id: None,
is_sensitive: Some(false),
force: Some(false),
#[cfg(feature = "12-48-0")]
comment: None,
#[cfg(feature = "12-48-0")]
marker: Some(marker.clone()),
};
DriveFileUrlBuilder {
client,
request,
#[cfg(feature = "12-48-0")]
marker,
}
}
pub fn as_request(&self) -> &endpoint::drive::files::upload_from_url::Request {
&self.request
}
pub fn folder(&mut self, folder: impl EntityRef<DriveFolder>) -> &mut Self {
self.request.folder_id.replace(folder.entity_ref());
self
}
#[cfg(feature = "12-48-0")]
#[cfg_attr(docsrs, doc(cfg(feature = "12-48-0")))]
pub fn comment(&mut self, comment: impl Into<String>) -> &mut Self {
self.request.comment.replace(comment.into());
self
}
pub fn sensitive(&mut self, sensitive: bool) -> &mut Self {
self.request.is_sensitive = Some(sensitive);
self
}
pub fn use_existing_if_uploaded(&mut self, use_existing_if_uploaded: bool) -> &mut Self {
self.request.force = Some(!use_existing_if_uploaded);
self
}
}
impl<C: Client> DriveFileUrlBuilder<C> {
#[cfg(feature = "12-48-0")]
#[cfg_attr(docsrs, doc(cfg(feature = "12-48-0")))]
pub async fn upload(&self) -> Result<(), Error<C::Error>> {
self.client
.request(&self.request)
.await
.map_err(Error::Client)?
.into_result()?;
Ok(())
}
#[cfg(any(docsrs, not(feature = "12-48-0")))]
#[cfg_attr(docsrs, doc(cfg(not(feature = "12-48-0"))))]
pub async fn upload_(&self) -> Result<DriveFile, Error<C::Error>> {
let file = self
.client
.request(&self.request)
.await
.map_err(Error::Client)?
.into_result()?;
Ok(file)
}
}
#[cfg(feature = "12-48-0")]
#[cfg_attr(docsrs, doc(cfg(feature = "12-48-0")))]
impl<C: Client> DriveFileUrlBuilder<C>
where
C: StreamingClient<Error = <C as Client>::Error>,
{
pub async fn upload_and_wait(&self) -> Result<DriveFile, Error<<C as Client>::Error>> {
let expected_marker = self.marker.clone();
self.client
.request(&self.request)
.await
.map_err(Error::Client)?
.into_result()?;
use channel::main::{self, MainStreamEvent};
let stream = self
.client
.channel(main::Request::default())
.await
.map_err(Error::Client)?
.map_err(Error::Client)
.try_filter_map(|event| async {
match event {
MainStreamEvent::UrlUploadFinished {
marker: Some(marker),
file,
} if marker == expected_marker => Ok(Some(file)),
_ => Ok(None),
}
});
futures::pin_mut!(stream);
let file = stream.try_next().await?.unwrap();
Ok(file)
}
}
pub struct DriveFileBuilder<C> {
client: C,
path: PathBuf,
type_: Mime,
request: endpoint::drive::files::create::Request,
}
impl<C> DriveFileBuilder<C> {
pub fn with_path(client: C, path: impl AsRef<Path>) -> Self {
let path = path.as_ref().to_owned();
let request = endpoint::drive::files::create::Request {
name: path.file_name().map(|s| s.to_string_lossy().into_owned()),
folder_id: None,
is_sensitive: Some(false),
force: Some(false),
};
let type_ = mime_guess::from_path(&path).first_or_octet_stream();
DriveFileBuilder {
client,
type_,
path,
request,
}
}
pub fn as_request(&self) -> &endpoint::drive::files::create::Request {
&self.request
}
pub fn folder(&mut self, folder: impl EntityRef<DriveFolder>) -> &mut Self {
self.request.folder_id.replace(folder.entity_ref());
self
}
pub fn type_(&mut self, type_: Mime) -> &mut Self {
self.type_ = type_;
self
}
pub fn name(&mut self, name: impl Into<String>) -> &mut Self {
self.request.name.replace(name.into());
self
}
pub fn sensitive(&mut self, sensitive: bool) -> &mut Self {
self.request.is_sensitive = Some(sensitive);
self
}
pub fn use_existing_if_uploaded(&mut self, use_existing_if_uploaded: bool) -> &mut Self {
self.request.force = Some(!use_existing_if_uploaded);
self
}
}
impl<C: UploadFileClient> DriveFileBuilder<C> {
pub async fn upload(&self) -> Result<DriveFile, Error<C::Error>> {
let fs_file = std::fs::File::open(&self.path)?;
let file = self
.client
.request_with_file(
&self.request,
self.type_.clone(),
self.request.name.clone().unwrap_or_default(),
fs_file,
)
.await
.map_err(Error::Client)?
.into_result()?;
Ok(file)
}
}
pub struct DriveFileUpdateBuilder<C> {
client: C,
request: endpoint::drive::files::update::Request,
}
impl<C> DriveFileUpdateBuilder<C> {
pub fn new(client: C, file: impl EntityRef<DriveFile>) -> Self {
let request = endpoint::drive::files::update::Request {
file_id: file.entity_ref(),
folder_id: None,
name: None,
is_sensitive: None,
};
DriveFileUpdateBuilder { client, request }
}
pub fn as_request(&self) -> &endpoint::drive::files::update::Request {
&self.request
}
pub fn set_folder(&mut self, folder: impl EntityRef<DriveFolder>) -> &mut Self {
self.request.folder_id.replace(Some(folder.entity_ref()));
self
}
pub fn delete_folder(&mut self) -> &mut Self {
self.request.folder_id.replace(None);
self
}
pub fn name(&mut self, name: impl Into<String>) -> &mut Self {
self.request.name.replace(name.into());
self
}
pub fn sensitive(&mut self, sensitive: bool) -> &mut Self {
self.request.is_sensitive = Some(sensitive);
self
}
}
impl<C: Client> DriveFileUpdateBuilder<C> {
pub async fn update(&self) -> Result<DriveFile, Error<C::Error>> {
let file = self
.client
.request(&self.request)
.await
.map_err(Error::Client)?
.into_result()?;
Ok(file)
}
}
pub struct DriveFolderUpdateBuilder<C> {
client: C,
request: endpoint::drive::folders::update::Request,
}
impl<C> DriveFolderUpdateBuilder<C> {
pub fn new(client: C, folder: impl EntityRef<DriveFolder>) -> Self {
let request = endpoint::drive::folders::update::Request {
folder_id: folder.entity_ref(),
parent_id: None,
name: None,
};
DriveFolderUpdateBuilder { client, request }
}
pub fn as_request(&self) -> &endpoint::drive::folders::update::Request {
&self.request
}
update_builder_option_field! {
#[doc_name = "parent folder of the folder"]
pub parent: impl EntityRef<DriveFolder> { parent_id = parent.entity_ref() };
}
pub fn name(&mut self, name: impl Into<String>) -> &mut Self {
self.request.name.replace(name.into());
self
}
}
impl<C: Client> DriveFolderUpdateBuilder<C> {
pub async fn update(&self) -> Result<DriveFolder, Error<C::Error>> {
let folder = self
.client
.request(&self.request)
.await
.map_err(Error::Client)?
.into_result()?;
Ok(folder)
}
}
pub struct DriveFileListBuilder<C> {
client: C,
request: endpoint::drive::files::Request,
}
impl<C> DriveFileListBuilder<C> {
pub fn new(client: C) -> Self {
let request = endpoint::drive::files::Request::default();
DriveFileListBuilder { client, request }
}
pub fn as_request(&self) -> &endpoint::drive::files::Request {
&self.request
}
pub fn type_(&mut self, type_: Mime) -> &mut Self {
self.request.type_.replace(type_);
self
}
pub fn folder(&mut self, folder: impl EntityRef<DriveFolder>) -> &mut Self {
self.request.folder_id.replace(folder.entity_ref());
self
}
}
impl<C: Client + Sync> DriveFileListBuilder<C> {
pub fn list(&self) -> PagerStream<BoxPager<C, DriveFile>> {
let pager = BackwardPager::new(&self.client, self.request.clone());
PagerStream::new(Box::pin(pager))
}
}