acick_dropbox/
dropbox.rs

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}