mirror of
https://github.com/lifegpc/pixiv_downloader.git
synced 2026-06-15 18:34:34 +08:00
add Proxy settings
This commit is contained in:
120
src/opt/proxy.rs
120
src/opt/proxy.rs
@@ -2,20 +2,39 @@ use crate::ext::try_err::TryErr;
|
||||
use crate::gettext;
|
||||
use json::JsonValue;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::Display;
|
||||
use std::ops::Deref;
|
||||
use std::ops::DerefMut;
|
||||
use url::Url;
|
||||
|
||||
/// The error when parsing Proxy settings
|
||||
#[derive(Debug, derive_more::From)]
|
||||
pub enum ProxyError {
|
||||
/// String error
|
||||
String(String),
|
||||
/// Url parse error
|
||||
UrlParseError(url::ParseError),
|
||||
}
|
||||
|
||||
impl Display for ProxyError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::String(s) => f.write_str(s.as_str()),
|
||||
Self::UrlParseError(s) => {
|
||||
f.write_str(gettext("Failed to parse URL:"))?;
|
||||
s.fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for ProxyError {
|
||||
fn from(v: &str) -> Self {
|
||||
Self::String(String::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// Proxy settings
|
||||
pub enum Proxy {
|
||||
/// Apply for all HTTP requests, [None] means do not proxy
|
||||
@@ -87,3 +106,104 @@ impl TryFrom<&JsonValue> for Proxy {
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Proxy {
|
||||
/// Match the url.
|
||||
/// * `url` - Url
|
||||
pub fn r#match(&self, url: &Url) -> Option<Option<Url>> {
|
||||
match self {
|
||||
Self::All(d) => Some(d.clone()),
|
||||
Self::HTTP(d) => {
|
||||
let scheme = url.scheme();
|
||||
if scheme.is_empty() || scheme == "http" {
|
||||
Some(d.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Self::HTTPS(d) => {
|
||||
if url.scheme() == "https" {
|
||||
Some(d.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// A list of [Proxy]
|
||||
pub struct ProxyChain {
|
||||
/// Proxies
|
||||
proxies: Vec<Proxy>,
|
||||
}
|
||||
|
||||
impl ProxyChain {
|
||||
/// Match the url
|
||||
/// * `url` - The url
|
||||
pub fn r#match(&self, url: &Url) -> Option<Url> {
|
||||
for i in self.proxies.iter() {
|
||||
match i.r#match(url) {
|
||||
Some(u) => {
|
||||
return u;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ProxyChain {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
proxies: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ProxyChain {
|
||||
type Target = Vec<Proxy>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.proxies
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ProxyChain {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.proxies
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&JsonValue> for ProxyChain {
|
||||
type Error = ProxyError;
|
||||
fn try_from(value: &JsonValue) -> Result<Self, Self::Error> {
|
||||
let mut list = Vec::new();
|
||||
if value.is_array() {
|
||||
for i in value.members() {
|
||||
list.push(Proxy::try_from(i)?);
|
||||
}
|
||||
Ok(Self { proxies: list })
|
||||
} else {
|
||||
Err(ProxyError::from(gettext("Failed to parse proxy list.")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<JsonValue> for ProxyChain {
|
||||
type Error = ProxyError;
|
||||
fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
|
||||
Self::try_from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_proxy(v: &JsonValue) -> bool {
|
||||
match ProxyChain::try_from(v) {
|
||||
Ok(_) => true,
|
||||
Err(e) => {
|
||||
println!("{}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,14 @@ use crate::ext::rw_lock::GetRwLock;
|
||||
use crate::ext::use_or_not::ToBool;
|
||||
use crate::ext::use_or_not::UseOrNot;
|
||||
use crate::list::NonTailList;
|
||||
use crate::opt::proxy::ProxyChain;
|
||||
use crate::opt::size::parse_u32_size;
|
||||
use crate::opt::use_progress_bar::UseProgressBar;
|
||||
use crate::opts::CommandOpts;
|
||||
use crate::retry_interval::parse_retry_interval_from_json;
|
||||
use crate::settings::SettingStore;
|
||||
use std::convert::TryFrom;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
use std::sync::RwLockReadGuard;
|
||||
@@ -25,6 +28,8 @@ pub struct OptHelper {
|
||||
default_retry_interval: NonTailList<Duration>,
|
||||
_author_name_filters: RwLock<Vec<AuthorNameFilter>>,
|
||||
_use_progress_bar: RwLock<Option<UseProgressBar>>,
|
||||
/// Proxy settings
|
||||
_proxy_chain: RwLock<ProxyChain>,
|
||||
}
|
||||
|
||||
impl OptHelper {
|
||||
@@ -171,6 +176,10 @@ impl OptHelper {
|
||||
} else {
|
||||
None
|
||||
});
|
||||
if settings.have("proxy") {
|
||||
self._proxy_chain
|
||||
.replace_with2(ProxyChain::try_from(settings.get("proxy").unwrap()).unwrap());
|
||||
}
|
||||
self.opt.replace_with2(opt);
|
||||
self.settings.replace_with2(settings);
|
||||
}
|
||||
@@ -179,6 +188,11 @@ impl OptHelper {
|
||||
self.opt.get_ref().overwrite
|
||||
}
|
||||
|
||||
/// The proxy chain
|
||||
pub fn proxy_chain(&self) -> ProxyChain {
|
||||
self._proxy_chain.get_ref().deref().clone()
|
||||
}
|
||||
|
||||
pub fn verbose(&self) -> bool {
|
||||
self.opt.get_ref().verbose
|
||||
}
|
||||
@@ -284,6 +298,7 @@ impl Default for OptHelper {
|
||||
default_retry_interval: l,
|
||||
_author_name_filters: RwLock::new(Vec::new()),
|
||||
_use_progress_bar: RwLock::new(None),
|
||||
_proxy_chain: RwLock::new(ProxyChain::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::gettext;
|
||||
use crate::retry_interval::check_retry_interval;
|
||||
use crate::settings::SettingDes;
|
||||
use crate::settings::JsonValueType;
|
||||
use crate::opt::proxy::check_proxy;
|
||||
use crate::opt::size::parse_u32_size;
|
||||
use json::JsonValue;
|
||||
|
||||
@@ -28,6 +29,7 @@ pub fn get_settings_list() -> Vec<SettingDes> {
|
||||
SettingDes::new("download-part-retry", gettext("Max retry count of each part when downloading in multiple thread mode."), JsonValueType::Number, Some(check_i64)).unwrap(),
|
||||
SettingDes::new("max-threads", gettext("The maximun threads when downloading file."), JsonValueType::Number, Some(check_u64)).unwrap(),
|
||||
SettingDes::new("part-size", gettext("The size of the each part when downloading file."), JsonValueType::Number, Some(check_parse_size_u32)).unwrap(),
|
||||
SettingDes::new("proxy", gettext("Proxy settings."), JsonValueType::Array, Some(check_proxy)).unwrap(),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::gettext;
|
||||
use crate::list::NonTailList;
|
||||
use crate::opthelper::get_helper;
|
||||
use json::JsonValue;
|
||||
use reqwest::{Client, IntoUrl, RequestBuilder, Response};
|
||||
use reqwest::{Client, ClientBuilder, IntoUrl, RequestBuilder, Response};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::default::Default;
|
||||
@@ -94,9 +94,9 @@ impl WebClient {
|
||||
/// Create a new instance of client
|
||||
///
|
||||
/// This function will not handle any basic options, please use [Self::default()] instead.
|
||||
pub fn new() -> Self {
|
||||
pub fn new(client: Client) -> Self {
|
||||
Self {
|
||||
client: Client::new(),
|
||||
client,
|
||||
headers: RwLock::new(HashMap::new()),
|
||||
cookies: RwLock::new(CookieJar::new()),
|
||||
verbose: Arc::new(AtomicBool::new(false)),
|
||||
@@ -374,8 +374,14 @@ impl WebClient {
|
||||
|
||||
impl Default for WebClient {
|
||||
fn default() -> Self {
|
||||
let c = Self::new();
|
||||
let opt = get_helper();
|
||||
let mut c = ClientBuilder::new();
|
||||
let chain = opt.proxy_chain();
|
||||
if !chain.is_empty() {
|
||||
c = c.proxy(reqwest::Proxy::custom(move |url| chain.r#match(url)));
|
||||
}
|
||||
let c = c.build().unwrap();
|
||||
let c = Self::new(c);
|
||||
c.set_verbose(opt.verbose());
|
||||
match opt.retry() {
|
||||
Some(retry) => c.set_retry(retry),
|
||||
|
||||
Reference in New Issue
Block a user