1use std::path::{Path, PathBuf};
2
3use crate::pager::{BackwardPager, BoxPager, PagerStream};
4use crate::Error;
5
6#[cfg(feature = "12-48-0")]
7use futures::stream::TryStreamExt;
8use mime::Mime;
9use misskey_api::model::drive::{DriveFile, DriveFolder};
10#[cfg(feature = "12-48-0")]
11use misskey_api::streaming::channel;
12use misskey_api::{endpoint, EntityRef};
13#[cfg(feature = "12-48-0")]
14use misskey_core::streaming::StreamingClient;
15use misskey_core::{Client, UploadFileClient};
16#[cfg(feature = "12-48-0")]
17use ulid_crate::Ulid;
18use url::Url;
19
20pub struct DriveFileUrlBuilder<C> {
22 client: C,
23 #[cfg(feature = "12-48-0")]
24 marker: String,
25 request: endpoint::drive::files::upload_from_url::Request,
26}
27
28impl<C> DriveFileUrlBuilder<C> {
29 pub fn with_url(client: C, url: Url) -> Self {
31 #[cfg(feature = "12-48-0")]
32 let marker = Ulid::new().to_string();
33 let request = endpoint::drive::files::upload_from_url::Request {
34 url,
35 folder_id: None,
36 is_sensitive: Some(false),
37 force: Some(false),
38 #[cfg(feature = "12-48-0")]
39 comment: None,
40 #[cfg(feature = "12-48-0")]
41 marker: Some(marker.clone()),
42 };
43 DriveFileUrlBuilder {
44 client,
45 request,
46 #[cfg(feature = "12-48-0")]
47 marker,
48 }
49 }
50
51 pub fn as_request(&self) -> &endpoint::drive::files::upload_from_url::Request {
53 &self.request
54 }
55
56 pub fn folder(&mut self, folder: impl EntityRef<DriveFolder>) -> &mut Self {
58 self.request.folder_id.replace(folder.entity_ref());
59 self
60 }
61
62 #[cfg(feature = "12-48-0")]
64 #[cfg_attr(docsrs, doc(cfg(feature = "12-48-0")))]
65 pub fn comment(&mut self, comment: impl Into<String>) -> &mut Self {
66 self.request.comment.replace(comment.into());
67 self
68 }
69
70 pub fn sensitive(&mut self, sensitive: bool) -> &mut Self {
72 self.request.is_sensitive = Some(sensitive);
73 self
74 }
75
76 pub fn use_existing_if_uploaded(&mut self, use_existing_if_uploaded: bool) -> &mut Self {
79 self.request.force = Some(!use_existing_if_uploaded);
80 self
81 }
82}
83
84impl<C: Client> DriveFileUrlBuilder<C> {
85 #[cfg(feature = "12-48-0")]
98 #[cfg_attr(docsrs, doc(cfg(feature = "12-48-0")))]
99 pub async fn upload(&self) -> Result<(), Error<C::Error>> {
100 self.client
101 .request(&self.request)
102 .await
103 .map_err(Error::Client)?
104 .into_result()?;
105 Ok(())
106 }
107
108 #[cfg(any(docsrs, not(feature = "12-48-0")))]
114 #[cfg_attr(docsrs, doc(cfg(not(feature = "12-48-0"))))]
115 pub async fn upload_(&self) -> Result<DriveFile, Error<C::Error>> {
116 let file = self
117 .client
118 .request(&self.request)
119 .await
120 .map_err(Error::Client)?
121 .into_result()?;
122 Ok(file)
123 }
124}
125
126#[cfg(feature = "12-48-0")]
127#[cfg_attr(docsrs, doc(cfg(feature = "12-48-0")))]
128impl<C: Client> DriveFileUrlBuilder<C>
129where
130 C: StreamingClient<Error = <C as Client>::Error>,
131{
132 pub async fn upload_and_wait(&self) -> Result<DriveFile, Error<<C as Client>::Error>> {
147 let expected_marker = self.marker.clone();
148 self.client
149 .request(&self.request)
150 .await
151 .map_err(Error::Client)?
152 .into_result()?;
153
154 use channel::main::{self, MainStreamEvent};
155 let stream = self
156 .client
157 .channel(main::Request::default())
158 .await
159 .map_err(Error::Client)?
160 .map_err(Error::Client)
161 .try_filter_map(|event| async {
162 match event {
163 MainStreamEvent::UrlUploadFinished {
164 marker: Some(marker),
165 file,
166 } if marker == expected_marker => Ok(Some(file)),
167 _ => Ok(None),
168 }
169 });
170 futures::pin_mut!(stream);
171 let file = stream.try_next().await?.unwrap();
172 Ok(file)
173 }
174}
175
176pub struct DriveFileBuilder<C> {
178 client: C,
179 path: PathBuf,
180 type_: Mime,
181 request: endpoint::drive::files::create::Request,
182}
183
184impl<C> DriveFileBuilder<C> {
185 pub fn with_path(client: C, path: impl AsRef<Path>) -> Self {
187 let path = path.as_ref().to_owned();
188 let request = endpoint::drive::files::create::Request {
189 name: path.file_name().map(|s| s.to_string_lossy().into_owned()),
190 folder_id: None,
191 is_sensitive: Some(false),
192 force: Some(false),
193 };
194 let type_ = mime_guess::from_path(&path).first_or_octet_stream();
195 DriveFileBuilder {
196 client,
197 type_,
198 path,
199 request,
200 }
201 }
202
203 pub fn as_request(&self) -> &endpoint::drive::files::create::Request {
205 &self.request
206 }
207
208 pub fn folder(&mut self, folder: impl EntityRef<DriveFolder>) -> &mut Self {
210 self.request.folder_id.replace(folder.entity_ref());
211 self
212 }
213
214 pub fn type_(&mut self, type_: Mime) -> &mut Self {
216 self.type_ = type_;
217 self
218 }
219
220 pub fn name(&mut self, name: impl Into<String>) -> &mut Self {
222 self.request.name.replace(name.into());
223 self
224 }
225
226 pub fn sensitive(&mut self, sensitive: bool) -> &mut Self {
228 self.request.is_sensitive = Some(sensitive);
229 self
230 }
231
232 pub fn use_existing_if_uploaded(&mut self, use_existing_if_uploaded: bool) -> &mut Self {
235 self.request.force = Some(!use_existing_if_uploaded);
236 self
237 }
238}
239
240impl<C: UploadFileClient> DriveFileBuilder<C> {
241 pub async fn upload(&self) -> Result<DriveFile, Error<C::Error>> {
243 let fs_file = std::fs::File::open(&self.path)?;
244 let file = self
245 .client
246 .request_with_file(
247 &self.request,
248 self.type_.clone(),
249 self.request.name.clone().unwrap_or_default(),
250 fs_file,
251 )
252 .await
253 .map_err(Error::Client)?
254 .into_result()?;
255 Ok(file)
256 }
257}
258
259pub struct DriveFileUpdateBuilder<C> {
261 client: C,
262 request: endpoint::drive::files::update::Request,
263}
264
265impl<C> DriveFileUpdateBuilder<C> {
266 pub fn new(client: C, file: impl EntityRef<DriveFile>) -> Self {
268 let request = endpoint::drive::files::update::Request {
269 file_id: file.entity_ref(),
270 folder_id: None,
271 name: None,
272 is_sensitive: None,
273 };
274 DriveFileUpdateBuilder { client, request }
275 }
276
277 pub fn as_request(&self) -> &endpoint::drive::files::update::Request {
279 &self.request
280 }
281
282 pub fn set_folder(&mut self, folder: impl EntityRef<DriveFolder>) -> &mut Self {
284 self.request.folder_id.replace(Some(folder.entity_ref()));
285 self
286 }
287
288 pub fn delete_folder(&mut self) -> &mut Self {
290 self.request.folder_id.replace(None);
291 self
292 }
293
294 pub fn name(&mut self, name: impl Into<String>) -> &mut Self {
296 self.request.name.replace(name.into());
297 self
298 }
299
300 pub fn sensitive(&mut self, sensitive: bool) -> &mut Self {
302 self.request.is_sensitive = Some(sensitive);
303 self
304 }
305}
306
307impl<C: Client> DriveFileUpdateBuilder<C> {
308 pub async fn update(&self) -> Result<DriveFile, Error<C::Error>> {
310 let file = self
311 .client
312 .request(&self.request)
313 .await
314 .map_err(Error::Client)?
315 .into_result()?;
316 Ok(file)
317 }
318}
319
320pub struct DriveFolderUpdateBuilder<C> {
322 client: C,
323 request: endpoint::drive::folders::update::Request,
324}
325
326impl<C> DriveFolderUpdateBuilder<C> {
327 pub fn new(client: C, folder: impl EntityRef<DriveFolder>) -> Self {
329 let request = endpoint::drive::folders::update::Request {
330 folder_id: folder.entity_ref(),
331 parent_id: None,
332 name: None,
333 };
334 DriveFolderUpdateBuilder { client, request }
335 }
336
337 pub fn as_request(&self) -> &endpoint::drive::folders::update::Request {
339 &self.request
340 }
341
342 update_builder_option_field! {
343 #[doc_name = "parent folder of the folder"]
344 pub parent: impl EntityRef<DriveFolder> { parent_id = parent.entity_ref() };
345 }
346
347 pub fn name(&mut self, name: impl Into<String>) -> &mut Self {
349 self.request.name.replace(name.into());
350 self
351 }
352}
353
354impl<C: Client> DriveFolderUpdateBuilder<C> {
355 pub async fn update(&self) -> Result<DriveFolder, Error<C::Error>> {
357 let folder = self
358 .client
359 .request(&self.request)
360 .await
361 .map_err(Error::Client)?
362 .into_result()?;
363 Ok(folder)
364 }
365}
366
367pub struct DriveFileListBuilder<C> {
369 client: C,
370 request: endpoint::drive::files::Request,
371}
372
373impl<C> DriveFileListBuilder<C> {
374 pub fn new(client: C) -> Self {
376 let request = endpoint::drive::files::Request::default();
377 DriveFileListBuilder { client, request }
378 }
379
380 pub fn as_request(&self) -> &endpoint::drive::files::Request {
382 &self.request
383 }
384
385 pub fn type_(&mut self, type_: Mime) -> &mut Self {
387 self.request.type_.replace(type_);
388 self
389 }
390
391 pub fn folder(&mut self, folder: impl EntityRef<DriveFolder>) -> &mut Self {
393 self.request.folder_id.replace(folder.entity_ref());
394 self
395 }
396}
397
398impl<C: Client + Sync> DriveFileListBuilder<C> {
399 pub fn list(&self) -> PagerStream<BoxPager<C, DriveFile>> {
401 let pager = BackwardPager::new(&self.client, self.request.clone());
402 PagerStream::new(Box::pin(pager))
403 }
404}