1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
use crate::prelude::*;
/// Verify content of a [`Source`] matches its torrent piece hashes.
#[injectable]
pub(crate) struct ContentVerifier {
verify_options: Ref<VerifyOptions>,
torrents: Ref<TorrentFileProvider>,
}
impl ContentVerifier {
/// Verify the source content matches the torrent hash.
///
/// - Skips entirely when `no_hash_check` is set
/// - Downloads the source `.torrent`, caching it via [`TorrentFileProvider`]
/// - Delegates piece hashing to [`TorrentVerifier`]
///
/// Returns `Ok(None)` if the content matches or the check is skipped.
/// Returns `Ok(Some(SourceIssue))` on a hash mismatch.
pub(crate) async fn execute(
&self,
source: &Source,
) -> Result<Option<SourceIssue>, Failure<VerifyAction>> {
if self.verify_options.no_hash_check {
debug!("{} hash check due to settings", "Skipped".bold());
return Ok(None);
}
trace!("Fetching torrent file for {}", source.torrent.id);
let torrent_path = self
.torrents
.get(source.torrent.id)
.await
.map_err(Failure::wrap(VerifyAction::GetSourceTorrent))?;
trace!(
"{} torrent hash against {}",
"Checking".bold(),
source.directory.display()
);
TorrentVerifier::execute(&torrent_path, &source.directory)
.await
.map_err(Failure::wrap(VerifyAction::VerifyHash))
}
}