models_cat/
utils.rs

1//! Some utility
2use reqwest::blocking;
3use sha2::{Digest, Sha256};
4use std::path::{Path, PathBuf};
5use std::sync::LazyLock;
6use std::{fs::File, io::Read};
7use thiserror::Error;
8
9#[derive(Debug, Error)]
10/// All errors the API can throw
11pub enum OpsError {
12    /// We failed to acquire lock for file `f`. Meaning
13    /// Someone else is writing/downloading said file
14    #[error("Lock acquisition failed: {0}")]
15    LockAcquisition(PathBuf),
16
17    /// Build error
18    #[error("Build error {0}")]
19    BuildError(String),
20
21    /// Hub error
22    #[error("Hub error {0}")]
23    HubError(String),
24
25    /// I/O Error
26    #[error("I/O error {0}")]
27    IoError(#[from] std::io::Error),
28
29    /// request error
30    #[error("Request error {0}")]
31    RequestError(#[from] reqwest::Error),
32}
33
34/// A static HTTP client for making blocking requests.
35///
36/// Uses a custom user agent and allows up to 10 redirects.
37/// The client is lazily initialized using `LazyLock` to ensure
38/// it is only created when first accessed.
39pub(crate) static BLOCKING_CLIENT: LazyLock<blocking::Client> = LazyLock::new(|| {
40    blocking::Client::builder()
41        .user_agent("curl/7.79.1")
42        .redirect(reqwest::redirect::Policy::limited(10)) // 自定义重定向次数
43        .build()
44        .expect("Failed to build reqwest client")
45});
46
47#[cfg(feature = "tokio")]
48pub(crate) static ASYNC_CLIENT: LazyLock<reqwest::Client> = LazyLock::new(|| {
49    reqwest::Client::builder()
50        .user_agent("curl/7.79.1")
51        .redirect(reqwest::redirect::Policy::limited(10))
52        .build()
53        .expect("Failed to build async reqwest client")
54});
55
56pub(crate) fn sha256(file_path: impl AsRef<Path>) -> Result<String, std::io::Error> {
57    let mut file = File::open(file_path)?;
58    let mut hasher = Sha256::new();
59    let mut buffer = [0; 1024 * 8];
60
61    loop {
62        let bytes_read = file.read(&mut buffer)?;
63        if bytes_read == 0 {
64            break;
65        }
66        hasher.update(&buffer[..bytes_read]);
67    }
68    Ok(format!("{:x}", hasher.finalize()))
69}
70
71#[cfg(test)]
72mod tests {
73    #[test]
74    fn test_sha256() {
75        let testfile = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/sha256-testfile.txt");
76        let sha256 = super::sha256(testfile).unwrap();
77        assert_eq!(
78            sha256,
79            "c2aeccc42d2a579c281daae7e464a14d747924159e28617ad01850f0dd1bd135"
80        );
81    }
82}