opendal/services/dropbox/
backend.rs1use std::fmt::Debug;
19use std::sync::Arc;
20
21use bytes::Buf;
22use http::Response;
23use http::StatusCode;
24
25use super::core::*;
26use super::delete::DropboxDeleter;
27use super::error::*;
28use super::lister::DropboxLister;
29use super::writer::DropboxWriter;
30use crate::raw::*;
31use crate::*;
32
33#[derive(Clone, Debug)]
34pub struct DropboxBackend {
35 pub core: Arc<DropboxCore>,
36}
37
38impl Access for DropboxBackend {
39 type Reader = HttpBody;
40 type Writer = oio::OneShotWriter<DropboxWriter>;
41 type Lister = oio::PageLister<DropboxLister>;
42 type Deleter = oio::OneShotDeleter<DropboxDeleter>;
43
44 fn info(&self) -> Arc<AccessorInfo> {
45 self.core.info.clone()
46 }
47
48 async fn create_dir(&self, path: &str, _args: OpCreateDir) -> Result<RpCreateDir> {
49 let resp = self.core.dropbox_get_metadata(path).await?;
51 if StatusCode::OK == resp.status() {
52 let bytes = resp.into_body();
53 let decoded_response: DropboxMetadataResponse =
54 serde_json::from_reader(bytes.reader()).map_err(new_json_deserialize_error)?;
55 if "folder" == decoded_response.tag {
56 return Ok(RpCreateDir::default());
57 }
58 if "file" == decoded_response.tag {
59 return Err(Error::new(
60 ErrorKind::NotADirectory,
61 format!("it's not a directory {}", path),
62 ));
63 }
64 }
65
66 let res = self.core.dropbox_create_folder(path).await?;
67 Ok(res)
68 }
69
70 async fn stat(&self, path: &str, _: OpStat) -> Result<RpStat> {
71 let resp = self.core.dropbox_get_metadata(path).await?;
72 let status = resp.status();
73 match status {
74 StatusCode::OK => {
75 let bytes = resp.into_body();
76 let decoded_response: DropboxMetadataResponse =
77 serde_json::from_reader(bytes.reader()).map_err(new_json_deserialize_error)?;
78 let entry_mode: EntryMode = match decoded_response.tag.as_str() {
79 "file" => EntryMode::FILE,
80 "folder" => EntryMode::DIR,
81 _ => EntryMode::Unknown,
82 };
83
84 let mut metadata = Metadata::new(entry_mode);
85 if entry_mode == EntryMode::FILE {
89 let date_utc_last_modified =
90 parse_datetime_from_rfc3339(&decoded_response.client_modified)?;
91 metadata.set_last_modified(date_utc_last_modified);
92
93 if let Some(size) = decoded_response.size {
94 metadata.set_content_length(size);
95 } else {
96 return Err(Error::new(
97 ErrorKind::Unexpected,
98 format!("no size found for file {}", path),
99 ));
100 }
101 }
102 Ok(RpStat::new(metadata))
103 }
104 _ => Err(parse_error(resp)),
105 }
106 }
107
108 async fn read(&self, path: &str, args: OpRead) -> Result<(RpRead, Self::Reader)> {
109 let resp = self.core.dropbox_get(path, args.range(), &args).await?;
110
111 let status = resp.status();
112 match status {
113 StatusCode::OK | StatusCode::PARTIAL_CONTENT => {
114 Ok((RpRead::default(), resp.into_body()))
115 }
116 _ => {
117 let (part, mut body) = resp.into_parts();
118 let buf = body.to_buffer().await?;
119 Err(parse_error(Response::from_parts(part, buf)))
120 }
121 }
122 }
123
124 async fn write(&self, path: &str, args: OpWrite) -> Result<(RpWrite, Self::Writer)> {
125 Ok((
126 RpWrite::default(),
127 oio::OneShotWriter::new(DropboxWriter::new(
128 self.core.clone(),
129 args,
130 String::from(path),
131 )),
132 ))
133 }
134
135 async fn delete(&self) -> Result<(RpDelete, Self::Deleter)> {
136 Ok((
137 RpDelete::default(),
138 oio::OneShotDeleter::new(DropboxDeleter::new(self.core.clone())),
139 ))
140 }
141
142 async fn list(&self, path: &str, args: OpList) -> Result<(RpList, Self::Lister)> {
143 Ok((
144 RpList::default(),
145 oio::PageLister::new(DropboxLister::new(
146 self.core.clone(),
147 path.to_string(),
148 args.recursive(),
149 args.limit(),
150 )),
151 ))
152 }
153
154 async fn copy(&self, from: &str, to: &str, _: OpCopy) -> Result<RpCopy> {
155 let resp = self.core.dropbox_copy(from, to).await?;
156
157 let status = resp.status();
158
159 match status {
160 StatusCode::OK => Ok(RpCopy::default()),
161 _ => {
162 let err = parse_error(resp);
163 match err.kind() {
164 ErrorKind::NotFound => Ok(RpCopy::default()),
165 _ => Err(err),
166 }
167 }
168 }
169 }
170
171 async fn rename(&self, from: &str, to: &str, _: OpRename) -> Result<RpRename> {
172 let resp = self.core.dropbox_move(from, to).await?;
173
174 let status = resp.status();
175
176 match status {
177 StatusCode::OK => Ok(RpRename::default()),
178 _ => {
179 let err = parse_error(resp);
180 match err.kind() {
181 ErrorKind::NotFound => Ok(RpRename::default()),
182 _ => Err(err),
183 }
184 }
185 }
186 }
187}