Skip to content

Instantly share code, notes, and snippets.

@bartlomieju
Created July 20, 2019 18:45
Show Gist options
  • Save bartlomieju/ffb21f610e23d2e03db437671b561ec2 to your computer and use it in GitHub Desktop.
Save bartlomieju/ffb21f610e23d2e03db437671b561ec2 to your computer and use it in GitHub Desktop.
Futures recursion
/// Asynchronously fetch remote source file specified by the URL following redirects.
fn fetch_remote_source_async(
self: &Self,
module_url: &Url,
) -> Box<impl Future<Item = SourceFile, Error = ErrBox>> {
use crate::http_util::FetchOnceResult;
let download_job = self.progress.add("Download", &module_url.to_string());
let module_uri = url_into_uri(&module_url);
let dir = self.clone();
let module_url = module_url.clone();
// Single pass fetch, either yields code or yields redirect.
let f = http_util::fetch_string_once(module_uri).and_then(
move |fetch_once_result| {
match fetch_once_result {
FetchOnceResult::Redirect(uri) => {
// If redirects, update module_name and filename for next looped call.
let new_module_url = Url::parse(&uri.to_string()).expect("http::uri::Uri should be parseable as Url");
dir.save_source_code_headers(
&module_url,
None,
Some(new_module_url.to_string())
).unwrap();
// Explicit drop to keep reference alive until future completes.
drop(download_job);
let module_url = module_url.clone();
// Recurse
let fut = dir.get_source_file_async(&new_module_url, dir.use_disk_cache, dir.no_remote_fetch)
.and_then(move |source_file| {
let mut source_file = source_file;
source_file.redirect_source_url = Some(module_url);
futures::future::ok(source_file)
});
Either::A(fut)
}
FetchOnceResult::Code(source, maybe_content_type) => {
// TODO: move caching logic outside this function
// We land on the code.
dir.save_source_code_headers(
&module_url,
maybe_content_type.clone(),
None,
).unwrap();
dir.save_source_code(
&module_url,
&source
).unwrap();
let filepath = dir
.deps_cache
.location
.join(dir.deps_cache.get_cache_filename(&module_url));
let media_type = map_content_type(
&filepath,
maybe_content_type.as_ref().map(String::as_str),
);
let source_file = SourceFile {
url: module_url.clone(),
redirect_source_url: None,
filename: filepath,
media_type,
source_code: source.as_bytes().to_owned(),
};
// Explicit drop to keep reference alive until future completes.
drop(download_job);
Either::B(futures::future::ok(source_file))
}
}
},
);
Box::new(f)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment