@@ -5,23 +5,29 @@ use std::path::{Path, PathBuf};
55use chrono:: Utc ;
66use derive_more:: AsRef ;
77use serde:: { Deserialize , Serialize , de:: DeserializeOwned } ;
8+ use sha2:: { Digest , Sha256 } ;
89use tokio:: fs;
10+ use tokio_stream:: StreamExt ;
11+ use tokio_util:: io:: ReaderStream ;
912use url:: Url ;
1013
1114pub use trim:: TrimConfig ;
1215
1316/// SHA256 digest of cache content.
14- #[ derive( Debug , Clone , Serialize , Deserialize , AsRef ) ]
15- pub struct Digest ( String ) ;
17+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , AsRef ) ]
18+ pub struct HexDigest ( String ) ;
1619
17- impl Digest {
20+ impl HexDigest {
1821 pub fn new ( data : & [ u8 ] ) -> Self {
1922 Self ( hex:: encode ( data) )
2023 }
2124}
2225
26+ #[ derive( Debug , Clone , Copy ) ]
27+ pub struct Asset < ' a > ( pub & ' a Path , pub & ' a HexDigest ) ;
28+
2329pub trait CachedAsset {
24- fn paths ( & self ) -> Vec < & Path > ;
30+ fn assets ( & self ) -> Vec < Asset < ' _ > > ;
2531}
2632
2733#[ derive( Debug , Clone , Serialize , Deserialize ) ]
@@ -51,10 +57,14 @@ impl FileCache {
5157 let state: CacheState < T > = serde_json:: from_slice ( & bytes) . ok ( ) ?;
5258
5359 if let CacheState :: Ok ( ref asset) = state {
54- let any_missing = asset. paths ( ) . iter ( ) . any ( |p| !p. exists ( ) ) ;
55- if any_missing {
56- // If any of the asset's files are missing, treat the cache as invalid.
57- return None ;
60+ for Asset ( path, digest) in asset. assets ( ) {
61+ // Check if we can open the file
62+ let file = fs:: File :: open ( path) . await . ok ( ) ?;
63+
64+ // Check if the file content matches the expected digest
65+ if hash_file ( file) . await ? != * digest {
66+ return None ;
67+ }
5868 }
5969 }
6070
@@ -90,7 +100,7 @@ impl FileCache {
90100 . join ( format ! ( "{hash}.json" ) )
91101 }
92102
93- pub fn blob_path ( & self , digest : & Digest , ext : & str ) -> PathBuf {
103+ pub fn blob_path ( & self , digest : & HexDigest , ext : & str ) -> PathBuf {
94104 let hash = digest. as_ref ( ) ;
95105
96106 blob_dir_from_root ( & self . root )
@@ -113,3 +123,15 @@ impl FileCache {
113123pub fn blob_dir_from_root ( root : & Path ) -> PathBuf {
114124 root. join ( "blobs" )
115125}
126+
127+ async fn hash_file ( file : fs:: File ) -> Option < HexDigest > {
128+ let mut stream = ReaderStream :: new ( file) ;
129+ let mut hasher = Sha256 :: new ( ) ;
130+
131+ while let Some ( item) = stream. next ( ) . await {
132+ let chunk = item. ok ( ) ?;
133+ hasher. update ( & chunk) ;
134+ }
135+
136+ Some ( HexDigest :: new ( & hasher. finalize ( ) ) )
137+ }
0 commit comments