mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-06-10 16:57:52 +02:00
feat: add proxy management
This commit is contained in:
@@ -519,7 +519,7 @@ mod tests {
|
||||
browser: browser.to_string(),
|
||||
version: version.to_string(),
|
||||
process_id: None,
|
||||
proxy: None,
|
||||
proxy_id: None,
|
||||
last_launch: None,
|
||||
release_type: "stable".to_string(),
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ProxySettings {
|
||||
pub enabled: bool,
|
||||
pub proxy_type: String, // "http", "https", "socks4", or "socks5"
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
@@ -636,12 +635,11 @@ impl Browser for ChromiumBrowser {
|
||||
|
||||
// Add proxy configuration if provided
|
||||
if let Some(proxy) = proxy_settings {
|
||||
if proxy.enabled {
|
||||
args.push(format!(
|
||||
"--proxy-server=http://{}:{}",
|
||||
proxy.host, proxy.port
|
||||
));
|
||||
}
|
||||
// Apply proxy settings
|
||||
args.push(format!(
|
||||
"--proxy-server=http://{}:{}",
|
||||
proxy.host, proxy.port
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(url) = url {
|
||||
@@ -887,7 +885,6 @@ mod tests {
|
||||
#[test]
|
||||
fn test_proxy_settings_creation() {
|
||||
let proxy = ProxySettings {
|
||||
enabled: true,
|
||||
proxy_type: "http".to_string(),
|
||||
host: "127.0.0.1".to_string(),
|
||||
port: 8080,
|
||||
@@ -895,14 +892,12 @@ mod tests {
|
||||
password: None,
|
||||
};
|
||||
|
||||
assert!(proxy.enabled);
|
||||
assert_eq!(proxy.proxy_type, "http");
|
||||
assert_eq!(proxy.host, "127.0.0.1");
|
||||
assert_eq!(proxy.port, 8080);
|
||||
|
||||
// Test different proxy types
|
||||
let socks_proxy = ProxySettings {
|
||||
enabled: true,
|
||||
proxy_type: "socks5".to_string(),
|
||||
host: "proxy.example.com".to_string(),
|
||||
port: 1080,
|
||||
@@ -980,7 +975,6 @@ mod tests {
|
||||
#[test]
|
||||
fn test_proxy_settings_serialization() {
|
||||
let proxy = ProxySettings {
|
||||
enabled: true,
|
||||
proxy_type: "http".to_string(),
|
||||
host: "127.0.0.1".to_string(),
|
||||
port: 8080,
|
||||
@@ -996,7 +990,6 @@ mod tests {
|
||||
|
||||
// Test that it can be deserialized (implements Deserialize)
|
||||
let deserialized: ProxySettings = serde_json::from_str(&json).unwrap();
|
||||
assert_eq!(deserialized.enabled, proxy.enabled);
|
||||
assert_eq!(deserialized.proxy_type, proxy.proxy_type);
|
||||
assert_eq!(deserialized.host, proxy.host);
|
||||
assert_eq!(deserialized.port, proxy.port);
|
||||
|
||||
+223
-155
@@ -24,7 +24,7 @@ pub struct BrowserProfile {
|
||||
pub browser: String,
|
||||
pub version: String,
|
||||
#[serde(default)]
|
||||
pub proxy: Option<ProxySettings>,
|
||||
pub proxy_id: Option<String>, // Reference to stored proxy
|
||||
#[serde(default)]
|
||||
pub process_id: Option<u32>,
|
||||
#[serde(default)]
|
||||
@@ -1150,6 +1150,79 @@ impl BrowserRunner {
|
||||
// Now update the profile with UUID (no need to store profile_path anymore)
|
||||
old_profile["id"] = serde_json::Value::String(profile_id.to_string());
|
||||
|
||||
// Handle proxy migration - extract proxy to separate storage if it exists
|
||||
if let Some(proxy_value) = old_profile.get("proxy").cloned() {
|
||||
if !proxy_value.is_null() {
|
||||
// Try to deserialize the proxy settings
|
||||
if let Ok(proxy_settings) = serde_json::from_value::<ProxySettings>(proxy_value) {
|
||||
// Create a stored proxy with the profile name (all proxies are now enabled by default)
|
||||
let proxy_name = format!("{profile_name} Proxy");
|
||||
match PROXY_MANAGER.create_stored_proxy(proxy_name.clone(), proxy_settings.clone()) {
|
||||
Ok(stored_proxy) => {
|
||||
// Update profile to reference the stored proxy
|
||||
old_profile["proxy_id"] = serde_json::Value::String(stored_proxy.id);
|
||||
println!(
|
||||
"Migrated proxy for profile '{}' to stored proxy '{}'",
|
||||
profile_name, stored_proxy.name
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Warning: Failed to migrate proxy for profile '{profile_name}': {e}");
|
||||
// If creation fails (e.g., name collision), try to find existing proxy with same settings
|
||||
let existing_proxies = PROXY_MANAGER.get_stored_proxies();
|
||||
if let Some(existing_proxy) = existing_proxies.iter().find(|p| {
|
||||
p.proxy_settings.proxy_type == proxy_settings.proxy_type
|
||||
&& p.proxy_settings.host == proxy_settings.host
|
||||
&& p.proxy_settings.port == proxy_settings.port
|
||||
&& p.proxy_settings.username == proxy_settings.username
|
||||
&& p.proxy_settings.password == proxy_settings.password
|
||||
}) {
|
||||
old_profile["proxy_id"] = serde_json::Value::String(existing_proxy.id.clone());
|
||||
println!(
|
||||
"Reused existing proxy '{}' for profile '{}'",
|
||||
existing_proxy.name, profile_name
|
||||
);
|
||||
} else {
|
||||
// Try with a different name if the original failed due to name collision
|
||||
let alt_proxy_name = format!(
|
||||
"{profile_name} Proxy {}",
|
||||
&uuid::Uuid::new_v4().to_string()[..8]
|
||||
);
|
||||
match PROXY_MANAGER
|
||||
.create_stored_proxy(alt_proxy_name.clone(), proxy_settings.clone())
|
||||
{
|
||||
Ok(stored_proxy) => {
|
||||
old_profile["proxy_id"] = serde_json::Value::String(stored_proxy.id);
|
||||
println!(
|
||||
"Migrated proxy for profile '{}' to stored proxy '{}' with fallback name",
|
||||
profile_name, stored_proxy.name
|
||||
);
|
||||
}
|
||||
Err(e2) => {
|
||||
println!("Error: Could not migrate proxy for profile '{profile_name}' even with fallback name: {e2}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!(
|
||||
"Warning: Could not deserialize proxy settings for profile '{profile_name}'"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Always remove the old proxy field after migration attempt, whether successful or not
|
||||
if old_profile
|
||||
.as_object_mut()
|
||||
.unwrap()
|
||||
.remove("proxy")
|
||||
.is_some()
|
||||
{
|
||||
println!("Removed legacy proxy field from profile '{profile_name}'");
|
||||
}
|
||||
|
||||
// Move old profile directory contents to new UUID/profile directory if it exists
|
||||
if old_profile_dir.exists() && old_profile_dir.is_dir() {
|
||||
// Copy all contents from old directory to new profile subdirectory
|
||||
@@ -1272,7 +1345,7 @@ impl BrowserRunner {
|
||||
browser: &str,
|
||||
version: &str,
|
||||
release_type: &str,
|
||||
proxy: Option<ProxySettings>,
|
||||
proxy_id: Option<String>,
|
||||
) -> Result<BrowserProfile, Box<dyn std::error::Error>> {
|
||||
println!("Attempting to create profile: {name}");
|
||||
|
||||
@@ -1301,7 +1374,7 @@ impl BrowserRunner {
|
||||
name: name.to_string(),
|
||||
browser: browser.to_string(),
|
||||
version: version.to_string(),
|
||||
proxy: proxy.clone(),
|
||||
proxy_id: proxy_id.clone(),
|
||||
process_id: None,
|
||||
last_launch: None,
|
||||
release_type: release_type.to_string(),
|
||||
@@ -1318,8 +1391,13 @@ impl BrowserRunner {
|
||||
println!("Profile '{name}' created successfully with ID: {profile_id}");
|
||||
|
||||
// Create user.js with common Firefox preferences and apply proxy settings if provided
|
||||
if let Some(proxy_settings) = &proxy {
|
||||
self.apply_proxy_settings_to_profile(&profile_data_dir, proxy_settings, None)?;
|
||||
if let Some(proxy_id_ref) = &proxy_id {
|
||||
if let Some(proxy_settings) = PROXY_MANAGER.get_proxy_settings_by_id(proxy_id_ref) {
|
||||
self.apply_proxy_settings_to_profile(&profile_data_dir, &proxy_settings, None)?;
|
||||
} else {
|
||||
// Proxy ID provided but not found, disable proxy
|
||||
self.disable_proxy_settings_in_profile(&profile_data_dir)?;
|
||||
}
|
||||
} else {
|
||||
// Create user.js with common Firefox preferences but no proxy
|
||||
self.disable_proxy_settings_in_profile(&profile_data_dir)?;
|
||||
@@ -1332,7 +1410,7 @@ impl BrowserRunner {
|
||||
&self,
|
||||
app_handle: tauri::AppHandle,
|
||||
profile_name: &str,
|
||||
proxy: Option<ProxySettings>,
|
||||
proxy_id: Option<String>,
|
||||
) -> Result<BrowserProfile, Box<dyn std::error::Error + Send + Sync>> {
|
||||
// Find the profile by name
|
||||
let profiles =
|
||||
@@ -1356,14 +1434,14 @@ impl BrowserRunner {
|
||||
.await?;
|
||||
|
||||
// If browser is running, stop existing proxy
|
||||
if browser_is_running && profile.proxy.is_some() {
|
||||
if browser_is_running && profile.proxy_id.is_some() {
|
||||
if let Some(pid) = profile.process_id {
|
||||
let _ = PROXY_MANAGER.stop_proxy(app_handle.clone(), pid).await;
|
||||
}
|
||||
}
|
||||
|
||||
// Update proxy settings
|
||||
profile.proxy = proxy.clone();
|
||||
profile.proxy_id = proxy_id.clone();
|
||||
|
||||
// Save the updated profile
|
||||
self
|
||||
@@ -1373,71 +1451,78 @@ impl BrowserRunner {
|
||||
})?;
|
||||
|
||||
// Handle proxy startup/configuration
|
||||
if let Some(proxy_settings) = &proxy {
|
||||
if proxy_settings.enabled && browser_is_running {
|
||||
// Browser is running and proxy is enabled, start new proxy
|
||||
if let Some(pid) = profile.process_id {
|
||||
match PROXY_MANAGER
|
||||
.start_proxy(app_handle.clone(), proxy_settings, pid, Some(profile_name))
|
||||
.await
|
||||
{
|
||||
Ok(internal_proxy_settings) => {
|
||||
let browser_runner = BrowserRunner::new();
|
||||
let profiles_dir = browser_runner.get_profiles_dir();
|
||||
let profile_path = profiles_dir.join(profile.id.to_string()).join("profile");
|
||||
if let Some(proxy_id_ref) = &proxy_id {
|
||||
if let Some(proxy_settings) = PROXY_MANAGER.get_proxy_settings_by_id(proxy_id_ref) {
|
||||
if browser_is_running {
|
||||
// Browser is running and proxy is enabled, start new proxy
|
||||
if let Some(pid) = profile.process_id {
|
||||
match PROXY_MANAGER
|
||||
.start_proxy(app_handle.clone(), &proxy_settings, pid, Some(profile_name))
|
||||
.await
|
||||
{
|
||||
Ok(internal_proxy_settings) => {
|
||||
let browser_runner = BrowserRunner::new();
|
||||
let profiles_dir = browser_runner.get_profiles_dir();
|
||||
let profile_path = profiles_dir.join(profile.id.to_string()).join("profile");
|
||||
|
||||
// Apply the proxy settings with the internal proxy to the profile directory
|
||||
browser_runner
|
||||
.apply_proxy_settings_to_profile(
|
||||
&profile_path,
|
||||
proxy_settings,
|
||||
Some(&internal_proxy_settings),
|
||||
)
|
||||
.map_err(|e| format!("Failed to update profile proxy: {e}"))?;
|
||||
// Apply the proxy settings with the internal proxy to the profile directory
|
||||
browser_runner
|
||||
.apply_proxy_settings_to_profile(
|
||||
&profile_path,
|
||||
&proxy_settings,
|
||||
Some(&internal_proxy_settings),
|
||||
)
|
||||
.map_err(|e| format!("Failed to update profile proxy: {e}"))?;
|
||||
|
||||
println!("Successfully started proxy for profile: {}", profile.name);
|
||||
println!("Successfully started proxy for profile: {}", profile.name);
|
||||
|
||||
// Give the proxy a moment to fully start up
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
|
||||
Some(internal_proxy_settings)
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Failed to start proxy: {e}");
|
||||
// Apply proxy settings without internal proxy
|
||||
let profiles_dir = self.get_profiles_dir();
|
||||
let profile_path = profiles_dir.join(profile.id.to_string()).join("profile");
|
||||
self
|
||||
.apply_proxy_settings_to_profile(&profile_path, proxy_settings, None)
|
||||
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> {
|
||||
format!("Failed to apply proxy settings: {e}").into()
|
||||
})?;
|
||||
None
|
||||
// Give the proxy a moment to fully start up
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Failed to start proxy: {e}");
|
||||
// Apply proxy settings without internal proxy
|
||||
let profiles_dir = self.get_profiles_dir();
|
||||
let profile_path = profiles_dir.join(profile.id.to_string()).join("profile");
|
||||
self
|
||||
.apply_proxy_settings_to_profile(&profile_path, &proxy_settings, None)
|
||||
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> {
|
||||
format!("Failed to apply proxy settings: {e}").into()
|
||||
})?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No PID available, apply proxy settings without internal proxy
|
||||
let profiles_dir = self.get_profiles_dir();
|
||||
let profile_path = profiles_dir.join(profile.id.to_string()).join("profile");
|
||||
self
|
||||
.apply_proxy_settings_to_profile(&profile_path, &proxy_settings, None)
|
||||
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> {
|
||||
format!("Failed to apply proxy settings: {e}").into()
|
||||
})?;
|
||||
}
|
||||
} else {
|
||||
// No PID available, apply proxy settings without internal proxy
|
||||
// Proxy disabled or browser not running, just apply settings
|
||||
let profiles_dir = self.get_profiles_dir();
|
||||
let profile_path = profiles_dir.join(profile.id.to_string()).join("profile");
|
||||
self
|
||||
.apply_proxy_settings_to_profile(&profile_path, proxy_settings, None)
|
||||
.apply_proxy_settings_to_profile(&profile_path, &proxy_settings, None)
|
||||
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> {
|
||||
format!("Failed to apply proxy settings: {e}").into()
|
||||
})?;
|
||||
None
|
||||
}
|
||||
} else {
|
||||
// Proxy disabled or browser not running, just apply settings
|
||||
// Proxy ID provided but proxy not found, disable proxy
|
||||
let profiles_dir = self.get_profiles_dir();
|
||||
let profile_path = profiles_dir.join(profile.id.to_string()).join("profile");
|
||||
self
|
||||
.apply_proxy_settings_to_profile(&profile_path, proxy_settings, None)
|
||||
.disable_proxy_settings_in_profile(&profile_path)
|
||||
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> {
|
||||
format!("Failed to apply proxy settings: {e}").into()
|
||||
format!("Failed to disable proxy settings: {e}").into()
|
||||
})?;
|
||||
None
|
||||
}
|
||||
} else {
|
||||
// No proxy settings, disable proxy
|
||||
// No proxy ID provided, disable proxy
|
||||
let profiles_dir = self.get_profiles_dir();
|
||||
let profile_path = profiles_dir.join(profile.id.to_string()).join("profile");
|
||||
self
|
||||
@@ -1445,8 +1530,7 @@ impl BrowserRunner {
|
||||
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> {
|
||||
format!("Failed to disable proxy settings: {e}").into()
|
||||
})?;
|
||||
None
|
||||
};
|
||||
}
|
||||
|
||||
Ok(profile)
|
||||
}
|
||||
@@ -1563,63 +1647,50 @@ impl BrowserRunner {
|
||||
// Add common Firefox preferences (like disabling default browser check)
|
||||
preferences.extend(self.get_common_firefox_preferences());
|
||||
|
||||
if proxy.enabled {
|
||||
// Use embedded PAC template instead of reading from file
|
||||
const PAC_TEMPLATE: &str = r#"function FindProxyForURL(url, host) {
|
||||
// Use embedded PAC template instead of reading from file
|
||||
const PAC_TEMPLATE: &str = r#"function FindProxyForURL(url, host) {
|
||||
return "{{proxy_url}}";
|
||||
}"#;
|
||||
|
||||
// Format proxy URL based on type and whether we have an internal proxy
|
||||
let proxy_url = if let Some(internal) = internal_proxy {
|
||||
// Use internal proxy as the primary proxy
|
||||
format!("HTTP {}:{}", internal.host, internal.port)
|
||||
} else {
|
||||
// Use user-configured proxy directly
|
||||
match proxy.proxy_type.as_str() {
|
||||
"http" => format!("HTTP {}:{}", proxy.host, proxy.port),
|
||||
"https" => format!("HTTPS {}:{}", proxy.host, proxy.port),
|
||||
"socks4" => format!("SOCKS4 {}:{}", proxy.host, proxy.port),
|
||||
"socks5" => format!("SOCKS5 {}:{}", proxy.host, proxy.port),
|
||||
_ => return Err(format!("Unsupported proxy type: {}", proxy.proxy_type).into()),
|
||||
}
|
||||
};
|
||||
|
||||
// Replace placeholders in PAC file
|
||||
let pac_content = PAC_TEMPLATE
|
||||
.replace("{{proxy_url}}", &proxy_url)
|
||||
.replace("{{proxy_credentials}}", ""); // Credentials are now handled by the PAC file
|
||||
|
||||
// Save PAC file in UUID directory
|
||||
let pac_path = uuid_dir.join("proxy.pac");
|
||||
fs::write(&pac_path, pac_content)?;
|
||||
|
||||
// Configure Firefox to use the PAC file
|
||||
preferences.extend([
|
||||
"user_pref(\"network.proxy.type\", 2);".to_string(),
|
||||
format!(
|
||||
"user_pref(\"network.proxy.autoconfig_url\", \"file://{}\");",
|
||||
pac_path.to_string_lossy()
|
||||
),
|
||||
"user_pref(\"network.proxy.failover_direct\", false);".to_string(),
|
||||
"user_pref(\"network.proxy.socks_remote_dns\", true);".to_string(),
|
||||
"user_pref(\"network.proxy.no_proxies_on\", \"\");".to_string(),
|
||||
"user_pref(\"signon.autologin.proxy\", true);".to_string(),
|
||||
"user_pref(\"network.proxy.share_proxy_settings\", false);".to_string(),
|
||||
"user_pref(\"network.automatic-ntlm-auth.allow-proxies\", false);".to_string(),
|
||||
"user_pref(\"network.auth-use-sspi\", false);".to_string(),
|
||||
]);
|
||||
// Format proxy URL based on type and whether we have an internal proxy
|
||||
let proxy_url = if let Some(internal) = internal_proxy {
|
||||
// Use internal proxy as the primary proxy
|
||||
format!("HTTP {}:{}", internal.host, internal.port)
|
||||
} else {
|
||||
preferences.push("user_pref(\"network.proxy.type\", 0);".to_string());
|
||||
preferences.push("user_pref(\"network.proxy.failover_direct\", true);".to_string());
|
||||
// Use user-configured proxy directly
|
||||
match proxy.proxy_type.as_str() {
|
||||
"http" => format!("HTTP {}:{}", proxy.host, proxy.port),
|
||||
"https" => format!("HTTPS {}:{}", proxy.host, proxy.port),
|
||||
"socks4" => format!("SOCKS4 {}:{}", proxy.host, proxy.port),
|
||||
"socks5" => format!("SOCKS5 {}:{}", proxy.host, proxy.port),
|
||||
_ => return Err(format!("Unsupported proxy type: {}", proxy.proxy_type).into()),
|
||||
}
|
||||
};
|
||||
|
||||
let pac_content = "function FindProxyForURL(url, host) { return 'DIRECT'; }";
|
||||
let pac_path = uuid_dir.join("proxy.pac");
|
||||
fs::write(&pac_path, pac_content)?;
|
||||
preferences.push(format!(
|
||||
// Replace placeholders in PAC file
|
||||
let pac_content = PAC_TEMPLATE
|
||||
.replace("{{proxy_url}}", &proxy_url)
|
||||
.replace("{{proxy_credentials}}", ""); // Credentials are now handled by the PAC file
|
||||
|
||||
// Save PAC file in UUID directory
|
||||
let pac_path = uuid_dir.join("proxy.pac");
|
||||
fs::write(&pac_path, pac_content)?;
|
||||
|
||||
// Configure Firefox to use the PAC file
|
||||
preferences.extend([
|
||||
"user_pref(\"network.proxy.type\", 2);".to_string(),
|
||||
format!(
|
||||
"user_pref(\"network.proxy.autoconfig_url\", \"file://{}\");",
|
||||
pac_path.to_string_lossy()
|
||||
));
|
||||
}
|
||||
),
|
||||
"user_pref(\"network.proxy.failover_direct\", false);".to_string(),
|
||||
"user_pref(\"network.proxy.socks_remote_dns\", true);".to_string(),
|
||||
"user_pref(\"network.proxy.no_proxies_on\", \"\");".to_string(),
|
||||
"user_pref(\"signon.autologin.proxy\", true);".to_string(),
|
||||
"user_pref(\"network.proxy.share_proxy_settings\", false);".to_string(),
|
||||
"user_pref(\"network.automatic-ntlm-auth.allow-proxies\", false);".to_string(),
|
||||
"user_pref(\"network.auth-use-sspi\", false);".to_string(),
|
||||
]);
|
||||
|
||||
// Write settings to user.js file
|
||||
fs::write(user_js_path, preferences.join("\n"))?;
|
||||
@@ -1726,10 +1797,16 @@ impl BrowserRunner {
|
||||
}
|
||||
|
||||
// For Chromium browsers, use local proxy settings if available
|
||||
// For Firefox browsers, continue using original proxy settings (handled via PAC files)
|
||||
// For Firefox browsers, proxy settings are handled via PAC files
|
||||
let stored_proxy_settings = profile
|
||||
.proxy_id
|
||||
.as_ref()
|
||||
.and_then(|id| PROXY_MANAGER.get_proxy_settings_by_id(id));
|
||||
let proxy_for_launch_args = match browser_type {
|
||||
BrowserType::Chromium | BrowserType::Brave => local_proxy_settings.or(profile.proxy.as_ref()),
|
||||
_ => profile.proxy.as_ref(),
|
||||
BrowserType::Chromium | BrowserType::Brave => {
|
||||
local_proxy_settings.or(stored_proxy_settings.as_ref())
|
||||
}
|
||||
_ => None, // Firefox browsers use PAC files, not launch args
|
||||
};
|
||||
|
||||
// Get profile data path and launch arguments
|
||||
@@ -2362,8 +2439,8 @@ impl BrowserRunner {
|
||||
}
|
||||
|
||||
// Handle proxy management based on browser status
|
||||
if let Some(proxy) = &inner_profile.proxy {
|
||||
if proxy.enabled {
|
||||
if let Some(proxy_id) = &inner_profile.proxy_id {
|
||||
if let Some(proxy) = PROXY_MANAGER.get_proxy_settings_by_id(proxy_id) {
|
||||
if is_running {
|
||||
// Browser is running, check if proxy is active
|
||||
let proxy_active = PROXY_MANAGER
|
||||
@@ -2372,27 +2449,23 @@ impl BrowserRunner {
|
||||
|
||||
if !proxy_active {
|
||||
// Browser is running but proxy is not - restart the proxy
|
||||
if let Some(proxy_settings) = PROXY_MANAGER.get_profile_proxy_info(&inner_profile.name)
|
||||
match PROXY_MANAGER
|
||||
.start_proxy(
|
||||
app_handle,
|
||||
&proxy,
|
||||
inner_profile.process_id.unwrap(),
|
||||
Some(&inner_profile.name),
|
||||
)
|
||||
.await
|
||||
{
|
||||
// Restart the proxy with the same configuration
|
||||
match PROXY_MANAGER
|
||||
.start_proxy(
|
||||
app_handle,
|
||||
&proxy_settings,
|
||||
inner_profile.process_id.unwrap(),
|
||||
Some(&inner_profile.name),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
println!("Restarted proxy for profile {}", inner_profile.name);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"Failed to restart proxy for profile {}: {}",
|
||||
inner_profile.name, e
|
||||
);
|
||||
}
|
||||
Ok(_) => {
|
||||
println!("Restarted proxy for profile {}", inner_profile.name);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"Failed to restart proxy for profile {}: {}",
|
||||
inner_profile.name, e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2840,11 +2913,11 @@ pub fn create_browser_profile(
|
||||
browser: String,
|
||||
version: String,
|
||||
release_type: String,
|
||||
proxy: Option<ProxySettings>,
|
||||
proxy_id: Option<String>,
|
||||
) -> Result<BrowserProfile, String> {
|
||||
let browser_runner = BrowserRunner::new();
|
||||
browser_runner
|
||||
.create_profile(&name, &browser, &version, &release_type, proxy)
|
||||
.create_profile(&name, &browser, &version, &release_type, proxy_id)
|
||||
.map_err(|e| format!("Failed to create profile: {e}"))
|
||||
}
|
||||
|
||||
@@ -2870,14 +2943,14 @@ pub async fn launch_browser_profile(
|
||||
// If the profile has proxy settings, we need to start the proxy first
|
||||
// and update the profile with proxy settings before launching
|
||||
let profile_for_launch = profile.clone();
|
||||
if let Some(proxy) = &profile.proxy {
|
||||
if proxy.enabled {
|
||||
if let Some(proxy_id) = &profile.proxy_id {
|
||||
if let Some(proxy) = PROXY_MANAGER.get_proxy_settings_by_id(proxy_id) {
|
||||
// Use a temporary PID (1) to start the proxy, we'll update it after browser launch
|
||||
let temp_pid = 1u32;
|
||||
|
||||
// Start the proxy first
|
||||
match PROXY_MANAGER
|
||||
.start_proxy(app_handle.clone(), proxy, temp_pid, Some(&profile.name))
|
||||
.start_proxy(app_handle.clone(), &proxy, temp_pid, Some(&profile.name))
|
||||
.await
|
||||
{
|
||||
Ok(internal_proxy) => {
|
||||
@@ -2890,7 +2963,7 @@ pub async fn launch_browser_profile(
|
||||
|
||||
// Apply the proxy settings with the internal proxy to the profile directory
|
||||
browser_runner
|
||||
.apply_proxy_settings_to_profile(&profile_path, proxy, Some(&internal_proxy))
|
||||
.apply_proxy_settings_to_profile(&profile_path, &proxy, Some(&internal_proxy))
|
||||
.map_err(|e| format!("Failed to update profile proxy: {e}"))?;
|
||||
|
||||
println!("Successfully started proxy for profile: {}", profile.name);
|
||||
@@ -2907,7 +2980,7 @@ pub async fn launch_browser_profile(
|
||||
|
||||
// Apply proxy settings without internal proxy
|
||||
browser_runner
|
||||
.apply_proxy_settings_to_profile(&profile_path, proxy, None)
|
||||
.apply_proxy_settings_to_profile(&profile_path, &proxy, None)
|
||||
.map_err(|e| format!("Failed to update profile proxy: {e}"))?;
|
||||
}
|
||||
}
|
||||
@@ -2930,8 +3003,8 @@ pub async fn launch_browser_profile(
|
||||
})?;
|
||||
|
||||
// Now update the proxy with the correct PID if we have one
|
||||
if let Some(proxy) = &profile.proxy {
|
||||
if proxy.enabled {
|
||||
if let Some(proxy_id) = &profile.proxy_id {
|
||||
if PROXY_MANAGER.get_proxy_settings_by_id(proxy_id).is_some() {
|
||||
if let Some(actual_pid) = updated_profile.process_id {
|
||||
// Update the proxy manager with the correct PID
|
||||
match PROXY_MANAGER.update_proxy_pid(1u32, actual_pid) {
|
||||
@@ -2953,11 +3026,11 @@ pub async fn launch_browser_profile(
|
||||
pub async fn update_profile_proxy(
|
||||
app_handle: tauri::AppHandle,
|
||||
profile_name: String,
|
||||
proxy: Option<ProxySettings>,
|
||||
proxy_id: Option<String>,
|
||||
) -> Result<BrowserProfile, String> {
|
||||
let browser_runner = BrowserRunner::new();
|
||||
browser_runner
|
||||
.update_profile_proxy(app_handle, &profile_name, proxy)
|
||||
.update_profile_proxy(app_handle, &profile_name, proxy_id)
|
||||
.await
|
||||
.map_err(|e| format!("Failed to update profile: {e}"))
|
||||
}
|
||||
@@ -3132,7 +3205,7 @@ pub fn create_browser_profile_new(
|
||||
browser_str: String,
|
||||
version: String,
|
||||
release_type: String,
|
||||
proxy: Option<ProxySettings>,
|
||||
proxy_id: Option<String>,
|
||||
) -> Result<BrowserProfile, String> {
|
||||
let browser_type =
|
||||
BrowserType::from_str(&browser_str).map_err(|e| format!("Invalid browser type: {e}"))?;
|
||||
@@ -3141,7 +3214,7 @@ pub fn create_browser_profile_new(
|
||||
browser_type.as_str().to_string(),
|
||||
version,
|
||||
release_type,
|
||||
proxy,
|
||||
proxy_id,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3245,7 +3318,7 @@ mod tests {
|
||||
assert_eq!(profile.name, "Test Profile");
|
||||
assert_eq!(profile.browser, "firefox");
|
||||
assert_eq!(profile.version, "139.0");
|
||||
assert!(profile.proxy.is_none());
|
||||
assert!(profile.proxy_id.is_none());
|
||||
assert!(profile.process_id.is_none());
|
||||
}
|
||||
|
||||
@@ -3253,8 +3326,7 @@ mod tests {
|
||||
fn test_create_profile_with_proxy() {
|
||||
let (runner, _temp_dir) = create_test_browser_runner();
|
||||
|
||||
let proxy = ProxySettings {
|
||||
enabled: true,
|
||||
let _proxy = ProxySettings {
|
||||
proxy_type: "http".to_string(),
|
||||
host: "127.0.0.1".to_string(),
|
||||
port: 8080,
|
||||
@@ -3268,16 +3340,13 @@ mod tests {
|
||||
"firefox",
|
||||
"139.0",
|
||||
"stable",
|
||||
Some(proxy.clone()),
|
||||
None, // Tests now use separate proxy storage system
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(profile.name, "Test Profile with Proxy");
|
||||
assert!(profile.proxy.is_some());
|
||||
let profile_proxy = profile.proxy.unwrap();
|
||||
assert_eq!(profile_proxy.proxy_type, "http");
|
||||
assert_eq!(profile_proxy.host, "127.0.0.1");
|
||||
assert_eq!(profile_proxy.port, 8080);
|
||||
// Note: Proxy settings are now stored separately in the proxy storage system
|
||||
assert!(profile.proxy_id.is_none()); // No proxy assigned in this test
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -3440,9 +3509,8 @@ mod tests {
|
||||
assert!(user_js_content.contains("app.update.enabled"));
|
||||
assert!(user_js_content.contains("app.update.auto"));
|
||||
|
||||
// Create profile with proxy
|
||||
let proxy = ProxySettings {
|
||||
enabled: true,
|
||||
// Create profile with proxy (proxy object unused in new architecture)
|
||||
let _proxy = ProxySettings {
|
||||
proxy_type: "http".to_string(),
|
||||
host: "127.0.0.1".to_string(),
|
||||
port: 8080,
|
||||
@@ -3456,7 +3524,7 @@ mod tests {
|
||||
"firefox",
|
||||
"139.0",
|
||||
"stable",
|
||||
Some(proxy),
|
||||
None, // Tests now use separate proxy storage system
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -174,6 +174,39 @@ async fn check_and_handle_startup_url(app_handle: tauri::AppHandle) -> Result<bo
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn create_stored_proxy(
|
||||
name: String,
|
||||
proxy_settings: crate::browser::ProxySettings,
|
||||
) -> Result<crate::proxy_manager::StoredProxy, String> {
|
||||
crate::proxy_manager::PROXY_MANAGER
|
||||
.create_stored_proxy(name, proxy_settings)
|
||||
.map_err(|e| format!("Failed to create stored proxy: {e}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn get_stored_proxies() -> Result<Vec<crate::proxy_manager::StoredProxy>, String> {
|
||||
Ok(crate::proxy_manager::PROXY_MANAGER.get_stored_proxies())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn update_stored_proxy(
|
||||
proxy_id: String,
|
||||
name: Option<String>,
|
||||
proxy_settings: Option<crate::browser::ProxySettings>,
|
||||
) -> Result<crate::proxy_manager::StoredProxy, String> {
|
||||
crate::proxy_manager::PROXY_MANAGER
|
||||
.update_stored_proxy(&proxy_id, name, proxy_settings)
|
||||
.map_err(|e| format!("Failed to update stored proxy: {e}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn delete_stored_proxy(proxy_id: String) -> Result<(), String> {
|
||||
crate::proxy_manager::PROXY_MANAGER
|
||||
.delete_stored_proxy(&proxy_id)
|
||||
.map_err(|e| format!("Failed to delete stored proxy: {e}"))
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
@@ -396,6 +429,10 @@ pub fn run() {
|
||||
import_browser_profile,
|
||||
check_missing_binaries,
|
||||
ensure_all_binaries_exist,
|
||||
create_stored_proxy,
|
||||
get_stored_proxies,
|
||||
update_stored_proxy,
|
||||
delete_stored_proxy,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
||||
@@ -685,7 +685,7 @@ impl ProfileImporter {
|
||||
name: new_profile_name.to_string(),
|
||||
browser: browser_type.to_string(),
|
||||
version: available_versions,
|
||||
proxy: None,
|
||||
proxy_id: None,
|
||||
process_id: None,
|
||||
last_launch: None,
|
||||
release_type: "stable".to_string(),
|
||||
|
||||
+230
-18
@@ -1,6 +1,9 @@
|
||||
use directories::BaseDirs;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Mutex;
|
||||
use tauri_plugin_shell::ShellExt;
|
||||
|
||||
@@ -17,19 +20,237 @@ pub struct ProxyInfo {
|
||||
pub local_port: u16,
|
||||
}
|
||||
|
||||
// Global proxy manager to track active proxies
|
||||
// Stored proxy configuration with name and ID for reuse
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct StoredProxy {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub proxy_settings: ProxySettings,
|
||||
}
|
||||
|
||||
impl StoredProxy {
|
||||
pub fn new(name: String, proxy_settings: ProxySettings) -> Self {
|
||||
Self {
|
||||
id: uuid::Uuid::new_v4().to_string(),
|
||||
name,
|
||||
proxy_settings,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_settings(&mut self, proxy_settings: ProxySettings) {
|
||||
self.proxy_settings = proxy_settings;
|
||||
}
|
||||
|
||||
pub fn update_name(&mut self, name: String) {
|
||||
self.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
// Global proxy manager to track active proxies and stored proxy configurations
|
||||
pub struct ProxyManager {
|
||||
active_proxies: Mutex<HashMap<u32, ProxyInfo>>, // Maps browser process ID to proxy info
|
||||
// Store proxy info by profile name for persistence across browser restarts
|
||||
profile_proxies: Mutex<HashMap<String, ProxySettings>>, // Maps profile name to proxy settings
|
||||
stored_proxies: Mutex<HashMap<String, StoredProxy>>, // Maps proxy ID to stored proxy
|
||||
base_dirs: BaseDirs,
|
||||
}
|
||||
|
||||
impl ProxyManager {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
let base_dirs = BaseDirs::new().expect("Failed to get base directories");
|
||||
let manager = Self {
|
||||
active_proxies: Mutex::new(HashMap::new()),
|
||||
profile_proxies: Mutex::new(HashMap::new()),
|
||||
stored_proxies: Mutex::new(HashMap::new()),
|
||||
base_dirs,
|
||||
};
|
||||
|
||||
// Load stored proxies on initialization
|
||||
if let Err(e) = manager.load_stored_proxies() {
|
||||
eprintln!("Warning: Failed to load stored proxies: {e}");
|
||||
}
|
||||
|
||||
manager
|
||||
}
|
||||
|
||||
// Get the path to the proxies directory
|
||||
fn get_proxies_dir(&self) -> PathBuf {
|
||||
let mut path = self.base_dirs.data_local_dir().to_path_buf();
|
||||
path.push(if cfg!(debug_assertions) {
|
||||
"DonutBrowserDev"
|
||||
} else {
|
||||
"DonutBrowser"
|
||||
});
|
||||
path.push("proxies");
|
||||
path
|
||||
}
|
||||
|
||||
// Get the path to a specific proxy file
|
||||
fn get_proxy_file_path(&self, proxy_id: &str) -> PathBuf {
|
||||
self.get_proxies_dir().join(format!("{proxy_id}.json"))
|
||||
}
|
||||
|
||||
// Load stored proxies from disk
|
||||
fn load_stored_proxies(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let proxies_dir = self.get_proxies_dir();
|
||||
|
||||
if !proxies_dir.exists() {
|
||||
return Ok(()); // No proxies directory yet
|
||||
}
|
||||
|
||||
let mut stored_proxies = self.stored_proxies.lock().unwrap();
|
||||
|
||||
// Read all JSON files from the proxies directory
|
||||
for entry in fs::read_dir(&proxies_dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
|
||||
if path.extension().is_some_and(|ext| ext == "json") {
|
||||
let content = fs::read_to_string(&path)?;
|
||||
let proxy: StoredProxy = serde_json::from_str(&content)?;
|
||||
stored_proxies.insert(proxy.id.clone(), proxy);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Save a single proxy to disk
|
||||
fn save_proxy(&self, proxy: &StoredProxy) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let proxies_dir = self.get_proxies_dir();
|
||||
|
||||
// Ensure directory exists
|
||||
fs::create_dir_all(&proxies_dir)?;
|
||||
|
||||
let proxy_file = self.get_proxy_file_path(&proxy.id);
|
||||
let content = serde_json::to_string_pretty(proxy)?;
|
||||
fs::write(&proxy_file, content)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Delete a proxy file from disk
|
||||
fn delete_proxy_file(&self, proxy_id: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let proxy_file = self.get_proxy_file_path(proxy_id);
|
||||
if proxy_file.exists() {
|
||||
fs::remove_file(proxy_file)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Create a new stored proxy
|
||||
pub fn create_stored_proxy(
|
||||
&self,
|
||||
name: String,
|
||||
proxy_settings: ProxySettings,
|
||||
) -> Result<StoredProxy, String> {
|
||||
// Check if name already exists
|
||||
{
|
||||
let stored_proxies = self.stored_proxies.lock().unwrap();
|
||||
if stored_proxies.values().any(|p| p.name == name) {
|
||||
return Err(format!("Proxy with name '{name}' already exists"));
|
||||
}
|
||||
}
|
||||
|
||||
let stored_proxy = StoredProxy::new(name, proxy_settings);
|
||||
|
||||
{
|
||||
let mut stored_proxies = self.stored_proxies.lock().unwrap();
|
||||
stored_proxies.insert(stored_proxy.id.clone(), stored_proxy.clone());
|
||||
}
|
||||
|
||||
if let Err(e) = self.save_proxy(&stored_proxy) {
|
||||
eprintln!("Warning: Failed to save proxy: {e}");
|
||||
}
|
||||
|
||||
Ok(stored_proxy)
|
||||
}
|
||||
|
||||
// Get all stored proxies
|
||||
pub fn get_stored_proxies(&self) -> Vec<StoredProxy> {
|
||||
let stored_proxies = self.stored_proxies.lock().unwrap();
|
||||
stored_proxies.values().cloned().collect()
|
||||
}
|
||||
|
||||
// Get a stored proxy by ID
|
||||
#[allow(dead_code)]
|
||||
pub fn get_stored_proxy(&self, proxy_id: &str) -> Option<StoredProxy> {
|
||||
let stored_proxies = self.stored_proxies.lock().unwrap();
|
||||
stored_proxies.get(proxy_id).cloned()
|
||||
}
|
||||
|
||||
// Update a stored proxy
|
||||
pub fn update_stored_proxy(
|
||||
&self,
|
||||
proxy_id: &str,
|
||||
name: Option<String>,
|
||||
proxy_settings: Option<ProxySettings>,
|
||||
) -> Result<StoredProxy, String> {
|
||||
// First, check for conflicts without holding a mutable reference
|
||||
{
|
||||
let stored_proxies = self.stored_proxies.lock().unwrap();
|
||||
|
||||
// Check if proxy exists
|
||||
if !stored_proxies.contains_key(proxy_id) {
|
||||
return Err(format!("Proxy with ID '{proxy_id}' not found"));
|
||||
}
|
||||
|
||||
// Check if new name conflicts with existing proxies
|
||||
if let Some(ref new_name) = name {
|
||||
if stored_proxies
|
||||
.values()
|
||||
.any(|p| p.id != proxy_id && p.name == *new_name)
|
||||
{
|
||||
return Err(format!("Proxy with name '{new_name}' already exists"));
|
||||
}
|
||||
}
|
||||
} // Release the lock here
|
||||
|
||||
// Now get mutable access for updates
|
||||
let updated_proxy = {
|
||||
let mut stored_proxies = self.stored_proxies.lock().unwrap();
|
||||
let stored_proxy = stored_proxies.get_mut(proxy_id).unwrap(); // Safe because we checked above
|
||||
|
||||
if let Some(new_name) = name {
|
||||
stored_proxy.update_name(new_name);
|
||||
}
|
||||
|
||||
if let Some(new_settings) = proxy_settings {
|
||||
stored_proxy.update_settings(new_settings);
|
||||
}
|
||||
|
||||
stored_proxy.clone()
|
||||
};
|
||||
|
||||
if let Err(e) = self.save_proxy(&updated_proxy) {
|
||||
eprintln!("Warning: Failed to save proxy: {e}");
|
||||
}
|
||||
|
||||
Ok(updated_proxy)
|
||||
}
|
||||
|
||||
// Delete a stored proxy
|
||||
pub fn delete_stored_proxy(&self, proxy_id: &str) -> Result<(), String> {
|
||||
{
|
||||
let mut stored_proxies = self.stored_proxies.lock().unwrap();
|
||||
if stored_proxies.remove(proxy_id).is_none() {
|
||||
return Err(format!("Proxy with ID '{proxy_id}' not found"));
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(e) = self.delete_proxy_file(proxy_id) {
|
||||
eprintln!("Warning: Failed to delete proxy file: {e}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Get proxy settings for a stored proxy ID
|
||||
pub fn get_proxy_settings_by_id(&self, proxy_id: &str) -> Option<ProxySettings> {
|
||||
let stored_proxies = self.stored_proxies.lock().unwrap();
|
||||
stored_proxies
|
||||
.get(proxy_id)
|
||||
.map(|p| p.proxy_settings.clone())
|
||||
}
|
||||
|
||||
// Start a proxy for given proxy settings and associate it with a browser process ID
|
||||
@@ -45,8 +266,7 @@ impl ProxyManager {
|
||||
let proxies = self.active_proxies.lock().unwrap();
|
||||
if let Some(proxy) = proxies.get(&browser_pid) {
|
||||
return Ok(ProxySettings {
|
||||
enabled: true,
|
||||
proxy_type: proxy.upstream_type.clone(),
|
||||
proxy_type: "http".to_string(),
|
||||
host: "127.0.0.1".to_string(), // Use 127.0.0.1 instead of localhost for better compatibility
|
||||
port: proxy.local_port,
|
||||
username: None,
|
||||
@@ -154,7 +374,6 @@ impl ProxyManager {
|
||||
|
||||
// Return proxy settings for the browser
|
||||
Ok(ProxySettings {
|
||||
enabled: true,
|
||||
proxy_type: "http".to_string(),
|
||||
host: "127.0.0.1".to_string(), // Use 127.0.0.1 instead of localhost for better compatibility
|
||||
port: proxy_info.local_port,
|
||||
@@ -202,7 +421,6 @@ impl ProxyManager {
|
||||
pub fn get_proxy_settings(&self, browser_pid: u32) -> Option<ProxySettings> {
|
||||
let proxies = self.active_proxies.lock().unwrap();
|
||||
proxies.get(&browser_pid).map(|proxy| ProxySettings {
|
||||
enabled: true,
|
||||
proxy_type: "http".to_string(),
|
||||
host: "127.0.0.1".to_string(), // Use 127.0.0.1 instead of localhost for better compatibility
|
||||
port: proxy.local_port,
|
||||
@@ -212,6 +430,7 @@ impl ProxyManager {
|
||||
}
|
||||
|
||||
// Get stored proxy info for a profile
|
||||
#[allow(dead_code)]
|
||||
pub fn get_profile_proxy_info(&self, profile_name: &str) -> Option<ProxySettings> {
|
||||
let profile_proxies = self.profile_proxies.lock().unwrap();
|
||||
profile_proxies.get(profile_name).cloned()
|
||||
@@ -321,7 +540,6 @@ mod tests {
|
||||
let proxy_manager = ProxyManager::new();
|
||||
|
||||
let proxy_settings = ProxySettings {
|
||||
enabled: true,
|
||||
proxy_type: "socks5".to_string(),
|
||||
host: "127.0.0.1".to_string(),
|
||||
port: 1080,
|
||||
@@ -373,9 +591,8 @@ mod tests {
|
||||
let proxy_settings = proxy_manager.get_proxy_settings(browser_pid);
|
||||
assert!(proxy_settings.is_some());
|
||||
let settings = proxy_settings.unwrap();
|
||||
assert!(settings.enabled);
|
||||
assert_eq!(settings.host, "127.0.0.1");
|
||||
assert_eq!(settings.port, 8080);
|
||||
assert!(settings.host == "127.0.0.1");
|
||||
assert!(settings.port == 8080);
|
||||
|
||||
// Test non-existent browser PID
|
||||
let non_existent = proxy_manager.get_proxy_settings(99999);
|
||||
@@ -386,7 +603,6 @@ mod tests {
|
||||
fn test_proxy_settings_validation() {
|
||||
// Test valid proxy settings
|
||||
let valid_settings = ProxySettings {
|
||||
enabled: true,
|
||||
proxy_type: "http".to_string(),
|
||||
host: "127.0.0.1".to_string(),
|
||||
port: 8080,
|
||||
@@ -394,14 +610,11 @@ mod tests {
|
||||
password: Some("pass".to_string()),
|
||||
};
|
||||
|
||||
assert!(valid_settings.enabled);
|
||||
assert_eq!(valid_settings.proxy_type, "http");
|
||||
assert!(!valid_settings.host.is_empty());
|
||||
assert!(valid_settings.port > 0);
|
||||
|
||||
// Test disabled proxy settings
|
||||
let disabled_settings = ProxySettings {
|
||||
enabled: false,
|
||||
// Test proxy settings with empty values
|
||||
let empty_settings = ProxySettings {
|
||||
proxy_type: "http".to_string(),
|
||||
host: "".to_string(),
|
||||
port: 0,
|
||||
@@ -409,7 +622,7 @@ mod tests {
|
||||
password: None,
|
||||
};
|
||||
|
||||
assert!(!disabled_settings.enabled);
|
||||
assert!(empty_settings.host.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -563,7 +776,6 @@ mod tests {
|
||||
#[test]
|
||||
fn test_proxy_command_construction() {
|
||||
let proxy_settings = ProxySettings {
|
||||
enabled: true,
|
||||
proxy_type: "http".to_string(),
|
||||
host: "proxy.example.com".to_string(),
|
||||
port: 8080,
|
||||
|
||||
Reference in New Issue
Block a user