opendal/services/onedrive/
lister.rs1use std::sync::Arc;
19
20use bytes::Buf;
21
22use super::core::OneDriveCore;
23use super::error::parse_error;
24use super::graph_model::{GraphApiOneDriveListResponse, ItemType, GENERAL_SELECT_PARAM};
25use crate::raw::oio;
26use crate::raw::*;
27use crate::*;
28
29pub struct OneDriveLister {
30 core: Arc<OneDriveCore>,
31 path: String,
32 op: OpList,
33}
34
35impl OneDriveLister {
36 const DRIVE_ROOT_PREFIX: &'static str = "/drive/root:";
37
38 pub(crate) fn new(path: String, core: Arc<OneDriveCore>, args: &OpList) -> Self {
39 Self {
40 core,
41 path,
42 op: args.clone(),
43 }
44 }
45}
46
47impl oio::PageList for OneDriveLister {
48 async fn next_page(&self, ctx: &mut oio::PageContext) -> Result<()> {
49 let request_url = if ctx.token.is_empty() {
50 let base = format!(
51 "{}:/children?{}",
52 self.core.onedrive_item_url(&self.path, true),
53 GENERAL_SELECT_PARAM
54 );
55 if let Some(limit) = self.op.limit() {
56 base + &format!("&$top={}", limit)
57 } else {
58 base
59 }
60 } else {
61 ctx.token.clone()
62 };
63
64 let response = self.core.onedrive_get_next_list_page(&request_url).await?;
65
66 let status_code = response.status();
67 if !status_code.is_success() {
68 if status_code == http::StatusCode::NOT_FOUND {
69 ctx.done = true;
70 return Ok(());
71 }
72 return Err(parse_error(response));
73 }
74
75 let bytes = response.into_body();
76 let decoded_response: GraphApiOneDriveListResponse =
77 serde_json::from_reader(bytes.reader()).map_err(new_json_deserialize_error)?;
78
79 let list_with_versions = self.core.info.native_capability().list_with_versions;
80
81 if ctx.token.is_empty() && !ctx.done {
83 let path = if self.path == "/" {
86 "".to_string()
87 } else {
88 self.path.clone()
89 };
90
91 let meta = self.core.onedrive_stat(&path, OpStat::default()).await?;
92
93 let entry = oio::Entry::new(&path, meta);
96 ctx.entries.push_back(entry);
97 }
98
99 if let Some(next_link) = decoded_response.next_link {
100 ctx.token = next_link;
101 } else {
102 ctx.done = true;
103 }
104
105 for drive_item in decoded_response.value {
106 let name = drive_item.name;
107 let parent_path = drive_item.parent_reference.path;
108 let parent_path = parent_path
109 .strip_prefix(Self::DRIVE_ROOT_PREFIX)
110 .unwrap_or("");
111
112 let path = format!("{}/{}", parent_path, name);
113 let mut normalized_path = build_rel_path(self.core.root.as_str(), path.as_str());
114 let entry_mode = match drive_item.item_type {
115 ItemType::Folder { .. } => EntryMode::DIR,
116 ItemType::File { .. } => EntryMode::FILE,
117 };
118
119 if entry_mode == EntryMode::DIR {
121 normalized_path.push('/');
122 }
123
124 let mut meta = Metadata::new(entry_mode)
125 .with_etag(drive_item.e_tag)
126 .with_content_length(drive_item.size.max(0) as u64);
127 let last_modified =
128 parse_datetime_from_rfc3339(drive_item.last_modified_date_time.as_str())?;
129 meta.set_last_modified(last_modified);
130
131 if list_with_versions {
136 let versions = self.core.onedrive_list_versions(&path).await?;
137 if let Some(version) = versions.first() {
138 meta.set_version(&version.id);
139 }
140 }
141
142 let entry = oio::Entry::new(&normalized_path, meta);
143 ctx.entries.push_back(entry)
144 }
145
146 Ok(())
147 }
148}