]> OzVa Git service - ozva-cloud/commitdiff
refactor: improve code quality
authorsigoden <sigoden@gmail.com>
Mon, 30 May 2022 21:49:42 +0000 (05:49 +0800)
committersigoden <sigoden@gmail.com>
Mon, 30 May 2022 23:56:05 +0000 (07:56 +0800)
src/assets/index.html
src/assets/index.js
src/server.rs

index 6cb661484b63f2ff395e926fb27e93baca523b7f..f90ef828c3008f3f91a77f4be35afe2eccf1b42f 100644 (file)
@@ -4,7 +4,7 @@
 <head>
   <meta charset="utf-8" />
   <meta name="viewport" content="width=device-width" />
-  __SLOB__
+  __SLOT__
 </head>
 <body>
   <div class="head">
index e09838cc39492a38d2d4357900367c0cb7dd36cf..4da39b2b88ecbc91120337dc8a1f1b8922b8c715 100644 (file)
@@ -1,6 +1,6 @@
-var $toolbox, $tbody, $breadcrumb, $uploaders, $uploadControl;
-var uploaderIdx = 0;
-var baseDir;
+let $tbody, $uploaders;
+let uploaderIdx = 0;
+let baseDir;
 
 class Uploader {
   idx = 0;
@@ -12,8 +12,8 @@ class Uploader {
   }
 
   upload() {
-    var { file, idx } = this;
-    var url = getUrl(file.name);
+    const { file, idx } = this;
+    let url = getUrl(file.name);
     if (file.name == baseDir + ".zip") {
       url += "?unzip";
     }
@@ -24,35 +24,45 @@ class Uploader {
   </div>`);
     this.$elem = document.getElementById(`file${idx}`);
 
-    var ajax = new XMLHttpRequest();
+    const ajax = new XMLHttpRequest();
     ajax.upload.addEventListener("progress", e => this.progress(e), false);
-    ajax.addEventListener("load", e => this.complete(e), false);
-    ajax.addEventListener("error", e => this.fail(e), false);
-    ajax.addEventListener("abort", e => this.fail(e), false);
+    ajax.addEventListener("readystatechange", () => {
+      console.log(ajax.readyState, ajax.status)
+      if(ajax.readyState === 4) {
+        if (ajax.status == 200) {
+          this.complete();
+        } else {
+          this.fail();
+        }
+      }
+    })
+    ajax.addEventListener("error", () => this.fail(), false);
+    ajax.addEventListener("abort", () => this.fail(), false);
     ajax.open("PUT", url);
     ajax.send(file);
   }
 
   progress(event) {
-    var percent = (event.loaded / event.total) * 100;
+    const percent = (event.loaded / event.total) * 100;
     this.$elem.innerHTML = `${this.file.name} (${percent.toFixed(2)}%)`;
   }
 
-  complete(event) {
+  complete() {
     this.$elem.innerHTML = `${this.file.name}`;
   }
 
-  fail(event) {
+  fail() {
     this.$elem.innerHTML = `<strike>${this.file.name}</strike>`;
   }
 }
 
 function addBreadcrumb(value) {
-  var parts = value.split("/").filter(v => !!v);
-  var len = parts.length;
-  var path = "";
-  for (var i = 0; i < len; i++) {
-    var name = parts[i];
+  const $breadcrumb = document.querySelector(".breadcrumb");
+  const parts = value.split("/").filter(v => !!v);
+  const len = parts.length;
+  let path = "";
+  for (let i = 0; i < len; i++) {
+    const name = parts[i];
     if (i > 0) {
       path  += "/" + name;
     }
@@ -69,9 +79,9 @@ function addBreadcrumb(value) {
 }
 
 function addPath(file, index) {
-  var url = getUrl(file.name)
-  var actionDelete = "";
-  var actionDownload = "";
+  const url = getUrl(file.name)
+  let actionDelete = "";
+  let actionDownload = "";
   if (file.path_type.endsWith("Dir")) {
     actionDownload = `
     <div class="action-btn">
@@ -93,7 +103,7 @@ function addPath(file, index) {
       <svg width="16" height="16" fill="currentColor"viewBox="0 0 16 16"><path d="M6.854 7.146a.5.5 0 1 0-.708.708L7.293 9l-1.147 1.146a.5.5 0 0 0 .708.708L8 9.707l1.146 1.147a.5.5 0 0 0 .708-.708L8.707 9l1.147-1.146a.5.5 0 0 0-.708-.708L8 8.293 6.854 7.146z"/><path d="M14 14V4.5L9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2zM9.5 3A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h5.5v2z"/></svg>
     </div>`;
   }
-  var actionCell = `
+  let actionCell = `
   <td class="cell-actions">
     ${actionDownload}
     ${actionDelete}
@@ -112,21 +122,25 @@ ${actionCell}
 }
 
 async function deletePath(index) {
-  var file = DATA.paths[index];
+  const file = DATA.paths[index];
   if (!file) return;
 
-  var ajax = new XMLHttpRequest();
-  ajax.open("DELETE", getUrl(file.name));
-  ajax.addEventListener("readystatechange", function() {
-    if(ajax.readyState === 4 && ajax.status === 200) {
+  try {
+    const res = await fetch(getUrl(file.name), {
+      method: "DELETE",
+    });
+    if (res.status === 200) {
         document.getElementById(`addPath${index}`).remove();
+    } else {
+      throw new Error(await res.text())
     }
-  });
-  ajax.send();
+  } catch (err) {
+    alert(`Fail to delete ${file.name}, ${err.message}`);
+  }
 }
 
 function getUrl(name) {
-    var url = location.href.split('?')[0];
+    let url = location.href.split('?')[0];
     if (!url.endsWith("/")) url += "/";
     url += encodeURI(name);
     return url;
@@ -147,12 +161,12 @@ function getSvg(path_type) {
 
 function formatMtime(mtime) {
   if (!mtime) return ""
-  var date = new Date(mtime);
-  var year = date.getFullYear();
-  var month = padZero(date.getMonth() + 1, 2);
-  var day = padZero(date.getDate(), 2);
-  var hours = padZero(date.getHours(), 2);
-  var minutes = padZero(date.getMinutes(), 2);
+  const date = new Date(mtime);
+  const year = date.getFullYear();
+  const month = padZero(date.getMonth() + 1, 2);
+  const day = padZero(date.getDate(), 2);
+  const hours = padZero(date.getHours(), 2);
+  const minutes = padZero(date.getMinutes(), 2);
   return `${year}/${month}/${day} ${hours}:${minutes}`;
 }
 
@@ -162,17 +176,15 @@ function padZero(value, size) {
 
 function formatSize(size) {
   if (!size) return ""
-  var sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
+  const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
   if (size == 0) return '0 Byte';
-  var i = parseInt(Math.floor(Math.log(size) / Math.log(1024)));
+  const i = parseInt(Math.floor(Math.log(size) / Math.log(1024)));
   return Math.round(size / Math.pow(1024, i), 2) + ' ' + sizes[i];
 }
 
 
 function ready() {
-  $toolbox = document.querySelector(".toolbox");
   $tbody = document.querySelector(".main tbody");
-  $breadcrumb = document.querySelector(".breadcrumb");
   $uploaders = document.querySelector(".uploaders");
 
   addBreadcrumb(DATA.breadcrumb);
@@ -180,10 +192,10 @@ function ready() {
   if (!DATA.readonly) {
     document.querySelector(".upload-control").classList.remove(["hidden"]);
     document.getElementById("file").addEventListener("change", e => {
-      var files = e.target.files;
-      for (var file of files) {
+      const files = e.target.files;
+      for (let file of files) {
         uploaderIdx += 1;
-        var uploader = new Uploader(uploaderIdx, file);
+        const uploader = new Uploader(uploaderIdx, file);
         uploader.upload();
       }
     });
index 6a616caeb053574b5126e1b954acf29723ea7d40..d93ecba073061b0d083df3b65f298f9ee26122f8 100644 (file)
@@ -7,8 +7,8 @@ use async_zip::Compression;
 use futures::stream::StreamExt;
 use futures::TryStreamExt;
 use headers::{
-    AccessControlAllowHeaders, AccessControlAllowOrigin, ContentType, ETag, HeaderMapExt,
-    IfModifiedSince, IfNoneMatch, LastModified,
+    AccessControlAllowHeaders, AccessControlAllowOrigin, ContentType, ETag, HeaderMap,
+    HeaderMapExt, IfModifiedSince, IfNoneMatch, LastModified,
 };
 use hyper::header::{HeaderValue, ACCEPT, CONTENT_TYPE, ORIGIN, RANGE, WWW_AUTHENTICATE};
 use hyper::service::{make_service_fn, service_fn};
@@ -28,15 +28,6 @@ use tokio_util::io::{ReaderStream, StreamReader};
 type Request = hyper::Request<Body>;
 type Response = hyper::Response<Body>;
 
-macro_rules! status_code {
-    ($status:expr) => {
-        hyper::Response::builder()
-            .status($status)
-            .body($status.canonical_reason().unwrap_or_default().into())
-            .unwrap()
-    };
-}
-
 const INDEX_HTML: &str = include_str!("assets/index.html");
 const INDEX_CSS: &str = include_str!("assets/index.css");
 const INDEX_JS: &str = include_str!("assets/index.js");
@@ -76,11 +67,16 @@ impl InnerService {
         let method = req.method().clone();
         let uri = req.uri().clone();
         let cors = self.args.cors;
-        let mut res = self
-            .handle(req)
-            .await
-            .unwrap_or_else(|_| status_code!(StatusCode::INTERNAL_SERVER_ERROR));
+
+        let mut res = self.handle(req).await.unwrap_or_else(|e| {
+            let mut res = Response::default();
+            *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
+            *res.body_mut() = Body::from(e.to_string());
+            res
+        });
+
         info!(r#""{} {}" - {}"#, method, uri, res.status());
+
         if cors {
             add_cors(&mut res);
         }
@@ -88,74 +84,77 @@ impl InnerService {
     }
 
     pub async fn handle(self: Arc<Self>, req: Request) -> BoxResult<Response> {
-        if !self.auth_guard(&req).unwrap_or_default() {
-            let mut res = status_code!(StatusCode::UNAUTHORIZED);
-            res.headers_mut()
-                .insert(WWW_AUTHENTICATE, HeaderValue::from_static("Basic"));
+        let mut res = Response::default();
+
+        if !self.auth_guard(&req, &mut res) {
             return Ok(res);
         }
-        match *req.method() {
-            Method::GET => self.handle_static(req).await,
-            Method::PUT => {
-                if self.args.readonly {
-                    return Ok(status_code!(StatusCode::FORBIDDEN));
-                }
-                self.handle_upload(req).await
-            }
-            Method::OPTIONS => Ok(status_code!(StatusCode::NO_CONTENT)),
-            Method::DELETE => self.handle_delete(req).await,
-            _ => Ok(status_code!(StatusCode::NOT_FOUND)),
-        }
-    }
 
-    async fn handle_static(&self, req: Request) -> BoxResult<Response> {
-        let req_path = req.uri().path();
-        let path = match self.get_file_path(req_path)? {
-            Some(path) => path,
-            None => return Ok(status_code!(StatusCode::FORBIDDEN)),
+        let path = req.uri().path();
+
+        let filepath = match self.extract_path(path) {
+            Some(v) => v,
+            None => {
+                *res.status_mut() = StatusCode::FORBIDDEN;
+                return Ok(res);
+            }
         };
-        match fs::metadata(&path).await {
-            Ok(meta) => {
-                if meta.is_dir() {
-                    let req_query = req.uri().query().unwrap_or_default();
-                    if req_query == "zip" {
-                        return self.handle_send_dir_zip(path.as_path()).await;
-                    }
-                    if let Some(q) = req_query.strip_prefix("q=") {
-                        return self.handle_query_dir(path.as_path(), q).await;
-                    }
-                    self.handle_ls_dir(path.as_path(), true).await
-                } else {
-                    self.handle_send_file(&req, path.as_path()).await
-                }
+        let filepath = filepath.as_path();
+
+        let query = req.uri().query().unwrap_or_default();
+
+        let meta = fs::metadata(filepath).await.ok();
+        let is_miss = meta.is_none();
+        let is_dir = meta.map(|v| v.is_dir()).unwrap_or_default();
+
+        let readonly = self.args.readonly;
+
+        match *req.method() {
+            Method::GET if is_dir && query == "zip" => {
+                self.handle_zip_dir(filepath, &mut res).await?
             }
-            Err(_) => {
-                if req_path.ends_with('/') {
-                    self.handle_ls_dir(path.as_path(), false).await
-                } else {
-                    Ok(status_code!(StatusCode::NOT_FOUND))
-                }
+            Method::GET if is_dir && query.starts_with("q=") => {
+                self.handle_query_dir(filepath, &query[3..], &mut res)
+                    .await?
+            }
+            Method::GET if !is_dir && !is_miss => {
+                self.handle_send_file(filepath, req.headers(), &mut res)
+                    .await?
             }
+            Method::GET if is_miss && path.ends_with('/') => {
+                self.handle_ls_dir(filepath, false, &mut res).await?
+            }
+            Method::GET => self.handle_ls_dir(filepath, true, &mut res).await?,
+            Method::OPTIONS => *res.status_mut() = StatusCode::NO_CONTENT,
+            Method::PUT if readonly => *res.status_mut() = StatusCode::FORBIDDEN,
+            Method::PUT => self.handle_upload(filepath, req, &mut res).await?,
+            Method::DELETE if !is_miss && readonly => *res.status_mut() = StatusCode::FORBIDDEN,
+            Method::DELETE if !is_miss => self.handle_delete(filepath, is_dir).await?,
+            _ => *res.status_mut() = StatusCode::NOT_FOUND,
         }
-    }
 
-    async fn handle_upload(&self, mut req: Request) -> BoxResult<Response> {
-        let forbidden = status_code!(StatusCode::FORBIDDEN);
-        let path = match self.get_file_path(req.uri().path())? {
-            Some(path) => path,
-            None => return Ok(forbidden),
-        };
+        Ok(res)
+    }
 
-        match path.parent() {
+    async fn handle_upload(
+        &self,
+        path: &Path,
+        mut req: Request,
+        res: &mut Response,
+    ) -> BoxResult<()> {
+        let ensure_parent = match path.parent() {
             Some(parent) => match fs::metadata(parent).await {
-                Ok(meta) => {
-                    if !meta.is_dir() {
-                        return Ok(forbidden);
-                    }
+                Ok(meta) => meta.is_dir(),
+                Err(_) => {
+                    fs::create_dir_all(parent).await?;
+                    true
                 }
-                Err(_) => fs::create_dir_all(parent).await?,
             },
-            None => return Ok(forbidden),
+            None => false,
+        };
+        if !ensure_parent {
+            *res.status_mut() = StatusCode::FORBIDDEN;
+            return Ok(());
         }
 
         let mut file = fs::File::create(&path).await?;
@@ -194,39 +193,37 @@ impl InnerService {
             fs::remove_file(&path).await?;
         }
 
-        return Ok(status_code!(StatusCode::OK));
+        Ok(())
     }
 
-    async fn handle_delete(&self, req: Request) -> BoxResult<Response> {
-        let path = match self.get_file_path(req.uri().path())? {
-            Some(path) => path,
-            None => return Ok(status_code!(StatusCode::FORBIDDEN)),
-        };
-
-        let meta = fs::metadata(&path).await?;
-        if meta.is_file() {
-            fs::remove_file(path).await?;
-        } else {
-            fs::remove_dir_all(path).await?;
+    async fn handle_delete(&self, path: &Path, is_dir: bool) -> BoxResult<()> {
+        match is_dir {
+            true => fs::remove_dir_all(path).await?,
+            false => fs::remove_file(path).await?,
         }
-        Ok(status_code!(StatusCode::OK))
+        Ok(())
     }
 
-    async fn handle_ls_dir(&self, path: &Path, exist: bool) -> BoxResult<Response> {
+    async fn handle_ls_dir(&self, path: &Path, exist: bool, res: &mut Response) -> BoxResult<()> {
         let mut paths: Vec<PathItem> = vec![];
         if exist {
             let mut rd = fs::read_dir(path).await?;
             while let Some(entry) = rd.next_entry().await? {
                 let entry_path = entry.path();
-                if let Ok(item) = get_path_item(entry_path, path.to_path_buf()).await {
+                if let Ok(item) = to_pathitem(entry_path, path.to_path_buf()).await {
                     paths.push(item);
                 }
             }
         }
-        self.send_index(path, paths)
+        self.send_index(path, paths, res)
     }
 
-    async fn handle_query_dir(&self, path: &Path, q: &str) -> BoxResult<Response> {
+    async fn handle_query_dir(
+        &self,
+        path: &Path,
+        query: &str,
+        res: &mut Response,
+    ) -> BoxResult<()> {
         let mut paths: Vec<PathItem> = vec![];
         let mut walkdir = WalkDir::new(path);
         while let Some(entry) = walkdir.next().await {
@@ -235,22 +232,22 @@ impl InnerService {
                     .file_name()
                     .to_string_lossy()
                     .to_lowercase()
-                    .contains(&q.to_lowercase())
+                    .contains(&query.to_lowercase())
                 {
                     continue;
                 }
                 if fs::symlink_metadata(entry.path()).await.is_err() {
                     continue;
                 }
-                if let Ok(item) = get_path_item(entry.path(), path.to_path_buf()).await {
+                if let Ok(item) = to_pathitem(entry.path(), path.to_path_buf()).await {
                     paths.push(item);
                 }
             }
         }
-        self.send_index(path, paths)
+        self.send_index(path, paths, res)
     }
 
-    async fn handle_send_dir_zip(&self, path: &Path) -> BoxResult<Response> {
+    async fn handle_zip_dir(&self, path: &Path, res: &mut Response) -> BoxResult<()> {
         let (mut writer, reader) = tokio::io::duplex(BUF_SIZE);
         let path = path.to_owned();
         tokio::spawn(async move {
@@ -259,16 +256,20 @@ impl InnerService {
             }
         });
         let stream = ReaderStream::new(reader);
-        let body = Body::wrap_stream(stream);
-        Ok(Response::new(body))
+        *res.body_mut() = Body::wrap_stream(stream);
+        Ok(())
     }
 
-    async fn handle_send_file(&self, req: &Request, path: &Path) -> BoxResult<Response> {
+    async fn handle_send_file(
+        &self,
+        path: &Path,
+        headers: &HeaderMap<HeaderValue>,
+        res: &mut Response,
+    ) -> BoxResult<()> {
         let (file, meta) = tokio::join!(fs::File::open(path), fs::metadata(path),);
         let (file, meta) = (file?, meta?);
-        let mut res = Response::default();
         if let Ok(mtime) = meta.modified() {
-            let timestamp = get_timestamp(&mtime);
+            let timestamp = to_timestamp(&mtime);
             let size = meta.len();
             let etag = format!(r#""{}-{}""#, timestamp, size)
                 .parse::<ETag>()
@@ -276,10 +277,9 @@ impl InnerService {
             let last_modified = LastModified::from(mtime);
             let fresh = {
                 // `If-None-Match` takes presedence over `If-Modified-Since`.
-                if let Some(if_none_match) = req.headers().typed_get::<IfNoneMatch>() {
+                if let Some(if_none_match) = headers.typed_get::<IfNoneMatch>() {
                     !if_none_match.precondition_passes(&etag)
-                } else if let Some(if_modified_since) = req.headers().typed_get::<IfModifiedSince>()
-                {
+                } else if let Some(if_modified_since) = headers.typed_get::<IfModifiedSince>() {
                     !if_modified_since.is_modified(mtime)
                 } else {
                     false
@@ -289,7 +289,7 @@ impl InnerService {
             res.headers_mut().typed_insert(etag);
             if fresh {
                 *res.status_mut() = StatusCode::NOT_MODIFIED;
-                return Ok(res);
+                return Ok(());
             }
         }
         if let Some(mime) = mime_guess::from_path(&path).first() {
@@ -298,10 +298,16 @@ impl InnerService {
         let stream = FramedRead::new(file, BytesCodec::new());
         let body = Body::wrap_stream(stream);
         *res.body_mut() = body;
-        Ok(res)
+
+        Ok(())
     }
 
-    fn send_index(&self, path: &Path, mut paths: Vec<PathItem>) -> BoxResult<Response> {
+    fn send_index(
+        &self,
+        path: &Path,
+        mut paths: Vec<PathItem>,
+        res: &mut Response,
+    ) -> BoxResult<()> {
         paths.sort_unstable();
         let rel_path = match self.args.path.parent() {
             Some(p) => path.strip_prefix(p).unwrap(),
@@ -314,10 +320,10 @@ impl InnerService {
         };
         let data = serde_json::to_string(&data).unwrap();
         let output = INDEX_HTML.replace(
-            "__SLOB__",
+            "__SLOT__",
             &format!(
                 r#"
-<title>Files in {} - Duf/</title>
+<title>Files in {}/ - Duf</title>
 <style>{}</style>
 <script>var DATA = {}; {}</script>
 "#,
@@ -327,44 +333,51 @@ impl InnerService {
                 INDEX_JS
             ),
         );
+        *res.body_mut() = output.into();
 
-        Ok(Response::new(output.into()))
+        Ok(())
     }
 
-    fn auth_guard(&self, req: &Request) -> BoxResult<bool> {
-        if let Some(auth) = &self.args.auth {
-            if let Some(value) = req.headers().get("Authorization") {
-                let value = value.to_str()?;
-                let value = if value.contains("Basic ") {
-                    &value[6..]
-                } else {
-                    return Ok(false);
-                };
-                let value = base64::decode(value)?;
-                let value = std::str::from_utf8(&value)?;
-                return Ok(value == auth);
-            } else {
-                if self.args.no_auth_read && req.method() == Method::GET {
-                    return Ok(true);
-                }
-                return Ok(false);
+    fn auth_guard(&self, req: &Request, res: &mut Response) -> bool {
+        let pass = {
+            match &self.args.auth {
+                None => true,
+                Some(auth) => match req.headers().get("Authorization") {
+                    Some(value) => match value.to_str().ok().map(|v| {
+                        let mut it = v.split(' ');
+                        (it.next(), it.next())
+                    }) {
+                        Some((Some("Basic "), Some(tail))) => base64::decode(tail)
+                            .ok()
+                            .and_then(|v| String::from_utf8(v).ok())
+                            .map(|v| v.as_str() == auth)
+                            .unwrap_or_default(),
+                        _ => false,
+                    },
+                    None => self.args.no_auth_read && req.method() == Method::GET,
+                },
             }
+        };
+        if !pass {
+            *res.status_mut() = StatusCode::UNAUTHORIZED;
+            res.headers_mut()
+                .insert(WWW_AUTHENTICATE, HeaderValue::from_static("Basic"));
         }
-        Ok(true)
+        pass
     }
 
-    fn get_file_path(&self, path: &str) -> BoxResult<Option<PathBuf>> {
-        let decoded_path = percent_decode(path[1..].as_bytes()).decode_utf8()?;
+    fn extract_path(&self, path: &str) -> Option<PathBuf> {
+        let decoded_path = percent_decode(path[1..].as_bytes()).decode_utf8().ok()?;
         let slashes_switched = if cfg!(windows) {
             decoded_path.replace('/', "\\")
         } else {
             decoded_path.into_owned()
         };
-        let path = self.args.path.join(&slashes_switched);
-        if path.starts_with(&self.args.path) {
-            Ok(Some(path))
+        let full_path = self.args.path.join(&slashes_switched);
+        if full_path.starts_with(&self.args.path) {
+            Some(full_path)
         } else {
-            Ok(None)
+            None
         }
     }
 }
@@ -392,7 +405,7 @@ enum PathType {
     SymlinkFile,
 }
 
-async fn get_path_item<P: AsRef<Path>>(path: P, base_path: P) -> BoxResult<PathItem> {
+async fn to_pathitem<P: AsRef<Path>>(path: P, base_path: P) -> BoxResult<PathItem> {
     let path = path.as_ref();
     let rel_path = path.strip_prefix(base_path).unwrap();
     let (meta, meta2) = tokio::join!(fs::metadata(&path), fs::symlink_metadata(&path));
@@ -405,7 +418,7 @@ async fn get_path_item<P: AsRef<Path>>(path: P, base_path: P) -> BoxResult<PathI
         (true, false) => PathType::SymlinkFile,
         (false, false) => PathType::File,
     };
-    let mtime = get_timestamp(&meta.modified()?);
+    let mtime = to_timestamp(&meta.modified()?);
     let size = match path_type {
         PathType::Dir | PathType::SymlinkDir => None,
         PathType::File | PathType::SymlinkFile => Some(meta.len()),
@@ -419,7 +432,7 @@ async fn get_path_item<P: AsRef<Path>>(path: P, base_path: P) -> BoxResult<PathI
     })
 }
 
-fn get_timestamp(time: &SystemTime) -> u64 {
+fn to_timestamp(time: &SystemTime) -> u64 {
     time.duration_since(SystemTime::UNIX_EPOCH)
         .unwrap()
         .as_millis() as u64