Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/desktop/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion apps/desktop/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ tokio = { version = "1", features = ["fs", "io-util", "macros", "process", "rt-m
url = "2"
webcodex-process = { path = "../../../crates/webcodex-process" }

[target.'cfg(target_os = "macos")'.dependencies]
[target.'cfg(unix)'.dependencies]
libc = "0.2"

[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.61.2", features = ["Win32_Storage_FileSystem"] }

1 change: 1 addition & 0 deletions apps/desktop/src-tauri/src/activity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub enum ActivityEventKind {
RegularTunnelReady,
RegularTunnelStopped,
RuntimeStopped,
StateRecovered,
OperationStarted,
OperationCancelRequested,
OperationCancelled,
Expand Down
57 changes: 57 additions & 0 deletions apps/desktop/src-tauri/src/deadline.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use std::time::Duration;
use tokio::time::Instant;

/// One absolute operation deadline. Nested work may consume the remaining
/// budget but must never manufacture a fresh duration-based timeout.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct Deadline {
at: Instant,
}

impl Deadline {
pub(crate) fn after(duration: Duration) -> Self {
Self {
at: Instant::now() + duration,
}
}

pub(crate) fn at(at: Instant) -> Self {
Self { at }
}

pub(crate) fn instant(self) -> Instant {
self.at
}

pub(crate) fn is_elapsed(self) -> bool {
Instant::now() >= self.at
}

/// Cleanup may use one small, explicit post-deadline slack window. Before
/// the business deadline expires cleanup remains inside the same budget.
pub(crate) fn cleanup_deadline(self, slack: Duration) -> Instant {
let now = Instant::now();
if now < self.at {
std::cmp::min(self.at, now + slack)
} else {
now + slack
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[tokio::test]
async fn nested_deadline_never_resets_outer_budget() {
let deadline = Deadline::after(Duration::from_millis(80));
tokio::time::sleep(Duration::from_millis(30)).await;
let nested = Deadline::at(deadline.instant());
assert!(
nested.instant().saturating_duration_since(Instant::now()) <= Duration::from_millis(60)
);
tokio::time::sleep_until(nested.instant()).await;
assert!(deadline.is_elapsed());
}
}
3 changes: 2 additions & 1 deletion apps/desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod activity;
mod commands;
mod deadline;
mod error;
mod models;
mod operation;
Expand All @@ -17,7 +18,7 @@ pub fn run() {
.setup(|app| {
let data_dir = app.path().app_local_data_dir()?;
let resource_dir = app.path().resource_dir()?;
app.manage(AppState::new(data_dir, resource_dir));
app.manage(AppState::new(data_dir, resource_dir)?);
Ok(())
})
.invoke_handler(tauri::generate_handler![
Expand Down
44 changes: 0 additions & 44 deletions apps/desktop/src-tauri/src/platform/macos.rs

This file was deleted.

63 changes: 0 additions & 63 deletions apps/desktop/src-tauri/src/platform/mod.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,8 @@
#[cfg(target_os = "macos")]
mod macos;
#[cfg(target_os = "windows")]
mod windows;

use tokio::process::Command;
use webcodex_process::SpawnOptions;

#[derive(Debug, Clone, Copy)]
pub struct OwnedProcessTree {
root_pid: u32,
}

impl OwnedProcessTree {
pub fn from_spawned_root(root_pid: u32) -> Option<Self> {
if root_pid == 0 {
return None;
}
#[cfg(target_os = "macos")]
i32::try_from(root_pid).ok()?;
Some(Self { root_pid })
}
}

pub fn configure_child(command: &mut Command) {
#[cfg(target_os = "windows")]
windows::configure_child(command);
#[cfg(target_os = "macos")]
macos::configure_child(command);
}

pub fn managed_spawn_options() -> SpawnOptions {
#[cfg(target_os = "windows")]
{
Expand All @@ -40,43 +14,6 @@ pub fn managed_spawn_options() -> SpawnOptions {
}
}

pub async fn terminate_owned_tree(tree: OwnedProcessTree) -> bool {
#[cfg(target_os = "windows")]
{
return windows::force_stop_owned_tree(tree.root_pid).await;
}
#[cfg(target_os = "macos")]
{
return macos::terminate_owned_tree(tree.root_pid);
}
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
{
let _ = tree;
false
}
}

pub async fn force_stop_owned_tree(tree: OwnedProcessTree) -> bool {
#[cfg(target_os = "windows")]
{
return windows::force_stop_owned_tree(tree.root_pid).await;
}
#[cfg(target_os = "macos")]
{
return macos::force_stop_owned_tree(tree.root_pid);
}
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
{
let _ = tree;
false
}
}

#[cfg(target_os = "macos")]
pub fn owned_tree_is_running(tree: OwnedProcessTree) -> bool {
macos::owned_tree_is_running(tree.root_pid)
}

pub fn current_username() -> String {
std::env::var("USERNAME")
.or_else(|_| std::env::var("USER"))
Expand Down
25 changes: 0 additions & 25 deletions apps/desktop/src-tauri/src/platform/windows.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,9 @@
use std::os::windows::process::CommandExt;
use std::process::Stdio;
use std::time::Duration;
use tokio::process::Command;
use webcodex_process::SpawnOptions;

const CREATE_NO_WINDOW: u32 = 0x0800_0000;

pub fn configure_child(command: &mut Command) {
command.as_std_mut().creation_flags(CREATE_NO_WINDOW);
}

pub fn managed_spawn_options() -> SpawnOptions {
SpawnOptions {
windows_creation_flags: CREATE_NO_WINDOW,
}
}

pub async fn force_stop_owned_tree(pid: u32) -> bool {
let mut command = Command::new("taskkill.exe");
command
.arg("/PID")
.arg(pid.to_string())
.arg("/T")
.arg("/F")
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null());
configure_child(&mut command);
matches!(
tokio::time::timeout(Duration::from_secs(5), command.status()).await,
Ok(Ok(status)) if status.success()
)
}
3 changes: 1 addition & 2 deletions apps/desktop/src-tauri/src/process/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
mod owned;
mod supervisor;

#[cfg(test)]
mod tests;

pub(crate) use owned::reclaim_owned_tree;
pub(crate) use supervisor::MachineEventReceiver;
pub use supervisor::{ProcessKind, ProcessPhase, ProcessSnapshot, ProcessSupervisor};
52 changes: 0 additions & 52 deletions apps/desktop/src-tauri/src/process/owned.rs

This file was deleted.

Loading
Loading