11use std:: collections:: HashMap ;
22use std:: io;
3+ use std:: path:: Path ;
34use std:: sync:: { Arc , LazyLock , OnceLock } ;
45use std:: time:: Duration ;
56
@@ -18,12 +19,12 @@ use url::Url;
1819
1920pub use self :: card:: Card ;
2021pub use self :: image:: Image ;
22+ use crate :: cache:: { self , CacheState , CachedAsset , FileCache } ;
2123use crate :: message:: Source ;
2224use crate :: server:: Server ;
2325use crate :: target:: { self , TargetRef } ;
2426use crate :: { config, isupport} ;
2527
26- mod cache;
2728pub mod card;
2829pub mod image;
2930
@@ -123,6 +124,15 @@ impl Preview {
123124 }
124125}
125126
127+ impl CachedAsset for Preview {
128+ fn paths ( & self ) -> Vec < & Path > {
129+ match self {
130+ Preview :: Card ( c) => vec ! [ c. image. path. as_path( ) ] ,
131+ Preview :: Image ( i) => vec ! [ i. path. as_path( ) ] ,
132+ }
133+ }
134+ }
135+
126136#[ derive( Debug ) ]
127137pub enum State {
128138 Loading ,
@@ -134,31 +144,31 @@ pub async fn load(
134144 url : Url ,
135145 client : Arc < reqwest:: Client > ,
136146 config : config:: Preview ,
147+ cache : Arc < FileCache > ,
137148) -> Result < Preview , LoadError > {
138149 let cache_key_url = canonical_preview_url ( & url) ;
139150
140151 if !config. is_enabled ( url. as_str ( ) ) {
141152 return Err ( LoadError :: Disabled ) ;
142153 }
143154
144- let result = if let Some ( state) =
145- cache:: load ( & cache_key_url, client. clone ( ) , & config) . await
146- {
155+ let result = if let Some ( state) = cache. load ( & cache_key_url) . await {
147156 match state {
148- cache :: State :: Ok ( preview) => Ok ( preview) ,
149- cache :: State :: Error => Err ( LoadError :: CachedFailed ) ,
157+ CacheState :: Ok ( preview) => Ok ( preview) ,
158+ CacheState :: Error => Err ( LoadError :: CachedFailed ) ,
150159 }
151160 } else {
152- match load_uncached ( url. clone ( ) , client, & config) . await {
161+ match load_uncached ( url. clone ( ) , client, & config, & cache ) . await {
153162 Ok ( preview) => {
154- cache:: save ( & cache_key_url, cache:: State :: Ok ( preview. clone ( ) ) )
163+ cache
164+ . save ( & cache_key_url, & CacheState :: Ok ( preview. clone ( ) ) )
155165 . await ;
156-
157166 Ok ( preview)
158167 }
159168 Err ( error) => {
160- cache:: save ( & cache_key_url, cache:: State :: Error ) . await ;
161-
169+ cache
170+ . save :: < Preview > ( & cache_key_url, & CacheState :: Error )
171+ . await ;
162172 Err ( error)
163173 }
164174 }
@@ -207,10 +217,11 @@ async fn load_uncached(
207217 url : Url ,
208218 client : Arc < reqwest:: Client > ,
209219 config : & config:: Preview ,
220+ cache : & FileCache ,
210221) -> Result < Preview , LoadError > {
211222 log:: trace!( "Loading preview for {url}" ) ;
212223
213- match fetch ( url. clone ( ) , client. clone ( ) , config) . await ? {
224+ match fetch ( url. clone ( ) , client. clone ( ) , config, cache ) . await ? {
214225 Fetched :: Image ( image) => Ok ( Preview :: Image ( image) ) ,
215226 Fetched :: Other ( bytes) => {
216227 let MetaTagProperties {
@@ -224,7 +235,7 @@ async fn load_uncached(
224235 image_url. ok_or ( LoadError :: MissingProperty ( "image" ) ) ?;
225236
226237 let Fetched :: Image ( image) =
227- fetch ( image_url, client, config) . await ?
238+ fetch ( image_url, client, config, cache ) . await ?
228239 else {
229240 return Err ( LoadError :: NotImage ) ;
230241 } ;
@@ -250,6 +261,7 @@ async fn fetch(
250261 url : Url ,
251262 client : Arc < reqwest:: Client > ,
252263 config : & config:: Preview ,
264+ cache : & FileCache ,
253265) -> Result < Fetched , LoadError > {
254266 // WARN: `concurrency` changes aren't picked up until app is relaunched
255267 let _permit = RATE_LIMIT
@@ -283,7 +295,7 @@ async fn fetch(
283295 }
284296
285297 // Store image to disk, we don't want to explode memory
286- let temp_path = cache:: download_path ( & url) ;
298+ let temp_path = cache. download_path ( & url) ;
287299
288300 if let Some ( parent) = temp_path. parent ( ) . filter ( |p| !p. exists ( ) ) {
289301 fs:: create_dir_all ( & parent) . await ?;
@@ -309,8 +321,9 @@ async fn fetch(
309321 written += chunk. len ( ) ;
310322 }
311323
312- let digest = image:: Digest :: new ( & hasher. finalize ( ) ) ;
313- let image_path = cache:: image_path ( & format, & digest) ;
324+ let digest = cache:: Digest :: new ( & hasher. finalize ( ) ) ;
325+ let image_path =
326+ cache. blob_path ( & digest, format. extensions_str ( ) [ 0 ] ) ;
314327
315328 if let Some ( parent) =
316329 image_path. parent ( ) . filter ( |p| !p. exists ( ) )
@@ -319,14 +332,11 @@ async fn fetch(
319332 }
320333
321334 fs:: rename ( & temp_path, & image_path) . await ?;
322- cache:: maybe_trim_image_cache (
323- written as u64 ,
324- config. request . image_cache . max_size_bytes ( ) ,
325- config. request . image_cache . trim_interval ,
326- image_path. clone ( ) ,
327- ) ;
328-
329- Ok :: < Image , LoadError > ( Image :: new ( format, url, digest) )
335+ cache. account_blob ( written as u64 , image_path. clone ( ) ) ;
336+
337+ Ok :: < Image , LoadError > ( Image :: new (
338+ format, url, digest, image_path,
339+ ) )
330340 }
331341 . await ;
332342
0 commit comments