You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

76 lines
2.6 KiB

  1. use anyhow::{anyhow, Context};
  2. use async_read_progress::*;
  3. use futures::stream::StreamExt;
  4. use tokio::fs::File;
  5. use tokio::io::AsyncRead;
  6. use tokio_util::io::StreamReader;
  7. use tracing::info;
  8. use crate::args::ARGS;
  9. use crate::compression;
  10. use crate::pbar;
  11. pub async fn open_http(
  12. url: &str,
  13. ) -> anyhow::Result<(Box<dyn AsyncRead + Unpin>, Option<u64>, String)> {
  14. info!("Requesting url {:?}...", url);
  15. let client = reqwest::Client::new();
  16. let resp = client
  17. .get(url)
  18. .send()
  19. .await
  20. .context("http client get request")?;
  21. let filename = String::from(resp.url().path_segments().unwrap().last().unwrap());
  22. info!("Completed request with code {}!", resp.status());
  23. if !resp.status().is_success() {
  24. return Err(anyhow!("incorrect status code attempting to retrieve file"));
  25. }
  26. let size = resp.content_length();
  27. let stream = resp.bytes_stream();
  28. let stream = stream.map(|v| v.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)));
  29. Ok((Box::new(StreamReader::new(stream)), size, filename))
  30. }
  31. pub async fn open(
  32. update_progressbar: bool,
  33. ) -> anyhow::Result<(Box<dyn AsyncRead + Unpin>, Option<u64>)> {
  34. let (reader, total_bytes, filename): (Box<dyn AsyncRead + Unpin>, Option<u64>, String) =
  35. if ARGS.input == "-" {
  36. info!("Reading from stdin...");
  37. (Box::new(tokio::io::stdin()), None, "dummy.txt".to_string())
  38. } else {
  39. if ARGS.input.starts_with("http") {
  40. open_http(&ARGS.input).await?
  41. } else {
  42. info!("Opening file {}...", ARGS.input);
  43. let file = File::open(&ARGS.input).await.context("open input file")?;
  44. let meta = file.metadata().await.context("read input file metadata")?;
  45. (Box::new(file), Some(meta.len()), ARGS.input.clone())
  46. }
  47. };
  48. //Hook into the progress bar.
  49. let reader = {
  50. Box::new(
  51. reader.report_progress(std::time::Duration::from_millis(20), move |bytes_read| {
  52. if update_progressbar {
  53. pbar::update_progress(bytes_read as u64);
  54. }
  55. }),
  56. )
  57. };
  58. let compression_mode = if ARGS.compression == compression::CompressionMode::AUTO {
  59. info!("Attempting to guess compression mode...");
  60. compression::CompressionMode::parse(&filename)
  61. } else {
  62. ARGS.compression
  63. };
  64. info!("Using compression mode {:?}.", compression_mode);
  65. info!("Attempting decompression...");
  66. let reader = compression::get_decompressed_reader(compression_mode, reader).await?;
  67. info!("Ok!");
  68. Ok((reader, total_bytes))
  69. }