Skip to content

Commit

Permalink
release-app restore watch dog, make kill more constrained and add win…
Browse files Browse the repository at this point in the history
…dow filter
  • Loading branch information
louis030195 committed Feb 20, 2025
1 parent a6b459b commit 1f7d97a
Show file tree
Hide file tree
Showing 4 changed files with 265 additions and 4 deletions.
1 change: 1 addition & 0 deletions screenpipe-app-tauri/lib/hooks/use-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ const DEFAULT_IGNORED_WINDOWS_IN_ALL_OS = [
"Recorder",
"Vaults",
"OBS Studio",
"screenpipe",
];

const DEFAULT_IGNORED_WINDOWS_PER_OS: Record<string, string[]> = {
Expand Down
2 changes: 1 addition & 1 deletion screenpipe-app-tauri/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "screenpipe-app"
version = "0.35.7"
version = "0.35.8"
description = ""
authors = ["you"]
license = ""
Expand Down
262 changes: 261 additions & 1 deletion screenpipe-core/src/pipes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ mod pipes {
use std::future::Future;
use std::path::PathBuf;
use std::pin::Pin;
use std::time::{SystemTime, UNIX_EPOCH};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use tokio::process::Command;
use tokio::sync::watch;

Expand Down Expand Up @@ -92,6 +92,248 @@ mod pipes {
.to_string()
}

async fn create_watchdog_script(parent_pid: u32, child_pid: u32) -> Result<PathBuf> {
let script_content = if cfg!(windows) {
format!(
r#"
$parentPid = {parent_pid}
$childPid = {child_pid}
function Get-ChildProcesses($ProcessId) {{
Get-WmiObject Win32_Process | Where-Object {{ $_.ParentProcessId -eq $ProcessId }} | ForEach-Object {{
$_.ProcessId
Get-ChildProcesses $_.ProcessId
}}
}}
while ($true) {{
try {{
$parent = Get-Process -Id $parentPid -ErrorAction Stop
Start-Sleep -Seconds 1
}} catch {{
Write-Host "Parent process ($parentPid) not found, terminating child processes"
# Get all child processes recursively
$children = Get-ChildProcesses $childPid
# Add the main process to the list
$allProcesses = @($childPid) + $children
foreach ($pid in $allProcesses) {{
try {{
Stop-Process -Id $pid -Force -ErrorAction SilentlyContinue
Write-Host "Stopped process: $pid"
}} catch {{
Write-Host "Process $pid already terminated"
}}
}}
exit
}}
}}
"#
)
} else {
format!(
r#"#!/bin/bash
set -x # Enable debug mode
parent_pid={parent_pid}
child_pid={child_pid}
echo "[$(date)] Watchdog started - monitoring parent PID: $parent_pid, child PID: $child_pid"
find_all_children() {{
local parent=$1
local children=$(pgrep -P $parent)
echo $children
for child in $children; do
find_all_children $child
done
}}
cleanup() {{
echo "[$(date)] Starting cleanup..."
# Get all child processes recursively
all_children=$(find_all_children $child_pid)
echo "[$(date)] Found child processes: $all_children"
# Try to kill by process group first
child_pgid=$(ps -o pgid= -p $child_pid 2>/dev/null | tr -d ' ')
if [ ! -z "$child_pgid" ]; then
echo "[$(date)] Killing process group $child_pgid"
pkill -TERM -g $child_pgid 2>/dev/null || true
sleep 1
pkill -KILL -g $child_pgid 2>/dev/null || true
fi
# Kill all children individually if they still exist
if [ ! -z "$all_children" ]; then
echo "[$(date)] Killing all child processes: $all_children"
kill -TERM $all_children 2>/dev/null || true
sleep 1
kill -KILL $all_children 2>/dev/null || true
fi
# Kill the main process if it still exists
echo "[$(date)] Killing main process $child_pid"
kill -TERM $child_pid 2>/dev/null || true
sleep 1
kill -KILL $child_pid 2>/dev/null || true
# Final verification
sleep 1
remaining=$(ps -o pid= -g $child_pgid 2>/dev/null || true)
if [ ! -z "$remaining" ]; then
echo "[$(date)] WARNING: Some processes might still be running: $remaining"
pkill -KILL -g $child_pgid 2>/dev/null || true
fi
exit 0
}}
trap cleanup SIGTERM SIGINT
while true; do
if ! ps -p $parent_pid > /dev/null 2>&1; then
echo "[$(date)] Parent process ($parent_pid) not found, terminating child processes"
cleanup
exit
fi
sleep 1
done
"#
)
};

let temp_dir = std::env::temp_dir();
let script_name = if cfg!(windows) {
format!("watchdog_{parent_pid}_{child_pid}.ps1")
} else {
format!("watchdog_{parent_pid}_{child_pid}.sh")
};
let script_path = temp_dir.join(script_name);

tokio::fs::write(&script_path, script_content).await?;

// Set executable permissions on Unix systems only
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = tokio::fs::metadata(&script_path).await?.permissions();
perms.set_mode(0o755);
tokio::fs::set_permissions(&script_path, perms).await?;
}

Ok(script_path)
}

async fn spawn_watchdog(parent_pid: u32, child_pid: u32) -> Result<tokio::process::Child> {
let script_path = create_watchdog_script(parent_pid, child_pid).await?;

info!(
"Spawning watchdog process for parent_pid={}, child_pid={}",
parent_pid, child_pid
);
info!("Watchdog script path: {:?}", script_path);

// Create a log file for the watchdog
let log_path =
std::env::temp_dir().join(format!("watchdog_{}_{}.log", parent_pid, child_pid));

#[cfg(windows)]
let child = {
Command::new("powershell")
.arg("-ExecutionPolicy")
.arg("Bypass")
.arg("-NoProfile")
.arg("-NonInteractive")
.arg("-WindowStyle")
.arg("Hidden")
.arg("-File")
.arg(&script_path)
.creation_flags(0x08000000)
.stdout(std::fs::File::create(&log_path)?)
.stderr(std::fs::File::create(&log_path)?)
.spawn()?
};

#[cfg(not(windows))]
let child = {
Command::new("bash")
.arg(&script_path)
.stdout(std::fs::File::create(&log_path)?)
.stderr(std::fs::File::create(&log_path)?)
.spawn()?
};

if let Some(id) = child.id() {
info!("Watchdog process spawned with PID: {}", id);

// Modify verification for Windows
#[cfg(windows)]
{
tokio::spawn(async move {
tokio::time::sleep(Duration::from_secs(1)).await;
let output = Command::new("powershell")
.arg("-NoProfile")
.arg("-NonInteractive")
.arg("-Command")
.arg(format!(
"Get-Process -Id {} -ErrorAction SilentlyContinue",
id
))
.output()
.await;

match output {
Ok(output) => {
if output.status.success() {
info!("Watchdog process verified running with PID: {}", id);
} else {
error!("Watchdog process not found after spawn! PID: {}", id);
}
}
Err(e) => error!("Failed to verify watchdog process: {}", e),
}
});
}

#[cfg(not(windows))]
{
tokio::spawn(async move {
tokio::time::sleep(Duration::from_secs(1)).await;
let output = Command::new("ps")
.args(["-p", &id.to_string()])
.output()
.await;

match output {
Ok(output) => {
if output.status.success() {
info!("Watchdog process verified running with PID: {}", id);
} else {
error!("Watchdog process not found after spawn! PID: {}", id);
}
}
Err(e) => error!("Failed to verify watchdog process: {}", e),
}
});
}
}

// Clean up script after a delay
let script_path_clone = script_path.clone();
tokio::spawn(async move {
tokio::time::sleep(Duration::from_secs(30)).await;
if let Err(e) = tokio::fs::remove_file(&script_path_clone).await {
error!("Failed to remove watchdog script: {}", e);
}
});

Ok(child)
}

pub async fn run_pipe(
pipe: &str,
screenpipe_dir: PathBuf,
Expand Down Expand Up @@ -349,6 +591,24 @@ mod pipes {
debug!("[{}] streaming logs for next.js pipe", pipe);
stream_logs(pipe, &mut child).await?;

let child_pid = child.id().expect("Failed to get child PID") as u32;
let parent_pid = std::process::id();

info!("Spawned bun process with PID: {}", child_pid);

// Spawn watchdog process
match spawn_watchdog(parent_pid, child_pid).await {
Ok(watchdog) => {
debug!(
"Watchdog process spawned successfully with PID: {:?}",
watchdog.id()
);
}
Err(e) => {
warn!("Failed to spawn watchdog process: {}", e);
}
}

return Ok((child, PipeState::Port(port)));
}

Expand Down
4 changes: 2 additions & 2 deletions screenpipe-server/src/pipe_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,9 +358,9 @@ impl PipeManager {

#[cfg(unix)]
{
// try with id first
// Make grep pattern more specific to target only pipe processes
let command = format!(
"ps axuw | grep {} | grep -v grep | awk '{{print $2}}' | xargs -I {{}} kill -TERM {{}}",
"ps axuw | grep 'pipes/{}/' | grep -v grep | awk '{{print $2}}' | xargs -I {{}} kill -TERM {{}}",
&id.to_string()
);

Expand Down

0 comments on commit 1f7d97a

Please sign in to comment.