1+ // Copyright 2018-2025 the Deno authors. MIT license.
2+
3+ use std:: borrow:: Cow ;
4+
5+ use url:: Url ;
6+
7+ use super :: FetchCachedError ;
8+ use super :: FetchCachedErrorKind ;
9+ use super :: FetchCachedNoFollowError ;
10+ // Removed unused import
11+ use super :: FileOrRedirect ;
12+ use super :: File ;
13+ use super :: TooManyRedirectsError ;
14+ use crate :: Checksum ;
15+
16+ pub trait AsyncFileFetcherExt {
17+ /// Fetch cached remote file asynchronously.
18+ ///
19+ /// This is a recursive operation if source file has redirections.
20+ async fn fetch_cached_async (
21+ & self ,
22+ url : & Url ,
23+ redirect_limit : i64 ,
24+ ) -> Result < Option < File > , FetchCachedError > ;
25+
26+ /// Fetches from cache without following redirects asynchronously.
27+ async fn fetch_cached_no_follow_async (
28+ & self ,
29+ url : & Url ,
30+ maybe_checksum : Option < Checksum < ' _ > > ,
31+ ) -> Result < Option < FileOrRedirect > , FetchCachedNoFollowError > ;
32+ }
33+
34+ #[ cfg( feature = "async-module-loading" ) ]
35+ impl < TBlobStore , TSys , THttpClient > AsyncFileFetcherExt for super :: FileFetcher < TBlobStore , TSys , THttpClient >
36+ where
37+ TBlobStore : super :: BlobStore + Clone ,
38+ TSys : crate :: sync:: MaybeSend + crate :: sync:: MaybeSync + sys_traits:: FsRead + sys_traits:: SystemTimeNow + Clone ,
39+ THttpClient : super :: HttpClient + Clone ,
40+ {
41+ async fn fetch_cached_async (
42+ & self ,
43+ url : & Url ,
44+ redirect_limit : i64 ,
45+ ) -> Result < Option < File > , FetchCachedError > {
46+ if !matches ! ( url. scheme( ) , "http" | "https" ) {
47+ return Ok ( None ) ;
48+ }
49+
50+ let mut url = Cow :: Borrowed ( url) ;
51+ for _ in 0 ..=redirect_limit {
52+ match self . fetch_cached_no_follow_async ( & url, None ) . await ? {
53+ Some ( FileOrRedirect :: File ( file) ) => {
54+ return Ok ( Some ( file) ) ;
55+ }
56+ Some ( FileOrRedirect :: Redirect ( redirect_url) ) => {
57+ url = Cow :: Owned ( redirect_url) ;
58+ }
59+ None => {
60+ return Ok ( None ) ;
61+ }
62+ }
63+ }
64+ Err (
65+ FetchCachedErrorKind :: TooManyRedirects ( TooManyRedirectsError (
66+ url. into_owned ( ) ,
67+ ) )
68+ . into_box ( ) ,
69+ )
70+ }
71+
72+ async fn fetch_cached_no_follow_async (
73+ & self ,
74+ url : & Url ,
75+ maybe_checksum : Option < Checksum < ' _ > > ,
76+ ) -> Result < Option < FileOrRedirect > , FetchCachedNoFollowError > {
77+ // We yield to the event loop briefly to allow other tasks to run
78+ tokio:: task:: yield_now ( ) . await ;
79+
80+ // Clone the URL
81+ let url = url. clone ( ) ;
82+
83+ // For simplicity, ignore the checksum
84+ // This may result in missing some cache validation, but it avoids complex lifetime issues
85+ let maybe_checksum_owned = None ;
86+
87+ // Directly run the operation in this thread
88+ self . fetch_cached_no_follow ( & url, maybe_checksum_owned)
89+ }
90+ }
91+
92+ #[ cfg( not( feature = "async-module-loading" ) ) ]
93+ impl < TBlobStore , TSys , THttpClient > AsyncFileFetcherExt for super :: FileFetcher < TBlobStore , TSys , THttpClient >
94+ where
95+ TBlobStore : super :: BlobStore + Clone ,
96+ TSys : crate :: sync:: MaybeSend + crate :: sync:: MaybeSync + sys_traits:: FsRead + sys_traits:: SystemTimeNow + Clone ,
97+ THttpClient : super :: HttpClient + Clone ,
98+ {
99+ async fn fetch_cached_async (
100+ & self ,
101+ url : & Url ,
102+ redirect_limit : i64 ,
103+ ) -> Result < Option < File > , FetchCachedError > {
104+ self . fetch_cached ( url, redirect_limit)
105+ }
106+
107+ async fn fetch_cached_no_follow_async (
108+ & self ,
109+ url : & Url ,
110+ maybe_checksum : Option < Checksum < ' _ > > ,
111+ ) -> Result < Option < FileOrRedirect > , FetchCachedNoFollowError > {
112+ self . fetch_cached_no_follow ( url, maybe_checksum)
113+ }
114+ }
0 commit comments