summaryrefslogtreecommitdiff
path: root/crates/utils/sha1_hash
diff options
context:
space:
mode:
Diffstat (limited to 'crates/utils/sha1_hash')
-rw-r--r--crates/utils/sha1_hash/Cargo.toml9
-rw-r--r--crates/utils/sha1_hash/res/story.txt48
-rw-r--r--crates/utils/sha1_hash/res/story_crlf.sha11
-rw-r--r--crates/utils/sha1_hash/res/story_lf.sha11
-rw-r--r--crates/utils/sha1_hash/src/lib.rs257
5 files changed, 0 insertions, 316 deletions
diff --git a/crates/utils/sha1_hash/Cargo.toml b/crates/utils/sha1_hash/Cargo.toml
deleted file mode 100644
index e206efd..0000000
--- a/crates/utils/sha1_hash/Cargo.toml
+++ /dev/null
@@ -1,9 +0,0 @@
-[package]
-name = "sha1_hash"
-edition = "2024"
-version.workspace = true
-
-[dependencies]
-tokio = { version = "1.48", features = ["full"] }
-sha1 = "0.10"
-futures = "0.3"
diff --git a/crates/utils/sha1_hash/res/story.txt b/crates/utils/sha1_hash/res/story.txt
deleted file mode 100644
index a91f467..0000000
--- a/crates/utils/sha1_hash/res/story.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-魏曹者,程序员也,发稀甚于代码。
-忽接神秘电话曰:
-"贺君中彩,得长生之赐。"
-魏曹冷笑曰:"吾命尚不及下版之期。"
-
-翌日果得U盘。
-接入电脑,弹窗示曰:
-"点此确认,即获永生。"
-魏曹径点"永拒"。
-
-三月后,U盘自格其盘。
-进度条滞于九九。
-客服电话已成空号。
-魏曹乃知身可不死,然体内癌细胞亦得不灭。
-
-遂谒主请辞。
-主曰:"巧甚,公司正欲优化。"
-魏曹曰:"吾不死。"
-主目骤亮:"则可007至司闭。"
-
-魏曹始试诸死法。
-坠楼,卧医三月,账单令其愿死。
-饮鸩,肝肾永损,然终不得死。
-终决卧轨。
-
-择高铁最速者。
-司机探头曰:"兄台,吾亦不死身也。"
-"此车已碾如君者二十人矣。"
-
-二人遂坐轨畔对饮。
-司机曰:"知最讽者何?"
-"吾等永存,而所爱者皆逝矣。"
-
-魏曹忽得系统提示:
-"侦得用户消极求生,将启工模。"
-自是无日不毕KPI,否则遍尝绝症之苦。
-
-是日对镜整寿衣。
-忽见顶生一丝乌发。
-泫然泣下,此兆示其将复活一轮回。
-
---- 忽忆DeepSeek尝作Footer曰:
-"文成而Hash1验,若星河之固。"
-遂取哈希值校之,
-字符流转如天河倒泻,
-终得"e3b0c44298fc1c14"之数。
-然文末数字竟阙如残月,
-方知此篇亦遭永劫轮回。
diff --git a/crates/utils/sha1_hash/res/story_crlf.sha1 b/crates/utils/sha1_hash/res/story_crlf.sha1
deleted file mode 100644
index bc8ad25..0000000
--- a/crates/utils/sha1_hash/res/story_crlf.sha1
+++ /dev/null
@@ -1 +0,0 @@
-40c1d848d8d6a14b9403ee022f2b28dabb3b3a71
diff --git a/crates/utils/sha1_hash/res/story_lf.sha1 b/crates/utils/sha1_hash/res/story_lf.sha1
deleted file mode 100644
index c2e3213..0000000
--- a/crates/utils/sha1_hash/res/story_lf.sha1
+++ /dev/null
@@ -1 +0,0 @@
-6838aca280112635a2cbf93440f4c04212f58ee8
diff --git a/crates/utils/sha1_hash/src/lib.rs b/crates/utils/sha1_hash/src/lib.rs
deleted file mode 100644
index 96a7897..0000000
--- a/crates/utils/sha1_hash/src/lib.rs
+++ /dev/null
@@ -1,257 +0,0 @@
-use sha1::{Digest, Sha1};
-use std::path::{Path, PathBuf};
-use std::sync::Arc;
-use tokio::fs::File;
-use tokio::io::{AsyncReadExt, BufReader};
-use tokio::task;
-
-/// # Struct - Sha1Result
-///
-/// Records SHA1 calculation results, including the file path and hash value
-#[derive(Debug, Clone)]
-pub struct Sha1Result {
- pub file_path: PathBuf,
- pub hash: String,
-}
-
-/// Calc SHA1 hash of a string
-pub fn calc_sha1_string<S: AsRef<str>>(input: S) -> String {
- let mut hasher = Sha1::new();
- hasher.update(input.as_ref().as_bytes());
- let hash_result = hasher.finalize();
-
- hash_result
- .iter()
- .map(|b| format!("{:02x}", b))
- .collect::<String>()
-}
-
-/// Calc SHA1 hash of a single file
-pub async fn calc_sha1<P: AsRef<Path>>(
- path: P,
- buffer_size: usize,
-) -> Result<Sha1Result, Box<dyn std::error::Error + Send + Sync>> {
- let file_path = path.as_ref().to_string_lossy().to_string();
-
- // Open file asynchronously
- let file = File::open(&path).await?;
- let mut reader = BufReader::with_capacity(buffer_size, file);
- let mut hasher = Sha1::new();
- let mut buffer = vec![0u8; buffer_size];
-
- // Read file in chunks and update hash asynchronously
- loop {
- let n = reader.read(&mut buffer).await?;
- if n == 0 {
- break;
- }
- hasher.update(&buffer[..n]);
- }
-
- let hash_result = hasher.finalize();
-
- // Convert to hex string
- let hash_hex = hash_result
- .iter()
- .map(|b| format!("{:02x}", b))
- .collect::<String>();
-
- Ok(Sha1Result {
- file_path: file_path.into(),
- hash: hash_hex,
- })
-}
-
-/// Calc SHA1 hashes for multiple files using multi-threading
-pub async fn calc_sha1_multi<P, I>(
- paths: I,
- buffer_size: usize,
-) -> Result<Vec<Sha1Result>, Box<dyn std::error::Error + Send + Sync>>
-where
- P: AsRef<Path> + Send + Sync + 'static,
- I: IntoIterator<Item = P>,
-{
- let buffer_size = Arc::new(buffer_size);
-
- // Collect all file paths
- let file_paths: Vec<P> = paths.into_iter().collect();
-
- if file_paths.is_empty() {
- return Ok(Vec::new());
- }
-
- // Create tasks for each file
- let tasks: Vec<_> = file_paths
- .into_iter()
- .map(|path| {
- let buffer_size = Arc::clone(&buffer_size);
- task::spawn(async move { calc_sha1(path, *buffer_size).await })
- })
- .collect();
-
- // Execute tasks with concurrency limit using join_all
- let results: Vec<Result<Sha1Result, Box<dyn std::error::Error + Send + Sync>>> =
- futures::future::join_all(tasks)
- .await
- .into_iter()
- .map(|task_result| match task_result {
- Ok(Ok(calc_result)) => Ok(calc_result),
- Ok(Err(e)) => Err(e),
- Err(e) => Err(Box::new(e) as Box<dyn std::error::Error + Send + Sync>),
- })
- .collect();
-
- // Check for any errors and collect successful results
- let mut successful_results = Vec::new();
- for result in results {
- match result {
- Ok(success) => successful_results.push(success),
- Err(e) => return Err(e),
- }
- }
-
- Ok(successful_results)
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use std::fs;
-
- #[test]
- fn test_sha1_string() {
- let test_string = "Hello, SHA1!";
- let hash = calc_sha1_string(test_string);
-
- let expected_hash = "de1c3daadc6f0f1626f4cf56c03e05a1e5d7b187";
-
- assert_eq!(
- hash, expected_hash,
- "SHA1 hash should be consistent for same input"
- );
- }
-
- #[test]
- fn test_sha1_string_empty() {
- let hash = calc_sha1_string("");
-
- // SHA1 of empty string is "da39a3ee5e6b4b0d3255bfef95601890afd80709"
- let expected_empty_hash = "da39a3ee5e6b4b0d3255bfef95601890afd80709";
- assert_eq!(
- hash, expected_empty_hash,
- "SHA1 hash mismatch for empty string"
- );
- }
-
- #[tokio::test]
- async fn test_sha1_accuracy() {
- // Test file path relative to the crate root
- let test_file_path = "res/story.txt";
- // Choose expected hash file based on platform
- let expected_hash_path = if cfg!(windows) {
- "res/story_crlf.sha1"
- } else {
- "res/story_lf.sha1"
- };
-
- // Calculate SHA1 hash
- let result = calc_sha1(test_file_path, 8192)
- .await
- .expect("Failed to calculate SHA1");
-
- // Read expected hash from file
- let expected_hash = fs::read_to_string(expected_hash_path)
- .expect("Failed to read expected hash file")
- .trim()
- .to_string();
-
- // Verify the calculated hash matches expected hash
- assert_eq!(
- result.hash, expected_hash,
- "SHA1 hash mismatch for test file"
- );
-
- println!("Test file: {}", result.file_path.display());
- println!("Calculated hash: {}", result.hash);
- println!("Expected hash: {}", expected_hash);
- println!(
- "Platform: {}",
- if cfg!(windows) {
- "Windows"
- } else {
- "Unix/Linux"
- }
- );
- }
-
- #[tokio::test]
- async fn test_sha1_empty_file() {
- // Create a temporary empty file for testing
- let temp_file = "test_empty.txt";
- fs::write(temp_file, "").expect("Failed to create empty test file");
-
- let result = calc_sha1(temp_file, 4096)
- .await
- .expect("Failed to calculate SHA1 for empty file");
-
- // SHA1 of empty string is "da39a3ee5e6b4b0d3255bfef95601890afd80709"
- let expected_empty_hash = "da39a3ee5e6b4b0d3255bfef95601890afd80709";
- assert_eq!(
- result.hash, expected_empty_hash,
- "SHA1 hash mismatch for empty file"
- );
-
- // Clean up
- fs::remove_file(temp_file).expect("Failed to remove temporary test file");
- }
-
- #[tokio::test]
- async fn test_sha1_simple_text() {
- // Create a temporary file with simple text
- let temp_file = "test_simple.txt";
- let test_content = "Hello, SHA1!";
- fs::write(temp_file, test_content).expect("Failed to create simple test file");
-
- let result = calc_sha1(temp_file, 4096)
- .await
- .expect("Failed to calculate SHA1 for simple text");
-
- // Note: This test just verifies that the function works without errors
- // The actual hash value is not critical for this test
-
- println!("Simple text test - Calculated hash: {}", result.hash);
-
- // Clean up
- fs::remove_file(temp_file).expect("Failed to remove temporary test file");
- }
-
- #[tokio::test]
- async fn test_sha1_multi_files() {
- // Test multiple files calculation
- let test_files = vec!["res/story.txt"];
-
- let results = calc_sha1_multi(test_files, 8192)
- .await
- .expect("Failed to calculate SHA1 for multiple files");
-
- assert_eq!(results.len(), 1, "Should have calculated hash for 1 file");
-
- // Choose expected hash file based on platform
- let expected_hash_path = if cfg!(windows) {
- "res/story_crlf.sha1"
- } else {
- "res/story_lf.sha1"
- };
-
- // Read expected hash from file
- let expected_hash = fs::read_to_string(expected_hash_path)
- .expect("Failed to read expected hash file")
- .trim()
- .to_string();
-
- assert_eq!(
- results[0].hash, expected_hash,
- "SHA1 hash mismatch in multi-file test"
- );
- }
-}