opendal/services/aliyun_drive/
lister.rs1use std::sync::Arc;
19
20use self::oio::Entry;
21use super::core::AliyunDriveCore;
22use super::core::AliyunDriveFileList;
23use crate::EntryMode;
24use crate::Error;
25use crate::ErrorKind;
26use crate::Metadata;
27use crate::Result;
28use crate::raw::*;
29use bytes::Buf;
30
31pub struct AliyunDriveLister {
32 core: Arc<AliyunDriveCore>,
33
34 parent: Option<AliyunDriveParent>,
35 limit: Option<usize>,
36}
37
38pub struct AliyunDriveParent {
39 pub file_id: String,
40 pub path: String,
41 pub updated_at: String,
42}
43
44impl AliyunDriveLister {
45 pub fn new(
46 core: Arc<AliyunDriveCore>,
47 parent: Option<AliyunDriveParent>,
48 limit: Option<usize>,
49 ) -> Self {
50 AliyunDriveLister {
51 core,
52 parent,
53 limit,
54 }
55 }
56}
57
58impl oio::PageList for AliyunDriveLister {
59 async fn next_page(&self, ctx: &mut oio::PageContext) -> Result<()> {
60 let Some(parent) = &self.parent else {
61 ctx.done = true;
62 return Ok(());
63 };
64
65 let offset = if ctx.token.is_empty() {
66 ctx.entries.push_back(Entry::new(
68 &parent.path,
69 Metadata::new(EntryMode::DIR).with_last_modified(
70 parent.updated_at.parse::<Timestamp>().map_err(|e| {
71 Error::new(ErrorKind::Unexpected, "parse last modified time").set_source(e)
72 })?,
73 ),
74 ));
75 None
76 } else {
77 Some(ctx.token.clone())
78 };
79
80 let res = self.core.list(&parent.file_id, self.limit, offset).await;
81 let res = match res {
82 Err(err) if err.kind() == ErrorKind::NotFound => {
83 ctx.done = true;
84 None
85 }
86 Err(err) => return Err(err),
87 Ok(res) => Some(res),
88 };
89
90 let Some(res) = res else {
91 return Ok(());
92 };
93
94 let result: AliyunDriveFileList =
95 serde_json::from_reader(res.reader()).map_err(new_json_serialize_error)?;
96
97 for item in result.items {
98 let (path, mut md) = if item.path_type == "folder" {
99 let path = format!("{}{}/", &parent.path.trim_start_matches('/'), &item.name);
100 (path, Metadata::new(EntryMode::DIR))
101 } else {
102 let path = format!("{}{}", &parent.path.trim_start_matches('/'), &item.name);
103 (path, Metadata::new(EntryMode::FILE))
104 };
105
106 md = md.with_last_modified(item.updated_at.parse::<Timestamp>().map_err(|e| {
107 Error::new(ErrorKind::Unexpected, "parse last modified time").set_source(e)
108 })?);
109 if let Some(v) = item.size {
110 md = md.with_content_length(v);
111 }
112 if let Some(v) = item.content_type {
113 md = md.with_content_type(v);
114 }
115
116 ctx.entries.push_back(Entry::new(&path, md));
117 }
118
119 let next_marker = result.next_marker.unwrap_or_default();
120 if next_marker.is_empty() {
121 ctx.done = true;
122 } else {
123 ctx.token = next_marker;
124 }
125
126 Ok(())
127 }
128}