opendal/services/sftp/
lister.rs1use std::pin::Pin;
19
20use futures::StreamExt;
21use openssh_sftp_client::fs::DirEntry;
22use openssh_sftp_client::fs::ReadDir;
23
24use super::error::parse_sftp_error;
25use crate::raw::oio;
26use crate::raw::oio::Entry;
27use crate::Result;
28
29pub struct SftpLister {
30 dir: Pin<Box<ReadDir>>,
31 prefix: String,
32}
33
34impl SftpLister {
35 pub fn new(dir: ReadDir, path: String) -> Self {
36 let prefix = if path == "/" { "".to_owned() } else { path };
37
38 SftpLister {
39 dir: Box::pin(dir),
40 prefix,
41 }
42 }
43}
44
45impl oio::List for SftpLister {
46 async fn next(&mut self) -> Result<Option<Entry>> {
47 loop {
48 let item = self
49 .dir
50 .next()
51 .await
52 .transpose()
53 .map_err(parse_sftp_error)?;
54
55 match item {
56 Some(e) => {
57 if e.filename().to_str() == Some("..") {
58 continue;
59 } else if e.filename().to_str() == Some(".") {
60 let mut path = self.prefix.as_str();
61 if self.prefix.is_empty() {
62 path = "/";
63 }
64 return Ok(Some(Entry::new(path, e.metadata().into())));
65 } else {
66 return Ok(Some(map_entry(self.prefix.as_str(), e)));
67 }
68 }
69 None => return Ok(None),
70 }
71 }
72 }
73}
74
75fn map_entry(prefix: &str, value: DirEntry) -> Entry {
76 let path = format!(
77 "{}{}{}",
78 prefix,
79 value.filename().to_str().unwrap(),
80 if value.file_type().unwrap().is_dir() {
81 "/"
82 } else {
83 ""
84 }
85 );
86
87 Entry::new(path.as_str(), value.metadata().into())
88}