|
import os
|
|
import subprocess
|
|
import time
|
|
import select
|
|
from pr.multiplexer import create_multiplexer, close_multiplexer, get_multiplexer
|
|
|
|
_processes = {}
|
|
|
|
def _register_process(pid:int, process):
|
|
_processes[pid] = process
|
|
return _processes
|
|
|
|
def _get_process(pid:int):
|
|
return _processes.get(pid)
|
|
|
|
def kill_process(pid:int):
|
|
try:
|
|
process = _get_process(pid)
|
|
if process:
|
|
process.kill()
|
|
_processes.pop(pid)
|
|
|
|
mux_name = f"cmd-{pid}"
|
|
if get_multiplexer(mux_name):
|
|
close_multiplexer(mux_name)
|
|
|
|
return {"status": "success", "message": f"Process {pid} has been killed"}
|
|
else:
|
|
return {"status": "error", "error": f"Process {pid} not found"}
|
|
except Exception as e:
|
|
return {"status": "error", "error": str(e)}
|
|
|
|
|
|
def tail_process(pid: int, timeout: int = 30):
|
|
process = _get_process(pid)
|
|
if process:
|
|
mux_name = f"cmd-{pid}"
|
|
mux = get_multiplexer(mux_name)
|
|
|
|
if not mux:
|
|
mux_name, mux = create_multiplexer(mux_name, show_output=True)
|
|
|
|
try:
|
|
start_time = time.time()
|
|
timeout_duration = timeout
|
|
stdout_content = ""
|
|
stderr_content = ""
|
|
|
|
while True:
|
|
if process.poll() is not None:
|
|
remaining_stdout, remaining_stderr = process.communicate()
|
|
if remaining_stdout:
|
|
mux.write_stdout(remaining_stdout)
|
|
stdout_content += remaining_stdout
|
|
if remaining_stderr:
|
|
mux.write_stderr(remaining_stderr)
|
|
stderr_content += remaining_stderr
|
|
|
|
if pid in _processes:
|
|
_processes.pop(pid)
|
|
|
|
close_multiplexer(mux_name)
|
|
|
|
return {
|
|
"status": "success",
|
|
"stdout": stdout_content,
|
|
"stderr": stderr_content,
|
|
"returncode": process.returncode
|
|
}
|
|
|
|
if time.time() - start_time > timeout_duration:
|
|
return {
|
|
"status": "running",
|
|
"message": "Process is still running. Call tail_process again to continue monitoring.",
|
|
"stdout_so_far": stdout_content,
|
|
"stderr_so_far": stderr_content,
|
|
"pid": pid
|
|
}
|
|
|
|
ready, _, _ = select.select([process.stdout, process.stderr], [], [], 0.1)
|
|
for pipe in ready:
|
|
if pipe == process.stdout:
|
|
line = process.stdout.readline()
|
|
if line:
|
|
mux.write_stdout(line)
|
|
stdout_content += line
|
|
elif pipe == process.stderr:
|
|
line = process.stderr.readline()
|
|
if line:
|
|
mux.write_stderr(line)
|
|
stderr_content += line
|
|
except Exception as e:
|
|
return {"status": "error", "error": str(e)}
|
|
else:
|
|
return {"status": "error", "error": f"Process {pid} not found"}
|
|
|
|
|
|
def run_command(command, timeout=30):
|
|
mux_name = None
|
|
try:
|
|
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
_register_process(process.pid, process)
|
|
|
|
mux_name, mux = create_multiplexer(f"cmd-{process.pid}", show_output=True)
|
|
|
|
start_time = time.time()
|
|
timeout_duration = timeout
|
|
stdout_content = ""
|
|
stderr_content = ""
|
|
|
|
while True:
|
|
if process.poll() is not None:
|
|
remaining_stdout, remaining_stderr = process.communicate()
|
|
if remaining_stdout:
|
|
mux.write_stdout(remaining_stdout)
|
|
stdout_content += remaining_stdout
|
|
if remaining_stderr:
|
|
mux.write_stderr(remaining_stderr)
|
|
stderr_content += remaining_stderr
|
|
|
|
if process.pid in _processes:
|
|
_processes.pop(process.pid)
|
|
|
|
close_multiplexer(mux_name)
|
|
|
|
return {
|
|
"status": "success",
|
|
"stdout": stdout_content,
|
|
"stderr": stderr_content,
|
|
"returncode": process.returncode
|
|
}
|
|
|
|
if time.time() - start_time > timeout_duration:
|
|
return {
|
|
"status": "running",
|
|
"message": f"Process still running after {timeout}s timeout. Use tail_process({process.pid}) to monitor or kill_process({process.pid}) to terminate.",
|
|
"stdout_so_far": stdout_content,
|
|
"stderr_so_far": stderr_content,
|
|
"pid": process.pid,
|
|
"mux_name": mux_name
|
|
}
|
|
|
|
ready, _, _ = select.select([process.stdout, process.stderr], [], [], 0.1)
|
|
for pipe in ready:
|
|
if pipe == process.stdout:
|
|
line = process.stdout.readline()
|
|
if line:
|
|
mux.write_stdout(line)
|
|
stdout_content += line
|
|
elif pipe == process.stderr:
|
|
line = process.stderr.readline()
|
|
if line:
|
|
mux.write_stderr(line)
|
|
stderr_content += line
|
|
except Exception as e:
|
|
if mux_name:
|
|
close_multiplexer(mux_name)
|
|
return {"status": "error", "error": str(e)}
|
|
def run_command_interactive(command):
|
|
try:
|
|
return_code = os.system(command)
|
|
return {"status": "success", "returncode": return_code}
|
|
except Exception as e:
|
|
return {"status": "error", "error": str(e)}
|