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