use std::sync::Arc;
use bytes::Buf;
use serde::Deserialize;
use serde_json::de;
use super::core::AzdlsCore;
use super::error::parse_error;
use crate::raw::*;
use crate::*;
pub struct AzdlsLister {
core: Arc<AzdlsCore>,
path: String,
limit: Option<usize>,
}
impl AzdlsLister {
pub fn new(core: Arc<AzdlsCore>, path: String, limit: Option<usize>) -> Self {
Self { core, path, limit }
}
}
impl oio::PageList for AzdlsLister {
async fn next_page(&self, ctx: &mut oio::PageContext) -> Result<()> {
let resp = self
.core
.azdls_list(&self.path, &ctx.token, self.limit)
.await?;
if resp.status() == http::StatusCode::NOT_FOUND {
ctx.done = true;
return Ok(());
}
if resp.status() != http::StatusCode::OK {
return Err(parse_error(resp));
}
if ctx.token.is_empty() && !ctx.done {
let e = oio::Entry::new(&self.path, Metadata::new(EntryMode::DIR));
ctx.entries.push_back(e);
}
if let Some(value) = resp.headers().get("x-ms-continuation") {
let value = value.to_str().map_err(|err| {
Error::new(ErrorKind::Unexpected, "header value is not valid string")
.set_source(err)
})?;
ctx.token = value.to_string();
} else {
ctx.token = "".to_string();
ctx.done = true;
}
let bs = resp.into_body();
let output: Output = de::from_reader(bs.reader()).map_err(new_json_deserialize_error)?;
for object in output.paths {
let mode = if &object.is_directory == "true" {
EntryMode::DIR
} else {
EntryMode::FILE
};
let meta = Metadata::new(mode)
.with_etag(format!("\"{}\"", &object.etag))
.with_content_length(object.content_length.parse().map_err(|err| {
Error::new(ErrorKind::Unexpected, "content length is not valid integer")
.set_source(err)
})?)
.with_last_modified(parse_datetime_from_rfc2822(&object.last_modified)?);
let mut path = build_rel_path(&self.core.root, &object.name);
if mode.is_dir() {
path += "/"
};
let de = oio::Entry::new(&path, meta);
ctx.entries.push_back(de);
}
Ok(())
}
}
#[derive(Default, Debug, Deserialize)]
#[serde(default)]
struct Output {
paths: Vec<Path>,
}
#[derive(Default, Debug, Deserialize, PartialEq, Eq)]
#[serde(default)]
struct Path {
#[serde(rename = "contentLength")]
content_length: String,
#[serde(rename = "etag")]
etag: String,
#[serde(rename = "isDirectory")]
is_directory: String,
#[serde(rename = "lastModified")]
last_modified: String,
#[serde(rename = "name")]
name: String,
}
#[cfg(test)]
mod tests {
use bytes::Bytes;
use super::*;
#[test]
fn test_parse_path() {
let bs = Bytes::from(
r#"{"paths":[{"contentLength":"1977097","etag":"0x8DACF9B0061305F","group":"$superuser","lastModified":"Sat, 26 Nov 2022 10:43:05 GMT","name":"c3b3ef48-7783-4946-81bc-dc07e1728878/d4ea21d7-a533-4011-8b1f-d0e566d63725","owner":"$superuser","permissions":"rw-r-----"}]}"#,
);
let out: Output = de::from_slice(&bs).expect("must success");
println!("{out:?}");
assert_eq!(
out.paths[0],
Path {
content_length: "1977097".to_string(),
etag: "0x8DACF9B0061305F".to_string(),
is_directory: "".to_string(),
last_modified: "Sat, 26 Nov 2022 10:43:05 GMT".to_string(),
name: "c3b3ef48-7783-4946-81bc-dc07e1728878/d4ea21d7-a533-4011-8b1f-d0e566d63725"
.to_string()
}
);
}
}