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 type BlockingReader = ();
44 type BlockingWriter = ();
45 type BlockingLister = ();
46 type BlockingDeleter = ();
47
48 fn info(&self) -> Arc<AccessorInfo> {
49 self.core.info.clone()
50 }
51
52 async fn create_dir(&self, path: &str, _args: OpCreateDir) -> Result<RpCreateDir> {
53 let resp = self.core.dropbox_get_metadata(path).await?;
55 if StatusCode::OK == resp.status() {
56 let bytes = resp.into_body();
57 let decoded_response: DropboxMetadataResponse =
58 serde_json::from_reader(bytes.reader()).map_err(new_json_deserialize_error)?;
59 if "folder" == decoded_response.tag {
60 return Ok(RpCreateDir::default());
61 }
62 if "file" == decoded_response.tag {
63 return Err(Error::new(
64 ErrorKind::NotADirectory,
65 format!("it's not a directory {}", path),
66 ));
67 }
68 }
69
70 let res = self.core.dropbox_create_folder(path).await?;
71 Ok(res)
72 }
73
74 async fn stat(&self, path: &str, _: OpStat) -> Result<RpStat> {
75 let resp = self.core.dropbox_get_metadata(path).await?;
76 let status = resp.status();
77 match status {
78 StatusCode::OK => {
79 let bytes = resp.into_body();
80 let decoded_response: DropboxMetadataResponse =
81 serde_json::from_reader(bytes.reader()).map_err(new_json_deserialize_error)?;
82 let entry_mode: EntryMode = match decoded_response.tag.as_str() {
83 "file" => EntryMode::FILE,
84 "folder" => EntryMode::DIR,
85 _ => EntryMode::Unknown,
86 };
87
88 let mut metadata = Metadata::new(entry_mode);
89 if entry_mode == EntryMode::FILE {
93 let date_utc_last_modified =
94 parse_datetime_from_rfc3339(&decoded_response.client_modified)?;
95 metadata.set_last_modified(date_utc_last_modified);
96
97 if let Some(size) = decoded_response.size {
98 metadata.set_content_length(size);
99 } else {
100 return Err(Error::new(
101 ErrorKind::Unexpected,
102 format!("no size found for file {}", path),
103 ));
104 }
105 }
106 Ok(RpStat::new(metadata))
107 }
108 _ => Err(parse_error(resp)),
109 }
110 }
111
112 async fn read(&self, path: &str, args: OpRead) -> Result<(RpRead, Self::Reader)> {
113 let resp = self.core.dropbox_get(path, args.range(), &args).await?;
114
115 let status = resp.status();
116 match status {
117 StatusCode::OK | StatusCode::PARTIAL_CONTENT => {
118 Ok((RpRead::default(), resp.into_body()))
119 }
120 _ => {
121 let (part, mut body) = resp.into_parts();
122 let buf = body.to_buffer().await?;
123 Err(parse_error(Response::from_parts(part, buf)))
124 }
125 }
126 }
127
128 async fn write(&self, path: &str, args: OpWrite) -> Result<(RpWrite, Self::Writer)> {
129 Ok((
130 RpWrite::default(),
131 oio::OneShotWriter::new(DropboxWriter::new(
132 self.core.clone(),
133 args,
134 String::from(path),
135 )),
136 ))
137 }
138
139 async fn delete(&self) -> Result<(RpDelete, Self::Deleter)> {
140 Ok((
141 RpDelete::default(),
142 oio::OneShotDeleter::new(DropboxDeleter::new(self.core.clone())),
143 ))
144 }
145
146 async fn list(&self, path: &str, args: OpList) -> Result<(RpList, Self::Lister)> {
147 Ok((
148 RpList::default(),
149 oio::PageLister::new(DropboxLister::new(
150 self.core.clone(),
151 path.to_string(),
152 args.recursive(),
153 args.limit(),
154 )),
155 ))
156 }
157
158 async fn copy(&self, from: &str, to: &str, _: OpCopy) -> Result<RpCopy> {
159 let resp = self.core.dropbox_copy(from, to).await?;
160
161 let status = resp.status();
162
163 match status {
164 StatusCode::OK => Ok(RpCopy::default()),
165 _ => {
166 let err = parse_error(resp);
167 match err.kind() {
168 ErrorKind::NotFound => Ok(RpCopy::default()),
169 _ => Err(err),
170 }
171 }
172 }
173 }
174
175 async fn rename(&self, from: &str, to: &str, _: OpRename) -> Result<RpRename> {
176 let resp = self.core.dropbox_move(from, to).await?;
177
178 let status = resp.status();
179
180 match status {
181 StatusCode::OK => Ok(RpRename::default()),
182 _ => {
183 let err = parse_error(resp);
184 match err.kind() {
185 ErrorKind::NotFound => Ok(RpRename::default()),
186 _ => Err(err),
187 }
188 }
189 }
190 }
191}