mirror of
https://github.com/lifegpc/pixiv_downloader.git
synced 2026-07-03 11:50:35 +08:00
Update
This commit is contained in:
@@ -1,40 +1,55 @@
|
||||
use super::pd_file::PdFile;
|
||||
use super::pd_file::PdFilePartStatus;
|
||||
use super::pd_file::PdFileResult;
|
||||
use super::enums::DownloaderResult;
|
||||
use super::enums::DownloaderStatus;
|
||||
use super::error::DownloaderError;
|
||||
use crate::ext::atomic::AtomicQuick;
|
||||
use crate::ext::rw_lock::GetRwLock;
|
||||
use crate::utils::ask_need_overwrite;
|
||||
use crate::webclient::WebClient;
|
||||
use crate::webclient::ToHeaders;
|
||||
use reqwest::IntoUrl;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::fs::remove_file;
|
||||
use std::io::Seek;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use tokio::task::JoinHandle;
|
||||
use url::Url;
|
||||
|
||||
#[derive(Debug)]
|
||||
/// A file downloader
|
||||
pub struct Downloader {
|
||||
pub struct Downloader<T: Write + Seek> {
|
||||
/// The webclient
|
||||
client: Arc<WebClient>,
|
||||
/// The download status
|
||||
status: Arc<PdFile>,
|
||||
pd: Arc<PdFile>,
|
||||
/// The url of the file
|
||||
url: Arc<Url>,
|
||||
/// The HTTP headers map
|
||||
headers: Arc<HashMap<String, String>>,
|
||||
/// The target file
|
||||
file: RwLock<Option<File>>,
|
||||
file: RwLock<Option<T>>,
|
||||
/// The status of the downloader
|
||||
status: RwLock<DownloaderStatus>,
|
||||
/// All tasks
|
||||
tasks: Vec<JoinHandle<PdFilePartStatus>>,
|
||||
/// Whether to enable mulitple thread mode
|
||||
multi: AtomicBool,
|
||||
}
|
||||
|
||||
impl Downloader {
|
||||
impl Downloader<File> {
|
||||
/// Create a new [Downloader] instance
|
||||
/// * `url` - The url of the file
|
||||
/// * `header` - HTTP headers
|
||||
/// * `path` - The path to store downloaded file.
|
||||
/// * `overwrite` - Whether to overwrite file
|
||||
pub fn new<U: IntoUrl, H: ToHeaders, P: AsRef<Path> + ?Sized>(url: U, headers: H, path: Option<&P>, overwrite: Option<bool>) -> Result<DownloaderResult, DownloaderError> {
|
||||
pub fn new<U: IntoUrl, H: ToHeaders, P: AsRef<Path> + ?Sized>(url: U, headers: H, path: Option<&P>, overwrite: Option<bool>) -> Result<DownloaderResult<File>, DownloaderError> {
|
||||
let h = match headers.to_headers() {
|
||||
Some(h) => { h }
|
||||
None => { HashMap::new() }
|
||||
@@ -50,6 +65,7 @@ impl Downloader {
|
||||
if !overwrite {
|
||||
return Ok(DownloaderResult::Canceled);
|
||||
} else {
|
||||
remove_file(p)?;
|
||||
PdFile::new()
|
||||
}
|
||||
}
|
||||
@@ -57,6 +73,7 @@ impl Downloader {
|
||||
if !ask_need_overwrite(p.to_str().unwrap()) {
|
||||
return Ok(DownloaderResult::Canceled);
|
||||
} else {
|
||||
remove_file(p)?;
|
||||
PdFile::new()
|
||||
}
|
||||
}
|
||||
@@ -83,10 +100,41 @@ impl Downloader {
|
||||
};
|
||||
Ok(DownloaderResult::Ok(Self {
|
||||
client: Arc::new(WebClient::new()),
|
||||
status: Arc::new(pd_file),
|
||||
pd: Arc::new(pd_file),
|
||||
url: Arc::new(url.into_url()?),
|
||||
headers: Arc::new(h),
|
||||
file: RwLock::new(file),
|
||||
status: RwLock::new(DownloaderStatus::Created),
|
||||
tasks: Vec::new(),
|
||||
multi: AtomicBool::new(false),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl <T: Write + Seek> Downloader<T> {
|
||||
/// Start download if download not started.
|
||||
///
|
||||
/// Returns the status of the Downloader
|
||||
pub fn download(&self) -> DownloaderStatus {
|
||||
if !self.is_created() {
|
||||
return self.status.get_ref().clone();
|
||||
}
|
||||
self.status.get_ref().clone()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Returns true if the downloader is created just now.
|
||||
pub fn is_created(&self) -> bool {
|
||||
*self.status.get_ref() == DownloaderStatus::Created
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Returns true if is multiple thread mode.
|
||||
pub fn is_multi_threads(&self) -> bool {
|
||||
if self.pd.is_downloading() {
|
||||
self.pd.is_multi_threads()
|
||||
} else {
|
||||
self.multi.qload()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
use super::downloader::Downloader;
|
||||
use std::io::Seek;
|
||||
use std::io::Write;
|
||||
|
||||
#[derive(Debug)]
|
||||
/// The result when try create a new [Downloader] interface
|
||||
pub enum DownloaderResult {
|
||||
pub enum DownloaderResult<T: Write + Seek> {
|
||||
/// Created successfully
|
||||
Ok(Downloader),
|
||||
Ok(Downloader<T>),
|
||||
/// The target file already downloaded and overwrite is disabled.
|
||||
Canceled,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
/// The status of the [Downloader]
|
||||
pub enum DownloaderStatus {
|
||||
/// The downloader is just created
|
||||
Created,
|
||||
/// The downloader is downloading now
|
||||
Downloading,
|
||||
/// The downloader is downloaded complete
|
||||
Downloaded,
|
||||
}
|
||||
|
||||
@@ -12,3 +12,4 @@ pub mod version;
|
||||
pub use enums::PdFileResult;
|
||||
pub use error::PdFileError;
|
||||
pub use file::PdFile;
|
||||
pub use part_status::PdFilePartStatus;
|
||||
|
||||
40
src/ext/atomic.rs
Normal file
40
src/ext/atomic.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
/// A trait to help to load and store atomic value quickly.
|
||||
pub trait AtomicQuick<T> {
|
||||
/// Loads a value from the atomic integer
|
||||
fn qload(&self) -> T;
|
||||
/// Stores a value into the atomic integer.
|
||||
fn qstore(&self, value: T);
|
||||
#[inline]
|
||||
/// Stores a value into the atomic integer.
|
||||
/// Alias for [Self::qstore]
|
||||
fn qsave(&self, value: T) {
|
||||
self.qstore(value)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_atomic_quick_with_atomic {
|
||||
($type1:ty, $type2:ty) => {
|
||||
impl AtomicQuick<$type2> for $type1 {
|
||||
fn qload(&self) -> $type2 {
|
||||
self.load(Ordering::Relaxed)
|
||||
}
|
||||
fn qstore(&self, value: $type2) {
|
||||
self.store(value, Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_atomic_quick_with_atomic!(std::sync::atomic::AtomicBool, bool);
|
||||
impl_atomic_quick_with_atomic!(std::sync::atomic::AtomicI8, i8);
|
||||
impl_atomic_quick_with_atomic!(std::sync::atomic::AtomicU8, u8);
|
||||
impl_atomic_quick_with_atomic!(std::sync::atomic::AtomicI16, i16);
|
||||
impl_atomic_quick_with_atomic!(std::sync::atomic::AtomicU16, u16);
|
||||
impl_atomic_quick_with_atomic!(std::sync::atomic::AtomicI32, i32);
|
||||
impl_atomic_quick_with_atomic!(std::sync::atomic::AtomicU32, u32);
|
||||
impl_atomic_quick_with_atomic!(std::sync::atomic::AtomicI64, i64);
|
||||
impl_atomic_quick_with_atomic!(std::sync::atomic::AtomicU64, u64);
|
||||
impl_atomic_quick_with_atomic!(std::sync::atomic::AtomicIsize, isize);
|
||||
impl_atomic_quick_with_atomic!(std::sync::atomic::AtomicUsize, usize);
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod atomic;
|
||||
pub mod cstr;
|
||||
#[cfg(feature = "flagset")]
|
||||
pub mod flagset;
|
||||
|
||||
Reference in New Issue
Block a user