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