Skip to content

Commit

Permalink
feat: sort the folder file.
Browse files Browse the repository at this point in the history
  • Loading branch information
jaywcjlove committed Jul 29, 2024
1 parent ba62fcf commit e833f5b
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 75 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2018"
[dependencies]
warp = "0.3"
tokio = { version = "1", features = ["full"] }
colored = "2"
colored = "2" # 用于输出彩色日志
clap = "4.1" # 解析命令行参数
mime_guess = "2.0"
mime_guess = "2.0" # 用于猜测文件的 MIME 类型
tokio-stream = { version = "0.1", features = ["fs"] }
153 changes: 84 additions & 69 deletions src/file_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,85 +3,100 @@ use std::path::Path;
use tokio::fs;
use warp::Reply;
use std::sync::Arc;
use tokio_stream::wrappers::ReadDirStream;
use tokio_stream::StreamExt;
use mime_guess::mime;

pub async fn serve_files(
path: warp::path::Tail,
css_content: Arc<String>,
base_dir: Arc<String>,
enable_cors: bool,
path: warp::path::Tail,
css_content: Arc<String>,
base_dir: Arc<String>,
enable_cors: bool,
) -> Result<warp::reply::Response, Infallible> {
let path_str = path.as_str();
let path_str = path.as_str();

let full_path = Path::new(&**base_dir).join(path_str);
let full_path_clone = full_path.clone(); // 克隆 PathBuf
let full_path = Path::new(&**base_dir).join(path_str);
let full_path_clone = full_path.clone(); // 克隆 PathBuf

let response = if full_path.is_dir() {
match fs::read_dir(full_path).await {
Ok(mut entries) => {
let relative_path: String = Path::new(path_str).to_str().unwrap_or(&base_dir).to_string();

// 检查 relative_path 是否为空
let relative_path = if relative_path.is_empty() {
base_dir.to_string()
} else {
relative_path
};
let response = if full_path.is_dir() {
match fs::read_dir(full_path).await {
Ok(entries) => {

let mut list = String::new();
list.push_str("<meta content=\"width=device-width,initial-scale=1.0,minimum-scale=1.0,shrink-to-fit=no\" name=\"viewport\">");
list.push_str(&format!("<title>Files within {}</title>", relative_path));
list.push_str(&format!("<style>{}</style>", css_content));
list.push_str(&format!("<h1><i>Index of&nbsp;</i>{}</h1><ul>", relative_path));
let mut dir_stream = ReadDirStream::new(entries);
let mut entries_vec: Vec<_> = Vec::new();
while let Some(entry) = dir_stream.next().await {
match entry {
Ok(entry) => entries_vec.push(entry),
Err(e) => eprintln!("Error reading entry: {}", e),
}
}

// Sort the entries
entries_vec.sort_by(|a, b| a.file_name().cmp(&b.file_name()));
let relative_path: String = Path::new(path_str).to_str().unwrap_or(&base_dir).to_string();

// 检查 relative_path 是否为空
let relative_path = if relative_path.is_empty() {
base_dir.to_string()
} else {
relative_path
};

// 添加返回上一级目录的链接(如果不是根目录)
if !path_str.is_empty() {
let parent_path = Path::new(path_str).parent().unwrap_or(Path::new(&**base_dir)).to_str().unwrap();
list.push_str(&format!("<li><a class=\"folder\" href=\"/{}\">../</a></li>", parent_path));
}
let mut list = String::new();
list.push_str("<meta content=\"width=device-width,initial-scale=1.0,minimum-scale=1.0,shrink-to-fit=no\" name=\"viewport\">");
list.push_str(&format!("<title>Files within {}</title>", relative_path));
list.push_str(&format!("<style>{}</style>", css_content));
list.push_str(&format!("<h1><i>Index of&nbsp;</i>{}</h1><ul>", relative_path));

while let Some(entry) = entries.next_entry().await.unwrap() {
let file_name: String = entry.file_name().into_string().unwrap();
let entry_path: std::path::PathBuf = entry.path();
let relative_path: String = Path::new(path_str).join(&file_name).to_str().unwrap().to_string();
// 添加返回上一级目录的链接(如果不是根目录)
if !path_str.is_empty() {
let parent_path = Path::new(path_str).parent().unwrap_or(Path::new(&**base_dir)).to_str().unwrap();
list.push_str(&format!("<li><a class=\"folder\" href=\"/{}\">../</a></li>", parent_path));
}

if entry_path.is_dir() {
list.push_str(&format!("<li><a class=\"folder\" href=\"/{}\">{}/</a></li>", relative_path, file_name));
} else {
list.push_str(&format!("<li><a class=\"file\" href=\"/{}\">{}</a></li>", relative_path, file_name));
}
}
list.push_str("</ul>");
warp::reply::html(list).into_response()
}
Err(_) => {
let error_message: String = "Directory not found".to_string();
warp::reply::html(error_message).into_response()
}
}
} else {
match fs::read(full_path).await {
Ok(content) => {
let mime_type: mime::Mime = mime_guess::from_path(&full_path_clone).first_or_octet_stream();
if mime_type == mime::TEXT_HTML || mime_type == mime::TEXT_PLAIN || mime_type == mime::TEXT_CSS || mime_type == mime::TEXT_JAVASCRIPT {
let content_str = String::from_utf8_lossy(&content).to_string();
warp::reply::with_header(content_str, "Content-Type", mime_type.to_string()).into_response()
} else {
warp::reply::with_header(content, "Content-Type", mime_type.to_string()).into_response()
}
}
Err(_) => {
let error_message = "File not found".to_string();
warp::reply::html(error_message).into_response()
}
}
};
// 现在 entries_vec 包含了排序后的目录条目
for entry in entries_vec {
let file_name: String = entry.file_name().into_string().unwrap();
let entry_path: std::path::PathBuf = entry.path();
let relative_path: String = Path::new(path_str).join(&file_name).to_str().unwrap().to_string();
if entry_path.is_dir() {
list.push_str(&format!("<li><a class=\"folder\" href=\"/{}\">{}/</a></li>", relative_path, file_name));
} else {
list.push_str(&format!("<li><a class=\"file\" href=\"/{}\">{}</a></li>", relative_path, file_name));
}
}

let response = if enable_cors {
warp::reply::with_header(response, "Access-Control-Allow-Origin", "*").into_response()
} else {
response
};
list.push_str("</ul>");
warp::reply::html(list).into_response()
}
Err(_) => {
let error_message: String = "Directory not found".to_string();
warp::reply::html(error_message).into_response()
}
}
} else {
match fs::read(full_path).await {
Ok(content) => {
let mime_type: mime::Mime = mime_guess::from_path(&full_path_clone).first_or_octet_stream();
if mime_type == mime::TEXT_HTML || mime_type == mime::TEXT_PLAIN || mime_type == mime::TEXT_CSS || mime_type == mime::TEXT_JAVASCRIPT {
let content_str = String::from_utf8_lossy(&content).to_string();
warp::reply::with_header(content_str, "Content-Type", mime_type.to_string()).into_response()
} else {
warp::reply::with_header(content, "Content-Type", mime_type.to_string()).into_response()
}
}
Err(_) => {
let error_message = "File not found".to_string();
warp::reply::html(error_message).into_response()
}
}
};

Ok(response)
let response = if enable_cors {
warp::reply::with_header(response, "Access-Control-Allow-Origin", "*").into_response()
} else {
response
};

Ok(response)
}
17 changes: 13 additions & 4 deletions src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,26 @@ ul a:hover {
text-decoration: underline;
}

ul a:hover::before {
background: #89afd43d;
}

ul a::before {
display: inline-block;
vertical-align: middle;
margin-right: 10px;
width: 24px;
text-align: center;
line-height: 12px;
background: #f3f3f3;
border-radius: 6px;
width: 26px;
height: 26px;
display: inline-flex;
justify-content: center;
align-items: center;
transition: all .3s;
}

ul a.file::before {
content: url("data:image/svg+xml;utf8,<svg width='15' height='19' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M10 8C8.34 8 7 6.66 7 5V1H3c-1.1 0-2 .9-2 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V8h-4zM8 5c0 1.1.9 2 2 2h3.59L8 1.41V5zM3 0h5l7 7v9c0 1.66-1.34 3-3 3H3c-1.66 0-3-1.34-3-3V3c0-1.66 1.34-3 3-3z' fill='black'/></svg>");
content: url("data:image/svg+xml;utf8,<svg width='15' height='19' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M10 8C8.34 8 7 6.66 7 5V1H3c-1.1 0-2 .9-2 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V8h-4zM8 5c0 1.1.9 2 2 2h3.59L8 1.41V5zM3 0h5l7 7v9c0 1.66-1.34 3-3 3H3c-1.66 0-3-1.34-3-3V3c0-1.66 1.34-3 3-3z' fill='currentColor'/></svg>");
}

ul a.folder::before {
Expand Down

0 comments on commit e833f5b

Please sign in to comment.