]> OzVa Git service - ozva-cloud/commitdiff
feat: sort by type first, then sort by name/mtime/size (#241)
authorsigoden <sigoden@gmail.com>
Tue, 4 Jul 2023 02:10:48 +0000 (10:10 +0800)
committerGitHub <noreply@github.com>
Tue, 4 Jul 2023 02:10:48 +0000 (10:10 +0800)
src/server.rs

index 71af7469e70a79ecf7f5849a9fef938500dea82b..64b3acd363408f43bd2f9bcac7ccbc4e5d94c94e 100644 (file)
@@ -26,12 +26,13 @@ use hyper::header::{
 use hyper::{Body, Method, StatusCode, Uri};
 use serde::Serialize;
 use std::borrow::Cow;
+use std::cmp::Ordering;
 use std::collections::HashMap;
 use std::fs::Metadata;
 use std::io::SeekFrom;
 use std::net::SocketAddr;
 use std::path::{Path, PathBuf};
-use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::atomic::{self, AtomicBool};
 use std::sync::Arc;
 use std::time::SystemTime;
 use tokio::fs::File;
@@ -495,7 +496,7 @@ impl Server {
                     let mut it = WalkDir::new(&dir).into_iter();
                     it.next();
                     while let Some(Ok(entry)) = it.next() {
-                        if !running.load(Ordering::SeqCst) {
+                        if !running.load(atomic::Ordering::SeqCst) {
                             break;
                         }
                         let entry_path = entry.path();
@@ -931,13 +932,28 @@ impl Server {
     ) -> Result<()> {
         if let Some(sort) = query_params.get("sort") {
             if sort == "name" {
-                paths.sort_by(|v1, v2| {
-                    alphanumeric_sort::compare_str(v1.name.to_lowercase(), v2.name.to_lowercase())
+                paths.sort_by(|v1, v2| match v1.path_type.cmp(&v2.path_type) {
+                    Ordering::Equal => {
+                        alphanumeric_sort::compare_str(v1.name.clone(), v2.name.clone())
+                    }
+                    v => v,
                 })
             } else if sort == "mtime" {
-                paths.sort_by(|v1, v2| v1.mtime.cmp(&v2.mtime))
+                paths.sort_by(|v1, v2| match v1.path_type.cmp(&v2.path_type) {
+                    Ordering::Equal => v1.mtime.cmp(&v2.mtime),
+                    v => v,
+                })
             } else if sort == "size" {
-                paths.sort_by(|v1, v2| v1.size.unwrap_or(0).cmp(&v2.size.unwrap_or(0)))
+                paths.sort_by(|v1, v2| match v1.path_type.cmp(&v2.path_type) {
+                    Ordering::Equal => {
+                        if v1.is_dir() {
+                            alphanumeric_sort::compare_str(v1.name.clone(), v2.name.clone())
+                        } else {
+                            v1.size.unwrap_or(0).cmp(&v2.size.unwrap_or(0))
+                        }
+                    }
+                    v => v,
+                })
             }
             if query_params
                 .get("order")
@@ -1254,7 +1270,7 @@ impl PathItem {
     }
 }
 
-#[derive(Debug, Serialize, Eq, PartialEq, Ord, PartialOrd)]
+#[derive(Debug, Serialize, Eq, PartialEq)]
 enum PathType {
     Dir,
     SymlinkDir,
@@ -1262,6 +1278,24 @@ enum PathType {
     SymlinkFile,
 }
 
+impl Ord for PathType {
+    fn cmp(&self, other: &Self) -> Ordering {
+        let to_value = |t: &Self| -> u8 {
+            if matches!(t, Self::Dir | Self::SymlinkDir) {
+                0
+            } else {
+                1
+            }
+        };
+        to_value(self).cmp(&to_value(other))
+    }
+}
+impl PartialOrd for PathType {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
 fn to_timestamp(time: &SystemTime) -> u64 {
     time.duration_since(SystemTime::UNIX_EPOCH)
         .unwrap_or_default()
@@ -1336,7 +1370,7 @@ async fn zip_dir<W: AsyncWrite + Unpin>(
             let mut it = WalkDir::new(&dir).into_iter();
             it.next();
             while let Some(Ok(entry)) = it.next() {
-                if !running.load(Ordering::SeqCst) {
+                if !running.load(atomic::Ordering::SeqCst) {
                     break;
                 }
                 let entry_path = entry.path();