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.
lolistealer/src/work_async.rs

116 lines
3.1 KiB

use super::*;
use std::{
path::Path,
};
use tokio::{
fs::{
OpenOptions,
},
prelude::*,
stream::StreamExt,
};
mod tasklist;
#[macro_use]
mod progress;
/// Download a loli async
pub async fn perform(url: impl AsRef<str>, path: impl AsRef<Path>, progress: &mut progress::CommandSender) -> Result<String, error::Error>
{
let url = url.as_ref();
let path = path.as_ref();
let task = format!("{:?}", path); //TODO: Real task name
let mut resp = reqwest::get(url).await?;
let len = resp.content_length();
prog_send!(link progress.push_task(&task));
if let Some(len) = len {
prog_send!(progress.bump_max(len));
} else {
prog_send!(progress.bump_max(1));
}
let mut file = OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.read(true)
.open(path).await?;
prog_send!(progress.println(format!("Starting download of {:?} bytes to {:?}", len, path)));
let mut bytes = resp.bytes_stream();
while let Some(buffer) = bytes.next().await {
let slice = buffer?;
let slice = slice.as_ref();
file.write(slice).await?;
if let Some(_) = len {
prog_send!(progress.bump(slice.len() as u64));
}
}
if len.is_none() {
prog_send!(progress.bump(1));
}
prog_send!(progress.println(format!("done for {}", url)));
//prog_send!(link progress.pop_task(task));
Ok(task)
}
pub async fn work(conf: config::Config) -> Result<(), Box<dyn std::error::Error>>
{
let rating = conf.rating;
let mut children = Vec::with_capacity(conf.output.len());
let prog = progress::AsyncProgressCounter::new("Initialising...", 1);
let mut prog_writer = prog.writer();
let prog = prog.host();
for path in conf.output.into_iter()
{
let url = url::parse(&rating);
let mut prog = prog_writer.clone_with(format!("-> {:?}", path));
children.push(tokio::task::spawn(async move {
//println!("Starting download ({})...", url);
prog.println(format!("Starting download ({})...", url)).await.expect("fatal");
/*let path = match path {
config::OutputType::File(file) => file, //TODO: Download to temp file, memmap to str slice and then base64 decode. Also, determine if we need .png or .jpg from header.
config::OutputType::Directory(dir) => {
//TODO: Implement downloading to temp and renaming to hash
unimplemented!();
},
};*/
let temp = tempfile::TempFile::new();
match perform(&url, &temp, &mut prog).await {
Err(e) => panic!("Failed downloading {} -> {:?}: {}", url, temp, e), //TODO: Make real error handler
Ok(task) => {
//TODO: memmap `temp` and decode base64 into new file `path`. also determine the encoding.
prog_send!(link prog.pop_task(task));
},
}
}));
}
prog_send!(link prog_writer.println("Children working..."));
for child in children.into_iter()
{
match child.await {
Ok(v) => (),
Err(err) => {
println!("Child failed: {}", err);
},
}
}
prog_send!(link prog_writer.set_title(""));
prog_send!(try link prog_writer.kill());
prog.await.expect("mpsc fatal");
Ok(())
}