files.rs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. use hex;
  2. use ring::digest::{Context, Digest, SHA256};
  3. use serde::{Deserialize, Serialize, Serializer};
  4. use sha2::{Digest as OtherDigest, Sha256}; // 确保导入 `Digest`
  5. use std::io::{self, Read};
  6. use std::path::{Path, PathBuf};
  7. use std::result::Result as new_Result;
  8. use std::{fs, option};
  9. use tauri::command;
  10. use std::time::{SystemTime, UNIX_EPOCH};
  11. // use std::result::Result;
  12. // use tauri::api::file::IntoInvokeHandler;
  13. #[derive(Debug, thiserror::Error)]
  14. pub enum Error {
  15. #[error(transparent)]
  16. Io(#[from] std::io::Error),
  17. }
  18. impl Serialize for Error {
  19. fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
  20. where
  21. S: Serializer,
  22. {
  23. serializer.serialize_str(self.to_string().as_ref())
  24. }
  25. }
  26. type Result<T> = std::result::Result<T, Error>;
  27. // 提取 /Users/sysadmin/code/rust_project/tauri-app/diff_source/node_modules 中,最后面的数据
  28. fn extract_last_value<'a>(path: &'a str, value: &'a str) -> &'a str {
  29. if let Some(index) = path.rfind(value) {
  30. let (content, _) = path.split_at(index);
  31. content.trim_end_matches('/')
  32. } else {
  33. path
  34. }
  35. }
  36. // 过滤
  37. fn filter_other_directory(path: &str, directories: &[&str]) -> bool {
  38. // let directories = ["node_modules", ".git", ".obsidian", ".DS_Store"];
  39. for directory in directories.iter() {
  40. if extract_last_value(path, directory) != path {
  41. return false;
  42. }
  43. }
  44. true
  45. }
  46. // fn read_files_in_directory(directory: &Path, files: &mut Vec<PathBuf>) -> Result<()> {
  47. // if let Ok(entries) = fs::read_dir(directory) {
  48. // for entry in entries {
  49. // if let Ok(entry) = entry {
  50. // let path = entry.path();
  51. // if path.is_file()
  52. // && filter_other_directory(
  53. // path.display().to_string().as_str(),
  54. // &[".obsidian", ".DS_Store"],
  55. // )
  56. // {
  57. // // 过滤文件
  58. // // TODO 后续加上需要过滤的文件
  59. // println!("59{}", path.display());
  60. // files.push(path.clone());
  61. // } else if path.is_dir()
  62. // && filter_other_directory(
  63. // path.display().to_string().as_str(),
  64. // &["node_modules", ".git", ".obsidian", ".DS_Store"],
  65. // )
  66. // {
  67. // // 过滤 目录
  68. // // println!("{}", path.display());
  69. // read_files_in_directory(&path, files)?;
  70. // }
  71. // }
  72. // }
  73. // }
  74. // Ok(())
  75. // }
  76. #[derive(Debug, Deserialize, Serialize)]
  77. pub enum FileSizeCategory {
  78. Huge, // 4GB+
  79. VeryLarge, // 1GB to 4GB-
  80. Large, // 128MB to 1GB-
  81. Medium, // 1MB to 128MB-
  82. Small, // 16KB to 1MB-
  83. Tiny, // 1B to 16KB-
  84. Empty, // Empty files or directories
  85. }
  86. #[derive(Debug, Deserialize, Serialize)]
  87. pub struct FileInfo {
  88. pub path: Option<String>,
  89. pub checkbox_all: Option<bool>,
  90. pub add_type: Option<String>,
  91. pub pass_type: Option<String>,
  92. // pub checked_size_values: Option<Vec<String>>, // 假设值类型为 String,具体类型视情况调整
  93. pub checked_size_values: Option<Vec<FileSizeCategory>>, // 使用正确的类型
  94. pub checkbox_size_all: Option<bool>,
  95. pub checked_type_values: Option<Vec<String>>, // 同上
  96. pub time: Option<String>,
  97. pub id: Option<u32>,
  98. pub progress: Option<f32>,
  99. pub types: Option<Vec<String>>,
  100. }
  101. #[command]
  102. pub fn get_all_directory(file_info: FileInfo) -> Result<Vec<PathBuf>> {
  103. let mut files = Vec::new();
  104. if let Some(ref path) = file_info.path {
  105. println!("Processing directory: {}", path);
  106. let directory = Path::new(path);
  107. // 确保 read_files_in_directory 能返回一个 Result<(), Error>
  108. read_files_in_directory(
  109. directory,
  110. &mut files,
  111. &file_info.checked_size_values,
  112. &file_info.types,
  113. )?;
  114. Ok(files)
  115. } else {
  116. // 当没有提供路径时返回错误
  117. // Err(Error::new(std::io::ErrorKind::NotFound, "No path provided"))
  118. Ok(files)
  119. }
  120. }
  121. // #[command]
  122. // fn getFileType(file_path: String) -> Option<String> {
  123. // let path = Path::new(&file_path);
  124. // path.extension()
  125. // .and_then(|ext| ext.to_str())
  126. // .map(|ext| ext.to_lowercase())
  127. // }
  128. #[command]
  129. pub fn get_file_type(file_path: &str) -> Option<&str> {
  130. let path = Path::new(file_path);
  131. path.extension().and_then(|ext| ext.to_str())
  132. }
  133. #[command]
  134. pub fn get_file_type_by_path(file_path: String) -> Result<String> {
  135. if let Some(file_type) = get_file_type(&file_path) {
  136. Ok(file_type.to_string())
  137. } else {
  138. Ok("Unknown file type".to_string())
  139. }
  140. }
  141. fn read_files_in_directory(
  142. dir: &Path,
  143. files: &mut Vec<PathBuf>,
  144. filters: &Option<Vec<FileSizeCategory>>,
  145. types: &Option<Vec<String>>,
  146. ) -> Result<()> {
  147. if dir.is_dir() {
  148. for entry in fs::read_dir(dir)? {
  149. let entry = entry?;
  150. let path = entry.path();
  151. if path.is_dir() {
  152. read_files_in_directory(&path, files, filters, types)?;
  153. } else {
  154. if let Ok(metadata) = fs::metadata(&path) {
  155. let size = metadata.len();
  156. let size_matches =
  157. filters.is_none() || file_size_matches(size, filters.as_ref().unwrap());
  158. let type_matches =
  159. types.is_none() || file_type_matches(&path, types.as_ref().unwrap());
  160. if size_matches && type_matches {
  161. files.push(path);
  162. }
  163. }
  164. }
  165. }
  166. }
  167. Ok(())
  168. }
  169. /* fn file_size_matches(size: u64, categories: &Vec<FileSizeCategory>) -> bool {
  170. categories.iter().any(|category| match category {
  171. FileSizeCategory::Huge => size >= 4294967296,
  172. FileSizeCategory::VeryLarge => size >= 1073741824 && size < 4294967296,
  173. FileSizeCategory::Large => size >= 134217728 && size < 1073741823,
  174. FileSizeCategory::Medium => size >= 1048576 && size < 134217728,
  175. FileSizeCategory::Small => size >= 16384 && size < 1048576,
  176. FileSizeCategory::Tiny => size >= 1 && size < 16384,
  177. FileSizeCategory::Empty => size == 0,
  178. })
  179. } */
  180. /// Determines if the given size matches any of the specified categories.
  181. fn file_size_matches(size: u64, categories: &Vec<FileSizeCategory>) -> bool {
  182. use FileSizeCategory::*;
  183. categories.iter().any(|category| match category {
  184. Huge => size >= 4_294_967_296,
  185. VeryLarge => (1_073_741_824..4_294_967_296).contains(&size),
  186. Large => (134_217_728..1_073_741_824).contains(&size),
  187. Medium => (1_048_576..134_217_728).contains(&size),
  188. Small => (16_384..1_048_576).contains(&size),
  189. Tiny => (1..16_384).contains(&size),
  190. Empty => size == 0,
  191. })
  192. }
  193. fn file_type_matches(path: &Path, types: &Vec<String>) -> bool {
  194. if let Some(ext) = path.extension() {
  195. if let Some(ext_str) = ext.to_str() {
  196. return types.iter().any(|type_str| type_str == ext_str);
  197. }
  198. }
  199. false
  200. }
  201. #[command]
  202. pub fn calculate_file_hash(file_path: String) -> Result<String> {
  203. // 使用 `?` 代替 `.expect` 来优雅地处理错误
  204. let file_bytes = fs::read(file_path)?;
  205. // 初始化 SHA256 哈希上下文
  206. let mut hasher = Sha256::new();
  207. hasher.update(&file_bytes);
  208. // 完成哈希计算
  209. let result = hasher.finalize();
  210. // 将结果转换为十六进制字符串
  211. let hash = hex::encode(result);
  212. Ok(hash)
  213. }
  214. #[derive(Debug, Serialize, Deserialize)]
  215. pub struct FileInfos {
  216. file_path: PathBuf,
  217. file_name: Option<String>,
  218. file_type: Option<String>,
  219. file_size: u64,
  220. modified_time: Option<u64>, // 时间戳形式
  221. }
  222. #[command]
  223. pub fn get_file_info(file_path: String) -> Result<FileInfos> {
  224. let path = Path::new(&file_path);
  225. // 正确地处理错误
  226. let metadata = fs::metadata(&path)?;
  227. // 获取文件修改时间
  228. let modified_time = metadata.modified().ok()
  229. .and_then(|t| t.duration_since(UNIX_EPOCH).ok())
  230. .map(|d| d.as_secs());
  231. // 构造FileInfo结构
  232. let file_info = FileInfos {
  233. file_path: path.to_path_buf(),
  234. file_name: path.file_name().and_then(|name| name.to_str()).map(|name| name.to_string()),
  235. file_type: get_file_type(&file_path).map(|t| t.to_string()),
  236. file_size: metadata.len(),
  237. modified_time,
  238. };
  239. Ok(file_info)
  240. }