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
|
use std::collections::HashMap;
use std::time::Duration;
use anyhow::Result;
use curl::easy::{Easy2, Handler, WriteError};
use curl::multi::{Easy2Handle, Multi};
const URLS: &[&str] = &[
"https://www.microsoft.com",
"https://www.google.com",
"https://www.amazon.com",
"https://www.apple.com",
];
struct Collector(Vec<u8>);
impl Handler for Collector {
fn write(&mut self, data: &[u8]) -> Result<usize, WriteError> {
self.0.extend_from_slice(data);
Ok(data.len())
}
}
fn download(multi: &mut Multi, token: usize, url: &str) -> Result<Easy2Handle<Collector>> {
let version = curl::Version::get();
let mut request = Easy2::new(Collector(Vec::new()));
request.url(&url)?;
request.useragent(&format!("curl/{}", version.version()))?;
let mut handle = multi.add2(request)?;
handle.set_token(token)?;
Ok(handle)
}
fn main() -> Result<()> {
let mut multi = Multi::new();
let mut handles = URLS
.iter()
.enumerate()
.map(|(token, url)| Ok((token, download(&mut multi, token, url)?)))
.collect::<Result<HashMap<_, _>>>()?;
let mut still_alive = true;
while still_alive {
// We still need to process the last messages when
// `Multi::perform` returns "0".
if multi.perform()? == 0 {
still_alive = false;
}
multi.messages(|message| {
let token = message.token().expect("failed to get the token");
let handle = handles
.get_mut(&token)
.expect("the download value should exist in the HashMap");
match message
.result_for2(&handle)
.expect("token mismatch with the `EasyHandle`")
{
Ok(()) => {
let http_status = handle
.response_code()
.expect("HTTP request finished without status code");
println!(
"R: Transfer succeeded (Status: {}) {} (Download length: {})",
http_status,
URLS[token],
handle.get_ref().0.len()
);
}
Err(error) => {
println!("E: {} - <{}>", error, URLS[token]);
}
}
});
if still_alive {
// The sleeping time could be reduced to allow other processing.
// For instance, a thread could check a condition signalling the
// thread shutdown.
multi.wait(&mut [], Duration::from_secs(60))?;
}
}
Ok(())
}
|