walker_common/source/
file.rs1use crate::retrieve::RetrievedDigest;
2use anyhow::anyhow;
3use bytes::Bytes;
4use digest::Digest;
5use futures_util::try_join;
6use sha2::{Sha256, Sha512};
7use std::io::ErrorKind;
8use std::path::{Path, PathBuf};
9use url::Url;
10
11pub async fn read_optional(path: impl AsRef<Path>) -> Result<Option<String>, anyhow::Error> {
12 match tokio::fs::read_to_string(path).await {
13 Ok(data) => Ok(Some(data)),
14 Err(err) if err.kind() == ErrorKind::NotFound => Ok(None),
15 Err(err) => Err(err.into()),
16 }
17}
18
19pub fn to_path(url: &Url) -> Result<PathBuf, anyhow::Error> {
20 url.to_file_path()
21 .map_err(|()| anyhow!("Failed to convert URL to path: {url}"))
22}
23
24pub async fn read_sig_and_digests(
31 path: &Path,
32 data: &Bytes,
33) -> anyhow::Result<(
34 Option<String>,
35 Option<RetrievedDigest<Sha256>>,
36 Option<RetrievedDigest<Sha512>>,
37)> {
38 let (signature, sha256, sha512) = try_join!(
39 read_optional(format!("{}.asc", path.display())),
40 read_optional(format!("{}.sha256", path.display())),
41 read_optional(format!("{}.sha512", path.display())),
42 )?;
43
44 let sha256 = sha256
45 .and_then(|expected| expected.split(' ').next().map(ToString::to_string))
47 .map(|expected| {
48 let mut actual = Sha256::new();
49 actual.update(data);
50 RetrievedDigest::<Sha256> {
51 expected,
52 actual: actual.finalize(),
53 }
54 });
55
56 let sha512 = sha512
57 .and_then(|expected| expected.split(' ').next().map(ToString::to_string))
59 .map(|expected| {
60 let mut actual = Sha512::new();
61 actual.update(data);
62 RetrievedDigest::<Sha512> {
63 expected,
64 actual: actual.finalize(),
65 }
66 });
67
68 Ok((signature, sha256, sha512))
69}