11use cc_server_kit:: prelude:: * ;
22use cc_server_kit:: salvo:: http:: HttpRange ;
3- use dashmap:: DashMap ;
43use fs_change_notifier:: * ;
54use headers:: {
65 AcceptRanges , ContentLength , ContentRange , ContentType , ETag , HeaderMapExt , IfMatch , IfModifiedSince , IfNoneMatch ,
@@ -10,8 +9,10 @@ use salvo::fs::NamedFile;
109use salvo:: http:: header:: { CONTENT_DISPOSITION , CONTENT_ENCODING , CONTENT_TYPE , IF_NONE_MATCH , RANGE } ;
1110use salvo:: http:: { HeaderMap , HeaderValue } ;
1211use std:: cmp;
12+ use std:: collections:: HashMap ;
1313use std:: path:: { Path , PathBuf } ;
1414use std:: sync:: Arc ;
15+ use tokio:: sync:: Mutex ;
1516
1617const CHUNK_SIZE : u64 = 1024 * 1024 ;
1718
@@ -196,22 +197,113 @@ impl CachedFile {
196197 }
197198}
198199
200+ /// Request given file either from in-memory cacher or from disk.
201+ pub async fn send_file (
202+ cacher : & Option < Arc < Mutex < CacheMap > > > ,
203+ req : & mut Request ,
204+ depot : & mut Depot ,
205+ res : & mut Response ,
206+ filename : & str ,
207+ path : & Path ,
208+ ) -> MResult < ( ) > {
209+ use salvo:: Writer ;
210+
211+ if let Some ( cacher) = cacher. as_ref ( ) {
212+ {
213+ let guard = cacher. lock ( ) . await ;
214+ if let Ok ( Some ( cached) ) = guard. fetch ( path) {
215+ cached. send ( req. headers ( ) , res) . await ;
216+ return Ok ( ( ) ) ;
217+ }
218+ }
219+ let length = tokio:: fs:: metadata ( path)
220+ . await
221+ . map_err ( |e| ServerError :: from_private ( e) . with_404 ( ) ) ?
222+ . len ( ) ;
223+ if length > 16 * 1024 * 1024 {
224+ file_upload ! ( path. to_path_buf( ) , filename. to_string( ) )
225+ . write ( req, depot, res)
226+ . await ;
227+ } else {
228+ let cached = CachedFile :: construct_from ( filename, path, length) . await ?;
229+ {
230+ let mut guard = cacher. lock ( ) . await ;
231+ guard. upsert ( path, cached. clone ( ) ) ?;
232+ }
233+ cached. send ( req. headers ( ) , res) . await ;
234+ }
235+ } else {
236+ file_upload ! ( path. to_path_buf( ) , filename. to_string( ) )
237+ . write ( req, depot, res)
238+ . await ;
239+ }
240+ Ok ( ( ) )
241+ }
242+
243+ /// Request given HTML page either from in-memory cacher or from disk.
244+ pub async fn send_html (
245+ cacher : & Option < Arc < Mutex < CacheMap > > > ,
246+ req : & mut Request ,
247+ depot : & mut Depot ,
248+ res : & mut Response ,
249+ filename : & str ,
250+ path : & Path ,
251+ ) -> MResult < ( ) > {
252+ use salvo:: Writer ;
253+
254+ if let Some ( cacher) = cacher. as_ref ( ) {
255+ let cached = {
256+ let guard = cacher. lock ( ) . await ;
257+ guard. fetch ( path)
258+ } ;
259+ if let Ok ( Some ( cached) ) = cached {
260+ let site = String :: from_utf8_lossy_owned ( cached. bytes ) ;
261+ html ! ( site) . unwrap ( ) . write ( req, depot, res) . await ;
262+ return Ok ( ( ) ) ;
263+ }
264+ let length = tokio:: fs:: metadata ( path)
265+ . await
266+ . map_err ( |e| ServerError :: from_private ( e) . with_404 ( ) ) ?
267+ . len ( ) ;
268+ if length > 16 * 1024 * 1024 {
269+ let site = tokio:: fs:: read_to_string ( path)
270+ . await
271+ . map_err ( |e| ServerError :: from_private ( e) . with_404 ( ) ) ?;
272+ html ! ( site) . unwrap ( ) . write ( req, depot, res) . await ;
273+ } else {
274+ let cached = CachedFile :: construct_from ( filename, path, length) . await ?;
275+ {
276+ let mut guard = cacher. lock ( ) . await ;
277+ guard. upsert ( path, cached. clone ( ) ) ?;
278+ }
279+ let site = String :: from_utf8_lossy_owned ( cached. bytes ) ;
280+ html ! ( site) . unwrap ( ) . write ( req, depot, res) . await ;
281+ }
282+ } else {
283+ let site = tokio:: fs:: read_to_string ( path)
284+ . await
285+ . map_err ( |e| ServerError :: from_private ( e) . with_404 ( ) ) ?;
286+ html ! ( site) . unwrap ( ) . write ( req, depot, res) . await ;
287+ }
288+ Ok ( ( ) )
289+ }
290+
199291/// In-memory cache implementation for files based on `DashMap`.
200- pub struct CacheMap ( DashMap < PathBuf , CachedFile > ) ;
292+ pub struct CacheMap ( HashMap < PathBuf , CachedFile > ) ;
201293
202294impl CacheMap {
203295 /// Create in-memory cache.
204- pub fn new ( ) -> Arc < Self > {
205- Arc :: new ( Self ( DashMap :: new ( ) ) )
296+ pub fn new ( ) -> Arc < Mutex < Self > > {
297+ Arc :: new ( Mutex :: new ( Self ( HashMap :: new ( ) ) ) )
206298 }
207299
208300 /// Clear cache.
209- pub fn clear ( & self ) {
301+ pub fn clear ( & mut self ) {
210302 self . 0 . clear ( ) ;
211303 }
212304
213305 /// Insert or update content by its path.
214- pub fn upsert ( & self , path : impl AsRef < Path > , content : CachedFile ) -> MResult < ( ) > {
306+ pub fn upsert ( & mut self , path : impl AsRef < Path > , content : CachedFile ) -> MResult < ( ) > {
215307 let path = std:: fs:: canonicalize ( path. as_ref ( ) ) . map_err ( ServerError :: from_private) ?;
216308 self . 0 . insert ( path, content) ;
217309 Ok ( ( ) )
@@ -220,19 +312,19 @@ impl CacheMap {
220312 /// Fetch content.
221313 pub fn fetch ( & self , path : impl AsRef < Path > ) -> MResult < Option < CachedFile > > {
222314 let path = std:: fs:: canonicalize ( path. as_ref ( ) ) . map_err ( ServerError :: from_private) ?;
223- Ok ( self . 0 . get ( & path) . map ( |r#ref| r#ref . value ( ) . clone ( ) ) )
315+ Ok ( self . 0 . get ( & path) . cloned ( ) )
224316 }
225317
226318 /// Remove content due to invalidation.
227- pub fn invalidate ( & self , path : impl AsRef < Path > ) -> MResult < ( ) > {
319+ pub fn invalidate ( & mut self , path : impl AsRef < Path > ) -> MResult < ( ) > {
228320 let path = std:: fs:: canonicalize ( path. as_ref ( ) ) . map_err ( ServerError :: from_private) ?;
229321 self . 0 . remove ( & path) ;
230322 Ok ( ( ) )
231323 }
232324}
233325
234326/// Cache invalidator runner.
235- pub async fn cache_runner ( path : impl AsRef < Path > , cache_map : Arc < CacheMap > ) -> MResult < ( ) > {
327+ pub async fn cache_runner ( path : impl AsRef < Path > , cache_map : Arc < Mutex < CacheMap > > ) -> MResult < ( ) > {
236328 let empty = std:: collections:: HashSet :: new ( ) ;
237329 loop {
238330 let ( mut wr, rx) = create_watcher ( |e| tracing:: error!( "{e:?}" ) ) . map_err ( |e| {
@@ -244,8 +336,11 @@ pub async fn cache_runner(path: impl AsRef<Path>, cache_map: Arc<CacheMap>) -> M
244336 . map_err ( ServerError :: from_private) ?;
245337
246338 let files = fetch_changed ( path. as_ref ( ) , rx, & empty) . await ;
247- for file in files {
248- cache_map. invalidate ( file) ?;
339+ {
340+ let mut guard = cache_map. lock ( ) . await ;
341+ for file in files {
342+ guard. invalidate ( file) ?;
343+ }
249344 }
250345 }
251346}
0 commit comments