feat: [US-034] - Add reverse mutual exclusivity check in DesktopRuntime

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nathan Flurry 2026-03-17 15:25:06 -07:00
parent a6ba0ecee0
commit e9a55e5299
3 changed files with 28 additions and 1 deletions

View file

@ -62,6 +62,15 @@ impl DesktopProblem {
) )
} }
pub fn browser_conflict() -> Self {
Self::new(
409,
"Browser Conflict",
"desktop/browser-conflict",
"The browser runtime is currently active. Browser and desktop modes are mutually exclusive.",
)
}
pub fn runtime_starting(message: impl Into<String>) -> Self { pub fn runtime_starting(message: impl Into<String>) -> Self {
Self::new( Self::new(
409, 409,

View file

@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::fs::{self, OpenOptions}; use std::fs::{self, OpenOptions};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::{Output, Stdio}; use std::process::{Output, Stdio};
use std::sync::Arc; use std::sync::{Arc, OnceLock};
use std::time::Duration; use std::time::Duration;
use tokio::process::{Child, Command}; use tokio::process::{Child, Command};
@ -50,6 +50,7 @@ pub struct DesktopRuntime {
recording_manager: DesktopRecordingManager, recording_manager: DesktopRecordingManager,
streaming_manager: DesktopStreamingManager, streaming_manager: DesktopStreamingManager,
inner: Arc<Mutex<DesktopRuntimeStateData>>, inner: Arc<Mutex<DesktopRuntimeStateData>>,
browser_runtime: Arc<OnceLock<Arc<crate::browser_runtime::BrowserRuntime>>>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -179,9 +180,17 @@ impl DesktopRuntime {
recording_fps: None, recording_fps: None,
})), })),
config, config,
browser_runtime: Arc::new(OnceLock::new()),
} }
} }
pub fn set_browser_runtime(
&self,
browser_runtime: Arc<crate::browser_runtime::BrowserRuntime>,
) {
let _ = self.browser_runtime.set(browser_runtime);
}
pub async fn status(&self) -> DesktopStatusResponse { pub async fn status(&self) -> DesktopStatusResponse {
let mut state = self.inner.lock().await; let mut state = self.inner.lock().await;
self.refresh_status_locked(&mut state).await; self.refresh_status_locked(&mut state).await;
@ -204,6 +213,14 @@ impl DesktopRuntime {
&self, &self,
request: DesktopStartRequest, request: DesktopStartRequest,
) -> Result<DesktopStatusResponse, DesktopProblem> { ) -> Result<DesktopStatusResponse, DesktopProblem> {
// Check mutual exclusivity with browser runtime
if let Some(browser_rt) = self.browser_runtime.get() {
let browser_status = browser_rt.status().await;
if browser_status.state == crate::browser_types::BrowserState::Active {
return Err(DesktopProblem::browser_conflict());
}
}
let mut state = self.inner.lock().await; let mut state = self.inner.lock().await;
if !self.platform_supported() { if !self.platform_supported() {

View file

@ -125,6 +125,7 @@ impl AppState {
process_runtime.clone(), process_runtime.clone(),
desktop_runtime.clone(), desktop_runtime.clone(),
)); ));
desktop_runtime.set_browser_runtime(browser_runtime.clone());
Self { Self {
auth, auth,
agent_manager, agent_manager,