1use std::io::Read;
2
3use anyhow::anyhow;
4use dropbox_sdk::files::{
5 self, FileMetadata, FolderMetadata, ListFolderArg, ListFolderContinueArg, ListFolderCursor,
6 Metadata, PathROrId, SharedLink,
7};
8use dropbox_sdk::sharing::{self, GetSharedLinkFileArg, Path};
9
10use crate::authorizer::Token;
11use crate::convert_dbx_err;
12use crate::hyper_client::HyperClient;
13use crate::Result;
14
15#[derive(Debug)]
16pub struct Dropbox {
17 client: HyperClient,
18}
19
20impl Dropbox {
21 pub fn new(token: Token) -> Self {
22 let client = HyperClient::new(token.access_token);
23 Self { client }
24 }
25
26 pub fn list_all_folders<P: Into<PathROrId>>(
27 &self,
28 path: P,
29 shared_link_url: Option<&str>,
30 ) -> Result<Vec<FolderMetadata>> {
31 let folders = self
32 .list_folder(path, shared_link_url)?
33 .into_iter()
34 .filter_map(|meta| match meta {
35 Metadata::Folder(folder_meta) => Some(folder_meta),
36 _ => None,
37 })
38 .collect();
39
40 Ok(folders)
41 }
42
43 pub fn list_all_files<P: Into<PathROrId>>(
44 &self,
45 path: P,
46 shared_link_url: Option<&str>,
47 ) -> Result<Vec<FileMetadata>> {
48 let files = self
49 .list_folder(path, shared_link_url)?
50 .into_iter()
51 .filter_map(|meta| match meta {
52 Metadata::File(file_meta) => Some(file_meta),
53 _ => None,
54 })
55 .collect();
56
57 Ok(files)
58 }
59
60 fn list_folder<P: Into<PathROrId>>(
61 &self,
62 path: P,
63 shared_link_url: Option<&str>,
64 ) -> Result<Vec<Metadata>> {
65 let mut arg = ListFolderArg::new(path.into());
66 if let Some(shared_link_url) = shared_link_url {
67 let shared_link = SharedLink::new(shared_link_url.to_owned());
68 arg = arg.with_shared_link(Some(shared_link));
69 }
70 let res = files::list_folder(&self.client, &arg).map_err(convert_dbx_err)??;
71
72 let mut folders = res.entries;
73 if res.has_more {
74 self.list_folder_continue(res.cursor, &mut folders)?;
75 }
76
77 Ok(folders)
78 }
79
80 fn list_folder_continue(
81 &self,
82 cursor: ListFolderCursor,
83 folders: &mut Vec<Metadata>,
84 ) -> Result<()> {
85 let arg = ListFolderContinueArg { cursor };
86 let res = files::list_folder_continue(&self.client, &arg).map_err(convert_dbx_err)??;
87 folders.extend(res.entries.into_iter());
88 if res.has_more {
89 self.list_folder_continue(res.cursor, folders)?;
90 }
91 Ok(())
92 }
93
94 pub fn get_shared_link_file<T: Into<String>>(
95 &self,
96 url: T,
97 path: Path,
98 ) -> Result<Box<dyn Read>> {
99 let arg = GetSharedLinkFileArg::new(url.into()).with_path(Some(path.clone()));
100 let res = sharing::get_shared_link_file(&self.client, &arg, None, None)
101 .map_err(convert_dbx_err)??;
102
103 match res.body {
104 Some(body) => Ok(body),
105 _ => Err(anyhow!("Found empty body : {}", path)),
106 }
107 }
108}