use crate::error::{TuskError, TuskResult}; use crate::mcp; use crate::models::settings::{AppSettings, DockerHost, McpStatus}; use crate::state::AppState; use std::fs; use std::sync::Arc; use tauri::{AppHandle, Manager, State}; fn get_settings_path(app: &AppHandle) -> TuskResult { let dir = app .path() .app_data_dir() .map_err(|e| TuskError::Custom(e.to_string()))?; fs::create_dir_all(&dir)?; Ok(dir.join("app_settings.json")) } #[tauri::command] pub async fn get_app_settings(app: AppHandle) -> TuskResult { let path = get_settings_path(&app)?; if !path.exists() { return Ok(AppSettings::default()); } let data = fs::read_to_string(&path)?; let settings: AppSettings = serde_json::from_str(&data)?; Ok(settings) } #[tauri::command] pub async fn save_app_settings( app: AppHandle, state: State<'_, Arc>, settings: AppSettings, ) -> TuskResult<()> { let path = get_settings_path(&app)?; let data = serde_json::to_string_pretty(&settings)?; fs::write(&path, data)?; // Apply docker host setting { let mut docker_host = state.docker_host.write().await; *docker_host = match settings.docker.host { DockerHost::Remote => settings.docker.remote_url.clone(), DockerHost::Local => None, }; } // Apply MCP setting: restart or stop let is_running = *state.mcp_running.read().await; if settings.mcp.enabled { if is_running { // Stop existing MCP server first let _ = state.mcp_shutdown_tx.send(true); // Give it a moment to shut down tokio::time::sleep(std::time::Duration::from_millis(200)).await; *state.mcp_running.write().await = false; } // Start new MCP server let connections_path = app .path() .app_data_dir() .map_err(|e| TuskError::Custom(e.to_string()))? .join("connections.json"); let mcp_state = state.inner().clone(); let port = settings.mcp.port; let shutdown_rx = state.mcp_shutdown_tx.subscribe(); tokio::spawn(async move { *mcp_state.mcp_running.write().await = true; if let Err(e) = mcp::start_mcp_server(mcp_state.clone(), connections_path, port, shutdown_rx).await { log::error!("MCP server error: {}", e); } *mcp_state.mcp_running.write().await = false; }); } else if is_running { // Stop MCP server let _ = state.mcp_shutdown_tx.send(true); *state.mcp_running.write().await = false; } Ok(()) } #[tauri::command] pub async fn get_mcp_status(app: AppHandle) -> TuskResult { // Read settings from file for enabled/port let settings = { let path = get_settings_path(&app)?; if path.exists() { let data = fs::read_to_string(&path)?; serde_json::from_str::(&data).unwrap_or_default() } else { AppSettings::default() } }; // Probe the actual port to determine if MCP is running let running = tokio::time::timeout( std::time::Duration::from_millis(500), tokio::net::TcpStream::connect(format!("127.0.0.1:{}", settings.mcp.port)), ) .await .map(|r| r.is_ok()) .unwrap_or(false); Ok(McpStatus { enabled: settings.mcp.enabled, port: settings.mcp.port, running, }) }