|
@@ -1,5 +1,5 @@
|
|
|
use hex;
|
|
|
-use serde::{Deserialize, Serialize, Serializer};
|
|
|
+use serde::{Deserialize, Serialize};
|
|
|
use sha2::{Digest as OtherDigest, Sha256}; // 确保导入 `Digest`
|
|
|
use std::fs;
|
|
|
use std::path::{Path, PathBuf};
|
|
@@ -7,75 +7,6 @@ use std::time::UNIX_EPOCH;
|
|
|
use tauri::command;
|
|
|
extern crate trash;
|
|
|
|
|
|
-#[derive(Debug, thiserror::Error)]
|
|
|
-pub enum Error {
|
|
|
- #[error(transparent)]
|
|
|
- Io(#[from] std::io::Error),
|
|
|
-}
|
|
|
-
|
|
|
-impl Serialize for Error {
|
|
|
- fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
|
|
- where
|
|
|
- S: Serializer,
|
|
|
- {
|
|
|
- serializer.serialize_str(self.to_string().as_ref())
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-type Result<T> = std::result::Result<T, Error>;
|
|
|
-
|
|
|
-// 提取 /Users/sysadmin/code/rust_project/tauri-app/diff_source/node_modules 中,最后面的数据
|
|
|
-/* fn extract_last_value<'a>(path: &'a str, value: &'a str) -> &'a str {
|
|
|
- if let Some(index) = path.rfind(value) {
|
|
|
- let (content, _) = path.split_at(index);
|
|
|
- content.trim_end_matches('/')
|
|
|
- } else {
|
|
|
- path
|
|
|
- }
|
|
|
-} */
|
|
|
-
|
|
|
-// 过滤
|
|
|
-/* fn filter_other_directory(path: &str, directories: &[&str]) -> bool {
|
|
|
- // let directories = ["node_modules", ".git", ".obsidian", ".DS_Store"];
|
|
|
- for directory in directories.iter() {
|
|
|
- if extract_last_value(path, directory) != path {
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- true
|
|
|
-} */
|
|
|
-
|
|
|
-// fn read_files_in_directory(directory: &Path, files: &mut Vec<PathBuf>) -> Result<()> {
|
|
|
-// if let Ok(entries) = fs::read_dir(directory) {
|
|
|
-// for entry in entries {
|
|
|
-// if let Ok(entry) = entry {
|
|
|
-// let path = entry.path();
|
|
|
-// if path.is_file()
|
|
|
-// && filter_other_directory(
|
|
|
-// path.display().to_string().as_str(),
|
|
|
-// &[".obsidian", ".DS_Store"],
|
|
|
-// )
|
|
|
-// {
|
|
|
-// // 过滤文件
|
|
|
-// // TODO 后续加上需要过滤的文件
|
|
|
-// println!("59{}", path.display());
|
|
|
-// files.push(path.clone());
|
|
|
-// } else if path.is_dir()
|
|
|
-// && filter_other_directory(
|
|
|
-// path.display().to_string().as_str(),
|
|
|
-// &["node_modules", ".git", ".obsidian", ".DS_Store"],
|
|
|
-// )
|
|
|
-// {
|
|
|
-// // 过滤 目录
|
|
|
-// // println!("{}", path.display());
|
|
|
-// read_files_in_directory(&path, files)?;
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// Ok(())
|
|
|
-// }
|
|
|
-
|
|
|
#[derive(Debug, Deserialize, Serialize)]
|
|
|
pub enum FileSizeCategory {
|
|
|
Huge, // 4GB+
|
|
@@ -104,34 +35,23 @@ pub struct FileInfo {
|
|
|
}
|
|
|
|
|
|
#[command]
|
|
|
-pub fn get_all_directory(file_info: FileInfo) -> Result<Vec<PathBuf>> {
|
|
|
+pub fn get_all_directory(file_info: FileInfo) -> Vec<PathBuf> {
|
|
|
let mut files = Vec::new();
|
|
|
if let Some(ref path) = file_info.path {
|
|
|
println!("Processing directory: {}", path);
|
|
|
let directory = Path::new(path);
|
|
|
- // 确保 read_files_in_directory 能返回一个 Result<(), Error>
|
|
|
read_files_in_directory(
|
|
|
directory,
|
|
|
&mut files,
|
|
|
&file_info.checked_size_values,
|
|
|
&file_info.types,
|
|
|
- )?;
|
|
|
- Ok(files)
|
|
|
+ );
|
|
|
+ files
|
|
|
} else {
|
|
|
- // 当没有提供路径时返回错误
|
|
|
- // Err(Error::new(std::io::ErrorKind::NotFound, "No path provided"))
|
|
|
- Ok(files)
|
|
|
+ files
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// #[command]
|
|
|
-// fn getFileType(file_path: String) -> Option<String> {
|
|
|
-// let path = Path::new(&file_path);
|
|
|
-// path.extension()
|
|
|
-// .and_then(|ext| ext.to_str())
|
|
|
-// .map(|ext| ext.to_lowercase())
|
|
|
-// }
|
|
|
-
|
|
|
#[command]
|
|
|
pub fn get_file_type(file_path: &str) -> Option<&str> {
|
|
|
let path = Path::new(file_path);
|
|
@@ -139,11 +59,11 @@ pub fn get_file_type(file_path: &str) -> Option<&str> {
|
|
|
}
|
|
|
|
|
|
#[command]
|
|
|
-pub fn get_file_type_by_path(file_path: String) -> Result<String> {
|
|
|
+pub fn get_file_type_by_path(file_path: String) -> String {
|
|
|
if let Some(file_type) = get_file_type(&file_path) {
|
|
|
- Ok(file_type.to_string())
|
|
|
+ file_type.to_string()
|
|
|
} else {
|
|
|
- Ok("Unknown file type".to_string())
|
|
|
+ "Unknown file type".to_string()
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -152,43 +72,36 @@ fn read_files_in_directory(
|
|
|
files: &mut Vec<PathBuf>,
|
|
|
filters: &Option<Vec<FileSizeCategory>>,
|
|
|
types: &Option<Vec<String>>,
|
|
|
-) -> Result<()> {
|
|
|
+) {
|
|
|
if dir.is_dir() {
|
|
|
- for entry in fs::read_dir(dir)? {
|
|
|
- let entry = entry?;
|
|
|
- let path = entry.path();
|
|
|
- if path.is_dir() {
|
|
|
- read_files_in_directory(&path, files, filters, types)?;
|
|
|
- } else {
|
|
|
- if let Ok(metadata) = fs::metadata(&path) {
|
|
|
- let size = metadata.len();
|
|
|
- let size_matches =
|
|
|
- filters.is_none() || file_size_matches(size, filters.as_ref().unwrap());
|
|
|
- let type_matches =
|
|
|
- types.is_none() || file_type_matches(&path, types.as_ref().unwrap());
|
|
|
-
|
|
|
- if size_matches && type_matches {
|
|
|
- files.push(path);
|
|
|
+ // 尝试读取目录,忽略错误
|
|
|
+ if let Ok(entries) = fs::read_dir(dir) {
|
|
|
+ for entry in entries {
|
|
|
+ if let Ok(entry) = entry {
|
|
|
+ let path = entry.path();
|
|
|
+ if path.is_dir() {
|
|
|
+ // 递归调用,忽略错误
|
|
|
+ read_files_in_directory(&path, files, filters, types);
|
|
|
+ } else {
|
|
|
+ // 尝试获取文件元数据,忽略错误
|
|
|
+ if let Ok(metadata) = fs::metadata(&path) {
|
|
|
+ let size = metadata.len();
|
|
|
+ let size_matches = filters.is_none()
|
|
|
+ || file_size_matches(size, filters.as_ref().unwrap());
|
|
|
+ let type_matches = types.is_none()
|
|
|
+ || file_type_matches(&path, types.as_ref().unwrap());
|
|
|
+
|
|
|
+ if size_matches && type_matches {
|
|
|
+ files.push(path);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- Ok(())
|
|
|
}
|
|
|
|
|
|
-/* fn file_size_matches(size: u64, categories: &Vec<FileSizeCategory>) -> bool {
|
|
|
- categories.iter().any(|category| match category {
|
|
|
- FileSizeCategory::Huge => size >= 4294967296,
|
|
|
- FileSizeCategory::VeryLarge => size >= 1073741824 && size < 4294967296,
|
|
|
- FileSizeCategory::Large => size >= 134217728 && size < 1073741823,
|
|
|
- FileSizeCategory::Medium => size >= 1048576 && size < 134217728,
|
|
|
- FileSizeCategory::Small => size >= 16384 && size < 1048576,
|
|
|
- FileSizeCategory::Tiny => size >= 1 && size < 16384,
|
|
|
- FileSizeCategory::Empty => size == 0,
|
|
|
- })
|
|
|
-} */
|
|
|
-/// Determines if the given size matches any of the specified categories.
|
|
|
fn file_size_matches(size: u64, categories: &Vec<FileSizeCategory>) -> bool {
|
|
|
use FileSizeCategory::*;
|
|
|
categories.iter().any(|category| match category {
|
|
@@ -212,9 +125,8 @@ fn file_type_matches(path: &Path, types: &Vec<String>) -> bool {
|
|
|
}
|
|
|
|
|
|
#[command]
|
|
|
-pub fn calculate_file_hash(file_path: String) -> Result<String> {
|
|
|
- // 使用 `?` 代替 `.expect` 来优雅地处理错误
|
|
|
- let file_bytes = fs::read(file_path)?;
|
|
|
+pub fn calculate_file_hash(file_path: String) -> String {
|
|
|
+ let file_bytes = fs::read(file_path).expect("Failed to read file");
|
|
|
|
|
|
// 初始化 SHA256 哈希上下文
|
|
|
let mut hasher = Sha256::new();
|
|
@@ -224,8 +136,7 @@ pub fn calculate_file_hash(file_path: String) -> Result<String> {
|
|
|
let result = hasher.finalize();
|
|
|
|
|
|
// 将结果转换为十六进制字符串
|
|
|
- let hash = hex::encode(result);
|
|
|
- Ok(hash)
|
|
|
+ hex::encode(result)
|
|
|
}
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
@@ -239,11 +150,24 @@ pub struct FileInfos {
|
|
|
}
|
|
|
|
|
|
#[command]
|
|
|
-pub fn get_file_info(file_path: String) -> Result<FileInfos> {
|
|
|
+pub fn get_file_info(file_path: String) -> FileInfos {
|
|
|
let path = Path::new(&file_path);
|
|
|
|
|
|
- // 正确地处理错误
|
|
|
- let metadata = fs::metadata(&path)?;
|
|
|
+ // 使用 match 来处理可能的错误
|
|
|
+ let metadata = match fs::metadata(&path) {
|
|
|
+ Ok(meta) => meta,
|
|
|
+ Err(_) => {
|
|
|
+ return FileInfos {
|
|
|
+ // 在这里处理错误,可能是返回默认的 FileInfos
|
|
|
+ file_path: path.to_path_buf(),
|
|
|
+ file_name: None,
|
|
|
+ file_type: None,
|
|
|
+ file_size: 0,
|
|
|
+ modified_time: None,
|
|
|
+ creation_time: None,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
// 获取文件修改时间
|
|
|
let modified_time = metadata
|
|
@@ -259,20 +183,18 @@ pub fn get_file_info(file_path: String) -> Result<FileInfos> {
|
|
|
.and_then(|t| t.duration_since(UNIX_EPOCH).ok())
|
|
|
.map(|d| d.as_secs());
|
|
|
|
|
|
- // 构造FileInfo结构
|
|
|
- let file_info = FileInfos {
|
|
|
+ // 构造 FileInfo 结构
|
|
|
+ FileInfos {
|
|
|
file_path: path.to_path_buf(),
|
|
|
file_name: path
|
|
|
.file_name()
|
|
|
.and_then(|name| name.to_str())
|
|
|
.map(|name| name.to_string()),
|
|
|
- file_type: get_file_type(&file_path).map(|t| t.to_string()),
|
|
|
+ file_type: get_file_type(&file_path).map(|t| t.to_string()), // 确保 get_file_type 也不返回 Result 或 Option
|
|
|
file_size: metadata.len(),
|
|
|
modified_time,
|
|
|
creation_time: accessed_time,
|
|
|
- };
|
|
|
-
|
|
|
- Ok(file_info)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
@@ -300,3 +222,24 @@ pub fn mv_file_to_trash(file_path: String) -> RequestMvFile {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+#[derive(Debug, Deserialize, Serialize)]
|
|
|
+enum AppError {
|
|
|
+ DataDirNotFound,
|
|
|
+ Other(String),
|
|
|
+}
|
|
|
+
|
|
|
+impl std::fmt::Display for AppError {
|
|
|
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
+ match *self {
|
|
|
+ AppError::DataDirNotFound => write!(f, "Application data directory not found"),
|
|
|
+ AppError::Other(ref err) => write!(f, "Error: {}", err),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[command]
|
|
|
+pub fn get_app_data_dir() -> String {
|
|
|
+ std::env::var("MY_APP_DATA_DIR")
|
|
|
+ .unwrap_or_else(|_| "Environment variable for app data directory not set".to_string())
|
|
|
+}
|