From 77cf29b7bcacbf55ee33d5c59cd9a1f55054a6ae Mon Sep 17 00:00:00 2001 From: Erick Guan Date: Sun, 20 Oct 2024 22:31:35 +0200 Subject: [PATCH] feat(services/gdrive): List dir shows timestamp --- core/src/services/gdrive/backend.rs | 4 +- core/src/services/gdrive/lister.rs | 80 ++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/core/src/services/gdrive/backend.rs b/core/src/services/gdrive/backend.rs index 09c51fd2c83..4b3d5324ccf 100644 --- a/core/src/services/gdrive/backend.rs +++ b/core/src/services/gdrive/backend.rs @@ -153,9 +153,9 @@ impl Access for GdriveBackend { Ok(RpDelete::default()) } - async fn list(&self, path: &str, _args: OpList) -> Result<(RpList, Self::Lister)> { + async fn list(&self, path: &str, args: OpList) -> Result<(RpList, Self::Lister)> { let path = build_abs_path(&self.core.root, path); - let l = GdriveLister::new(path, self.core.clone()); + let l = GdriveLister::new(path, self.core.clone(), args); Ok((RpList::default(), oio::PageLister::new(l))) } diff --git a/core/src/services/gdrive/lister.rs b/core/src/services/gdrive/lister.rs index 2dfec0e739c..a9e21c16b0b 100644 --- a/core/src/services/gdrive/lister.rs +++ b/core/src/services/gdrive/lister.rs @@ -20,19 +20,38 @@ use std::sync::Arc; use http::StatusCode; use super::core::GdriveCore; +use super::core::GdriveFile; use super::core::GdriveFileList; use super::error::parse_error; use crate::raw::*; use crate::*; +use bytes::Buf; +use chrono::Utc; pub struct GdriveLister { path: String, core: Arc, + op: OpList, +} + +async fn stat_file(core: Arc, path: &str) -> Result { + // reuse gdrive_stat which resolves `file_id` by path via core's `path_cache`. + let resp = core.gdrive_stat(path).await?; + + if resp.status() != StatusCode::OK { + return Err(parse_error(resp)); + } + + let bs = resp.into_body(); + let gdrive_file: GdriveFile = + serde_json::from_reader(bs.reader()).map_err(new_json_deserialize_error)?; + + Ok(gdrive_file) } impl GdriveLister { - pub fn new(path: String, core: Arc) -> Self { - Self { path, core } + pub fn new(path: String, core: Arc, op: OpList) -> Self { + Self { path, core, op } } } @@ -64,10 +83,32 @@ impl oio::PageList for GdriveLister { return Ok(()); } + let stat_file_metadata = !self + .op + .metakey() + .is_disjoint(Metakey::ContentLength | Metakey::LastModified); + // Return self at the first page. if ctx.token.is_empty() && !ctx.done { let path = build_rel_path(&self.core.root, &self.path); - let e = oio::Entry::new(&path, Metadata::new(EntryMode::DIR)); + let mut metadata = Metadata::new(EntryMode::DIR); + if stat_file_metadata { + let gdrive_file = stat_file(self.core.clone(), &path).await?; + if let Some(v) = gdrive_file.size { + metadata.set_content_length(v.parse::().map_err(|e| { + Error::new(ErrorKind::Unexpected, "parse content length").set_source(e) + })?); + } + if let Some(v) = gdrive_file.modified_time { + metadata.set_last_modified(v.parse::>().map_err( + |e| { + Error::new(ErrorKind::Unexpected, "parse last modified time") + .set_source(e) + }, + )?); + } + } + let e = oio::Entry::new(&path, metadata); ctx.entries.push_back(e); } @@ -90,14 +131,39 @@ impl oio::PageList for GdriveLister { EntryMode::FILE }; - let root = &self.core.root; let path = format!("{}{}", &self.path, file.name); - let normalized_path = build_rel_path(root, &path); // Update path cache with list result. - self.core.path_cache.insert(&path, &file.id).await; + // + // Only cache non-existent entry. When Google Drive converts a format, + // for example, Microsoft Powerpoint, they will be two entries. + // These two entries have the same file id. + if let Ok(None) = self.core.path_cache.get(&path).await { + self.core.path_cache.insert(&path, &file.id).await; + } + + let root = &self.core.root; + let normalized_path = build_rel_path(root, &path); + + let mut metadata = Metadata::new(file_type); + if stat_file_metadata { + let gdrive_file = stat_file(self.core.clone(), &normalized_path).await?; + if let Some(v) = gdrive_file.size { + metadata.set_content_length(v.parse::().map_err(|e| { + Error::new(ErrorKind::Unexpected, "parse content length").set_source(e) + })?); + } + if let Some(v) = gdrive_file.modified_time { + metadata.set_last_modified(v.parse::>().map_err( + |e| { + Error::new(ErrorKind::Unexpected, "parse last modified time") + .set_source(e) + }, + )?); + } + } - let entry = oio::Entry::new(&normalized_path, Metadata::new(file_type)); + let entry = oio::Entry::new(&normalized_path, metadata); ctx.entries.push_back(entry); }