opendal_service_onedrive/
backend.rs1use std::sync::Arc;
19
20use http::StatusCode;
21
22use opendal_core::raw::*;
23use opendal_core::*;
24
25use super::core::parse_error;
26use super::core::{ErrorContext, OneDriveCore};
27use super::deleter::OneDriveDeleter;
28use super::lister::OneDriveLister;
29use super::reader::*;
30use super::writer::OneDriveWriter;
31
32use std::fmt::Debug;
33
34use asyncband::mutex::Mutex;
35use log::debug;
36
37use super::ONEDRIVE_SCHEME;
38use super::config::OnedriveConfig;
39use super::core::OneDriveSigner;
40
41#[doc = include_str!("docs.md")]
43#[derive(Default)]
44pub struct OnedriveBuilder {
45 pub(super) config: OnedriveConfig,
46}
47
48impl Debug for OnedriveBuilder {
49 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 f.debug_struct("OnedriveBuilder")
51 .field("config", &self.config)
52 .finish_non_exhaustive()
53 }
54}
55
56impl OnedriveBuilder {
57 pub fn root(mut self, root: &str) -> Self {
59 self.config.root = if root.is_empty() {
60 None
61 } else {
62 Some(root.to_string())
63 };
64
65 self
66 }
67
68 pub fn access_token(mut self, access_token: &str) -> Self {
78 self.config.access_token = Some(access_token.to_string());
79 self
80 }
81
82 pub fn refresh_token(mut self, refresh_token: &str) -> Self {
90 self.config.refresh_token = Some(refresh_token.to_string());
91 self
92 }
93
94 pub fn client_id(mut self, client_id: &str) -> Self {
98 self.config.client_id = Some(client_id.to_string());
99 self
100 }
101
102 pub fn client_secret(mut self, client_secret: &str) -> Self {
107 self.config.client_secret = Some(client_secret.to_string());
108 self
109 }
110
111 #[deprecated(
113 since = "0.57.0",
114 note = "OneDrive supports version listing without this option."
115 )]
116 pub fn enable_versioning(self, _enabled: bool) -> Self {
117 self
118 }
119}
120
121impl Builder for OnedriveBuilder {
122 type Config = OnedriveConfig;
123
124 fn build(self) -> Result<impl Service> {
125 let root = normalize_root(&self.config.root.unwrap_or_default());
126 debug!("backend use root {root}");
127
128 let info = ServiceInfo::new(ONEDRIVE_SCHEME, &root, "");
129 let capability = Capability {
130 read: true,
131 read_with_suffix: true,
132 read_with_if_none_match: true,
133
134 write: true,
135 write_with_if_match: true,
136 #[cfg(target_pointer_width = "64")]
138 write_total_max_size: Some(250 * 1024 * 1024 * 1024), copy: true,
141 rename: true,
142
143 stat: true,
144 stat_with_if_none_match: true,
145 delete: true,
149 create_dir: true,
150
151 list: true,
152 list_with_limit: true,
153 list_with_start_after: true,
154 list_with_versions: true,
155
156 shared: true,
157
158 ..Default::default()
159 };
160
161 let accessor_info = info;
162 let mut signer = OneDriveSigner::new();
163
164 match (self.config.access_token, self.config.refresh_token) {
169 (Some(access_token), None) => {
170 signer.access_token = access_token;
171 signer.expires_in = Timestamp::MAX;
172 }
173 (None, Some(refresh_token)) => {
174 let client_id = self.config.client_id.ok_or_else(|| {
175 Error::new(
176 ErrorKind::ConfigInvalid,
177 "client_id must be set when refresh_token is set",
178 )
179 .with_context("service", ONEDRIVE_SCHEME)
180 })?;
181
182 signer.refresh_token = refresh_token;
183 signer.client_id = client_id;
184 if let Some(client_secret) = self.config.client_secret {
185 signer.client_secret = client_secret;
186 }
187 }
188 (Some(_), Some(_)) => {
189 return Err(Error::new(
190 ErrorKind::ConfigInvalid,
191 "access_token and refresh_token cannot be set at the same time",
192 )
193 .with_context("service", ONEDRIVE_SCHEME));
194 }
195 (None, None) => {
196 return Err(Error::new(
197 ErrorKind::ConfigInvalid,
198 "access_token or refresh_token must be set",
199 )
200 .with_context("service", ONEDRIVE_SCHEME));
201 }
202 };
203
204 let core = Arc::new(OneDriveCore {
205 info: accessor_info,
206 capability,
207 root,
208 signer: Arc::new(Mutex::new(signer)),
209 });
210
211 Ok(OnedriveBackend { core })
212 }
213}
214
215#[derive(Clone, Debug)]
216pub struct OnedriveBackend {
217 pub core: Arc<OneDriveCore>,
218}
219
220impl Service for OnedriveBackend {
221 type Reader = oio::StreamReader<OnedriveReader>;
222 type Writer = oio::OneShotWriter<OneDriveWriter>;
223 type Lister = oio::PageLister<OneDriveLister>;
224 type Deleter = oio::OneShotDeleter<OneDriveDeleter>;
225 type Copier = oio::OneShotCopier;
226 type Composer = ();
227
228 fn info(&self) -> ServiceInfo {
229 self.core.info.clone()
230 }
231
232 fn capability(&self) -> Capability {
233 self.core.capability
234 }
235
236 async fn create_dir(
237 &self,
238 ctx: &OperationContext,
239 path: &str,
240 _args: OpCreateDir,
241 ) -> Result<RpCreateDir> {
242 if path == "/" {
243 return Ok(RpCreateDir::default());
245 }
246
247 let response = self.core.onedrive_create_dir(ctx, path).await?;
248 match response.status() {
249 StatusCode::CREATED | StatusCode::OK => Ok(RpCreateDir::default()),
250 _ => Err(parse_error(
251 ErrorContext::new(ServiceOperation("CreateFolder")),
252 response,
253 )),
254 }
255 }
256
257 async fn stat(&self, ctx: &OperationContext, path: &str, args: OpStat) -> Result<RpStat> {
258 let meta = self.core.onedrive_stat(ctx, path, args).await?;
259
260 Ok(RpStat::new(meta))
261 }
262 fn read(&self, ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
263 let output: oio::StreamReader<OnedriveReader> = {
264 Ok(oio::StreamReader::new(OnedriveReader::new(
265 self.clone(),
266 ctx.clone(),
267 path,
268 args,
269 )))
270 }?;
271
272 Ok(output)
273 }
274
275 fn write(&self, ctx: &OperationContext, path: &str, args: OpWrite) -> Result<Self::Writer> {
276 let output: oio::OneShotWriter<OneDriveWriter> = {
277 Ok(oio::OneShotWriter::new(OneDriveWriter::new(
278 self.core.clone(),
279 ctx.clone(),
280 args,
281 path.to_string(),
282 )))
283 }?;
284
285 Ok(output)
286 }
287
288 fn delete(&self, ctx: &OperationContext) -> Result<Self::Deleter> {
289 let output: oio::OneShotDeleter<OneDriveDeleter> = {
290 Ok(oio::OneShotDeleter::new(OneDriveDeleter::new(
291 self.core.clone(),
292 ctx.clone(),
293 )))
294 }?;
295
296 Ok(output)
297 }
298
299 fn copy(
300 &self,
301 ctx: &OperationContext,
302 from: &str,
303 to: &str,
304 args: OpCopy,
305 ) -> Result<Self::Copier> {
306 let backend = self.clone();
307 let core = self.core.clone();
308 let ctx = ctx.clone();
309 let from = from.to_string();
310 let to = to.to_string();
311 let source_content_length_hint = args.source_content_length_hint();
312
313 Ok(oio::OneShotCopier::new(async move {
314 let source_size = match source_content_length_hint {
315 Some(size) => size,
316 None => backend
317 .stat(&ctx, &from, OpStat::default())
318 .await?
319 .into_metadata()
320 .content_length(),
321 };
322
323 let monitor_url = core.initialize_copy(&ctx, &from, &to).await?;
324 core.wait_until_complete(&ctx, monitor_url).await?;
325 Ok(MetadataBuilder::file(source_size).build())
326 }))
327 }
328
329 async fn rename(
330 &self,
331 ctx: &OperationContext,
332 from: &str,
333 to: &str,
334 _args: OpRename,
335 ) -> Result<RpRename> {
336 if from == to {
337 return Ok(RpRename::default());
338 }
339
340 self.core.onedrive_move(ctx, from, to).await?;
341
342 Ok(RpRename::default())
343 }
344
345 fn list(&self, ctx: &OperationContext, path: &str, args: OpList) -> Result<Self::Lister> {
346 let output: oio::PageLister<OneDriveLister> = {
347 let l = OneDriveLister::new(path.to_string(), self.core.clone(), ctx.clone(), &args);
348 Ok(oio::PageLister::new(l))
349 }?;
350
351 Ok(output)
352 }
353
354 async fn presign(
355 &self,
356 _ctx: &OperationContext,
357 _path: &str,
358 _args: OpPresign,
359 ) -> Result<RpPresign> {
360 Err(Error::new(
361 ErrorKind::Unsupported,
362 "operation is not supported",
363 ))
364 }
365}