mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-07-24 21:30:58 +02:00
refactor: better custom name
This commit is contained in:
@@ -39,6 +39,7 @@ pub struct ApiProfile {
|
||||
pub group_id: Option<String>,
|
||||
pub tags: Vec<String>,
|
||||
pub is_running: bool,
|
||||
pub proxy_bypass_rules: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
@@ -79,6 +80,7 @@ pub struct UpdateProfileRequest {
|
||||
pub group_id: Option<String>,
|
||||
pub tags: Option<Vec<String>>,
|
||||
pub extension_group_id: Option<String>,
|
||||
pub proxy_bypass_rules: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -487,6 +489,7 @@ async fn get_profiles() -> Result<Json<ApiProfilesResponse>, StatusCode> {
|
||||
group_id: profile.group_id.clone(),
|
||||
tags: profile.tags.clone(),
|
||||
is_running: profile.process_id.is_some(), // Simple check based on process_id
|
||||
proxy_bypass_rules: profile.proxy_bypass_rules.clone(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -541,6 +544,7 @@ async fn get_profile(
|
||||
group_id: profile.group_id.clone(),
|
||||
tags: profile.tags.clone(),
|
||||
is_running: profile.process_id.is_some(), // Simple check based on process_id
|
||||
proxy_bypass_rules: profile.proxy_bypass_rules.clone(),
|
||||
},
|
||||
}))
|
||||
} else {
|
||||
@@ -639,6 +643,7 @@ async fn create_profile(
|
||||
group_id: profile.group_id,
|
||||
tags: profile.tags,
|
||||
is_running: false,
|
||||
proxy_bypass_rules: profile.proxy_bypass_rules,
|
||||
},
|
||||
}))
|
||||
}
|
||||
@@ -756,6 +761,15 @@ async fn update_profile(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(proxy_bypass_rules) = request.proxy_bypass_rules {
|
||||
if profile_manager
|
||||
.update_profile_proxy_bypass_rules(&state.app_handle, &id, proxy_bypass_rules)
|
||||
.is_err()
|
||||
{
|
||||
return Err(StatusCode::BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
// Return updated profile
|
||||
get_profile(Path(id), State(state)).await
|
||||
}
|
||||
|
||||
@@ -2726,6 +2726,53 @@ pub async fn kill_browser_profile(
|
||||
profile.name,
|
||||
profile.id
|
||||
);
|
||||
|
||||
// Auto-update non-running profiles and cleanup unused binaries
|
||||
let browser_for_update = profile.browser.clone();
|
||||
let app_handle_for_update = app_handle.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let registry = crate::downloaded_browsers_registry::DownloadedBrowsersRegistry::instance();
|
||||
let mut versions = registry.get_downloaded_versions(&browser_for_update);
|
||||
if !versions.is_empty() {
|
||||
versions.sort_by(|a, b| crate::api_client::compare_versions(b, a));
|
||||
let latest_version = &versions[0];
|
||||
|
||||
let auto_updater = crate::auto_updater::AutoUpdater::instance();
|
||||
match auto_updater
|
||||
.auto_update_profile_versions(
|
||||
&app_handle_for_update,
|
||||
&browser_for_update,
|
||||
latest_version,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(updated) => {
|
||||
if !updated.is_empty() {
|
||||
log::info!(
|
||||
"Auto-updated {} profiles after stop: {:?}",
|
||||
updated.len(),
|
||||
updated
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Failed to auto-update profile versions after stop: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match registry.cleanup_unused_binaries() {
|
||||
Ok(cleaned) => {
|
||||
if !cleaned.is_empty() {
|
||||
log::info!("Cleaned up unused binaries after stop: {:?}", cleaned);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Failed to cleanup unused binaries after stop: {e}");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
|
||||
@@ -1033,6 +1033,51 @@ impl Downloader {
|
||||
tokens.remove(&download_key);
|
||||
}
|
||||
|
||||
// Auto-update non-running profiles to the new version and cleanup unused binaries
|
||||
{
|
||||
let browser_for_update = browser_str.clone();
|
||||
let version_for_update = version.clone();
|
||||
let app_handle_for_update = app_handle.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let auto_updater = crate::auto_updater::AutoUpdater::instance();
|
||||
match auto_updater
|
||||
.auto_update_profile_versions(
|
||||
&app_handle_for_update,
|
||||
&browser_for_update,
|
||||
&version_for_update,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(updated) => {
|
||||
if !updated.is_empty() {
|
||||
log::info!(
|
||||
"Auto-updated {} profiles to {} {}: {:?}",
|
||||
updated.len(),
|
||||
browser_for_update,
|
||||
version_for_update,
|
||||
updated
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Failed to auto-update profile versions: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
let registry = crate::downloaded_browsers_registry::DownloadedBrowsersRegistry::instance();
|
||||
match registry.cleanup_unused_binaries() {
|
||||
Ok(cleaned) => {
|
||||
if !cleaned.is_empty() {
|
||||
log::info!("Cleaned up unused binaries after download: {:?}", cleaned);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Failed to cleanup unused binaries: {e}");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok(version)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -725,6 +725,27 @@ impl McpServer {
|
||||
"required": ["profile_id"]
|
||||
}),
|
||||
},
|
||||
McpTool {
|
||||
name: "update_profile_proxy_bypass_rules".to_string(),
|
||||
description:
|
||||
"Update proxy bypass rules for a profile. Requests matching these rules will connect directly, bypassing the proxy."
|
||||
.to_string(),
|
||||
input_schema: serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"profile_id": {
|
||||
"type": "string",
|
||||
"description": "The UUID of the profile to update"
|
||||
},
|
||||
"rules": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Array of bypass rules. Supports hostnames (e.g. 'example.com'), IP addresses, and regex patterns."
|
||||
}
|
||||
},
|
||||
"required": ["profile_id", "rules"]
|
||||
}),
|
||||
},
|
||||
McpTool {
|
||||
name: "list_extensions".to_string(),
|
||||
description: "List all managed browser extensions. Requires Pro subscription.".to_string(),
|
||||
@@ -889,6 +910,11 @@ impl McpServer {
|
||||
// Fingerprint management
|
||||
"get_profile_fingerprint" => self.handle_get_profile_fingerprint(&arguments).await,
|
||||
"update_profile_fingerprint" => self.handle_update_profile_fingerprint(&arguments).await,
|
||||
"update_profile_proxy_bypass_rules" => {
|
||||
self
|
||||
.handle_update_profile_proxy_bypass_rules(&arguments)
|
||||
.await
|
||||
}
|
||||
// Extension management
|
||||
"list_extensions" => self.handle_list_extensions().await,
|
||||
"list_extension_groups" => self.handle_list_extension_groups().await,
|
||||
@@ -2141,6 +2167,54 @@ impl McpServer {
|
||||
}))
|
||||
}
|
||||
|
||||
async fn handle_update_profile_proxy_bypass_rules(
|
||||
&self,
|
||||
arguments: &serde_json::Value,
|
||||
) -> Result<serde_json::Value, McpError> {
|
||||
let profile_id = arguments
|
||||
.get("profile_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| McpError {
|
||||
code: -32602,
|
||||
message: "Missing profile_id".to_string(),
|
||||
})?;
|
||||
|
||||
let rules: Vec<String> = arguments
|
||||
.get("rules")
|
||||
.and_then(|v| v.as_array())
|
||||
.ok_or_else(|| McpError {
|
||||
code: -32602,
|
||||
message: "Missing rules array".to_string(),
|
||||
})?
|
||||
.iter()
|
||||
.filter_map(|v| v.as_str().map(|s| s.to_string()))
|
||||
.collect();
|
||||
|
||||
let inner = self.inner.lock().await;
|
||||
let app_handle = inner.app_handle.as_ref().ok_or_else(|| McpError {
|
||||
code: -32000,
|
||||
message: "MCP server not properly initialized".to_string(),
|
||||
})?;
|
||||
|
||||
let profile = ProfileManager::instance()
|
||||
.update_profile_proxy_bypass_rules(app_handle, profile_id, rules.clone())
|
||||
.map_err(|e| McpError {
|
||||
code: -32000,
|
||||
message: format!("Failed to update proxy bypass rules: {e}"),
|
||||
})?;
|
||||
|
||||
Ok(serde_json::json!({
|
||||
"content": [{
|
||||
"type": "text",
|
||||
"text": format!(
|
||||
"Proxy bypass rules updated for profile '{}': {} rule(s) configured",
|
||||
profile.name,
|
||||
rules.len()
|
||||
)
|
||||
}]
|
||||
}))
|
||||
}
|
||||
|
||||
async fn handle_list_extensions(&self) -> Result<serde_json::Value, McpError> {
|
||||
if !CLOUD_AUTH.has_active_paid_subscription().await {
|
||||
return Err(McpError {
|
||||
@@ -2366,6 +2440,7 @@ mod tests {
|
||||
// Fingerprint tools
|
||||
assert!(tool_names.contains(&"get_profile_fingerprint"));
|
||||
assert!(tool_names.contains(&"update_profile_fingerprint"));
|
||||
assert!(tool_names.contains(&"update_profile_proxy_bypass_rules"));
|
||||
// Extension tools
|
||||
assert!(tool_names.contains(&"list_extensions"));
|
||||
assert!(tool_names.contains(&"list_extension_groups"));
|
||||
|
||||
@@ -849,6 +849,7 @@ impl ProfileManager {
|
||||
pub fn clone_profile(
|
||||
&self,
|
||||
profile_id: &str,
|
||||
custom_name: Option<String>,
|
||||
) -> Result<BrowserProfile, Box<dyn std::error::Error>> {
|
||||
let profile_uuid =
|
||||
uuid::Uuid::parse_str(profile_id).map_err(|_| format!("Invalid profile ID: {profile_id}"))?;
|
||||
@@ -865,7 +866,10 @@ impl ProfileManager {
|
||||
}
|
||||
|
||||
let new_id = uuid::Uuid::new_v4();
|
||||
let clone_name = self.generate_clone_name(&source.name)?;
|
||||
let clone_name = match custom_name {
|
||||
Some(name) if !name.trim().is_empty() => name.trim().to_string(),
|
||||
_ => self.generate_clone_name(&source.name)?,
|
||||
};
|
||||
|
||||
let profiles_dir = self.get_profiles_dir();
|
||||
let source_dir = profiles_dir.join(source.id.to_string());
|
||||
@@ -2185,9 +2189,9 @@ pub async fn update_wayfern_config(
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn clone_profile(profile_id: String) -> Result<BrowserProfile, String> {
|
||||
pub fn clone_profile(profile_id: String, name: Option<String>) -> Result<BrowserProfile, String> {
|
||||
ProfileManager::instance()
|
||||
.clone_profile(&profile_id)
|
||||
.clone_profile(&profile_id, name)
|
||||
.map_err(|e| format!("Failed to clone profile: {e}"))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user