1use 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)]
10pub enum OpsError {
12 #[error("Lock acquisition failed: {0}")]
15 LockAcquisition(PathBuf),
16
17 #[error("Build error {0}")]
19 BuildError(String),
20
21 #[error("Hub error {0}")]
23 HubError(String),
24
25 #[error("I/O error {0}")]
27 IoError(#[from] std::io::Error),
28
29 #[error("Request error {0}")]
31 RequestError(#[from] reqwest::Error),
32}
33
34pub(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)) .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}