diff --git a/Cargo.lock b/Cargo.lock index 942a228..bbb3752 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1503,6 +1503,7 @@ dependencies = [ "serde_urlencoded", "tokio", "tokio-native-tls", + "tokio-socks", "tower-service", "url", "wasm-bindgen", @@ -2013,6 +2014,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-socks" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" +dependencies = [ + "either", + "futures-util", + "thiserror", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.14" diff --git a/src/cli.rs b/src/cli.rs index fb4a6fe..32a07c9 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -5,6 +5,7 @@ use crate::{ config::{cache_dir, config_dir, CONFIG_FILE_NAME, THEME_FILE_NAME}, }; use wiki_api::languages::Language; +use wiki_api::proxy::init_proxy; #[derive(Parser)] #[command(author, version, about, long_about = None)] @@ -35,6 +36,10 @@ struct Cli { #[arg(long = "theme-config-path")] print_theme_config_path: bool, + /// Set the proxy + #[arg(long = "proxy")] + proxy: Option, + #[cfg(debug_assertions)] #[arg(value_name = "PATH", long = "page")] load_debug_page: Option, @@ -43,6 +48,7 @@ struct Cli { pub struct CliResults { pub actions: Option, pub log_level: Option, + pub warn_list: Vec, } pub fn match_cli() -> CliResults { @@ -52,6 +58,7 @@ pub fn match_cli() -> CliResults { let mut results = CliResults { actions: None, log_level: None, + warn_list: Vec::new(), }; let mut packet = ActionPacket::default(); @@ -103,6 +110,14 @@ pub fn match_cli() -> CliResults { should_quit = true; } + if let Some(proxy) = cli.proxy { + if let Err(err) = init_proxy(&proxy) { + results.warn_list.push(err); + let action = Action::PopupMessage("Information".to_string(), "Something went wrong when trying to initial proxy \nCheck the logs for further information".to_string()); + packet.add_action(action); + } + }; + #[cfg(debug_assertions)] if let Some(ref debug_page) = cli.load_debug_page { if let Some(page) = wiki_api::page::Page::from_path(debug_page) { diff --git a/src/main.rs b/src/main.rs index c528a1e..3b0d6d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,6 +24,11 @@ async fn main() -> Result<()> { initialize_logging(results.log_level)?; initialize_panic_handler()?; + // Log match cli message + for err in results.warn_list { + warn!(err) + } + let (action_tx, mut action_rx) = mpsc::unbounded_channel(); let app_component = Arc::new(Mutex::new(AppComponent::default())); diff --git a/wiki-api/Cargo.toml b/wiki-api/Cargo.toml index eacc1a2..15fc7cd 100644 --- a/wiki-api/Cargo.toml +++ b/wiki-api/Cargo.toml @@ -16,7 +16,7 @@ bitflags = { version = "2.6.0", features = ["serde"] } ego-tree = "0.6.2" html5ever = "0.26.0" markup5ever_rcdom = "0.2.0" -reqwest = "0.11.20" +reqwest = { version = "0.11.20", features = ["socks"] } scraper = "0.17.1" serde = "1.0.188" serde_json = "1.0.105" diff --git a/wiki-api/src/lib.rs b/wiki-api/src/lib.rs index 3e712f9..b496a0d 100644 --- a/wiki-api/src/lib.rs +++ b/wiki-api/src/lib.rs @@ -4,6 +4,7 @@ pub mod document; pub mod languages; pub mod page; pub mod parser; +pub mod proxy; pub mod search; // TODO: Make Endpoint a real struct diff --git a/wiki-api/src/page.rs b/wiki-api/src/page.rs index 333efbb..4b9479e 100644 --- a/wiki-api/src/page.rs +++ b/wiki-api/src/page.rs @@ -13,6 +13,7 @@ use tracing::{debug, warn}; use url::Url; use super::languages::Language; +use super::proxy::get_proxy; pub mod link_data { use crate::{languages::Language, search::Namespace, Endpoint}; @@ -398,7 +399,15 @@ impl PageBuilder { impl PageBuilder { async fn fetch_with_params(self, mut params: Vec<(&str, String)>) -> Result { async fn action_parse(params: Vec<(&str, String)>, endpoint: Url) -> Result { - Client::new() + // Create builder with proxy + let client_builder = match get_proxy() { + Some(proxy) => Client::builder().proxy(proxy.clone()), + None => Client::builder(), + }; + + client_builder + .build() + .expect("clinet build error") .get(endpoint) .query(&[ ("action", "parse"), diff --git a/wiki-api/src/proxy.rs b/wiki-api/src/proxy.rs new file mode 100644 index 0000000..021062a --- /dev/null +++ b/wiki-api/src/proxy.rs @@ -0,0 +1,34 @@ +use reqwest::Proxy; +use std::sync::OnceLock; + +static PROXY: OnceLock = OnceLock::new(); + +fn validate_proxy(addr: &str) -> Result<(), String> { + let _addr_clean = if let Some(addr) = addr.strip_prefix("socks5://") { + addr + } else if let Some(addr) = addr.strip_prefix("http://") { + addr + } else if let Some(addr) = addr.strip_prefix("https://") { + addr + } else { + return Err(format!("Invalid proxy protocol: {}", addr)); + }; + + // TODO: check host and port + Ok(()) +} + +// Init proxy only once +pub fn init_proxy(str: &str) -> Result<(), String> { + validate_proxy(str)?; + let proxy = match Proxy::all(str) { + Ok(o) => o, + Err(e) => return Err(e.to_string()), + }; + PROXY.set(proxy).expect("init error"); + Ok(()) +} + +pub fn get_proxy() -> Option<&'static Proxy> { + PROXY.get() +} diff --git a/wiki-api/src/search.rs b/wiki-api/src/search.rs index cbb98c7..4b56f38 100644 --- a/wiki-api/src/search.rs +++ b/wiki-api/src/search.rs @@ -13,6 +13,7 @@ use std::fmt::Write; use crate::Endpoint; use crate::languages::Language; +use crate::proxy::get_proxy; /// A finished search containing the found results and additional optional information regarding /// the search @@ -699,7 +700,15 @@ impl SearchBuilder { /// - The returned result could not interpreted as a `Search` pub async fn search(self) -> Result { async fn action_query(params: Vec<(&str, String)>, endpoint: Endpoint) -> Result { - Client::new() + // Create builder with proxy + let client_builder = match get_proxy() { + Some(proxy) => Client::builder().proxy(proxy.clone()), + None => Client::builder(), + }; + + client_builder + .build() + .expect("clinet build error") .get(endpoint) .query(&[ ("action", "query"),