1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

use std::{
    fs::File,
    io::{self,
        ErrorKind,
        prelude::*,
    },
    time::{SystemTime, Duration},
};

use super::{ XResult, new_box_ioerror, };
use super::util_size::get_display_size;
use super::util_msg::print_lastline;
use super::util_file::resolve_file_path;

pub const DEFAULT_BUF_SIZE: usize = 8 * 1024;


pub fn get_read_stdin_or_file(file: &str) -> XResult<Box<dyn Read>> {
    if file.is_empty() {
        Ok(Box::new(io::stdin()))
    } else {
        match File::open(&resolve_file_path(file)) {
            Ok(f) => Ok(Box::new(f)),
            Err(err) => Err(new_box_ioerror(&format!("Open file {}, erorr: {}", file, err))),
        }
    }
}

pub fn read_to_string(read: &mut dyn Read) -> XResult<String> {
    let mut buffer = String::new();
    read.read_to_string(&mut buffer)?;
    Ok(buffer)
}

pub fn read_to_bytes(read: &mut dyn Read) -> XResult<Vec<u8>> {
    let mut buffer = vec![];
    read.read_to_end(&mut buffer)?;
    Ok(buffer)
}

pub fn copy_io<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W, total: i64) -> io::Result<u64>
        where R: io::Read, W: io::Write {
    copy_io_with_head(reader, writer, total, "Downloading")
}

pub fn print_status_last_line(head: &str, total: i64, written: i64, cost: Duration) {
    let mut download_speed = "-".to_string();
    let cost_as_secs = cost.as_secs();
    if cost_as_secs > 0 {
        download_speed = format!("{}/s", get_display_size((written / (cost_as_secs as i64)) as i64));
    }
    if total > 0 {
        print_lastline(&format!("{}, Total: {}, Finished: {}, Speed: {}",
            head,
            get_display_size(total),
            get_display_size(written),
            download_speed));
    } else {
        print_lastline(&format!("{}, Finished: {}, Speed: {}",
            head,
            get_display_size(written),
            download_speed));
    }
}

pub fn copy_io_with_head<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W, total: i64, head: &str) -> io::Result<u64>
        where R: io::Read, W: io::Write {
    //let written_cell = RefCell::new(0u64);
    let start = SystemTime::now();
    let written = copy_io_callback(reader, writer, total, &|total, written, _len| {
        //written_cell.replace_with(|&mut w| w + len as u64);
        //let written = *written_cell.borrow();
        let cost = SystemTime::now().duration_since(start.clone()).unwrap();
        print_status_last_line(head, total, written as i64, cost);
    });
    println!();
    written
}

pub fn copy_io_callback<R: ?Sized, W: ?Sized, FCallback>(reader: &mut R, writer: &mut W, total: i64, callback: &FCallback) -> io::Result<u64>
        where R: io::Read,
              W: io::Write,
              FCallback: Fn(i64, u64, usize) -> () {
    let mut written = 0u64;
    let mut buf: [u8; DEFAULT_BUF_SIZE] = [0u8; DEFAULT_BUF_SIZE];
    loop {
        let len = match reader.read(&mut buf) {
            Ok(0) => return Ok(written),
            Ok(len) => len,
            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
            Err(e) => return Err(e),
        };
        writer.write_all(&buf[..len])?;
        written += len as u64;
        callback(total, written, len);
    }
}