This commit is contained in:
2026-01-14 01:59:30 -08:00
parent e27e13b64c
commit 7a0d226443
4 changed files with 236 additions and 81 deletions

91
TUI.py
View File

@@ -5,6 +5,8 @@ from __future__ import annotations
import json
import re
import sys
import subprocess
import asyncio
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple
@@ -438,6 +440,8 @@ class PipelineHubApp(App):
self._pipeline_running = False
self._pipeline_worker: Any = None
self._selected_row_index: int = 0
self._zt_server_proc: Optional[subprocess.Popen] = None
self._zt_server_last_config: Optional[str] = None
# ------------------------------------------------------------------
# Layout
@@ -499,6 +503,93 @@ class PipelineHubApp(App):
if self.worker_table:
self.worker_table.add_columns("ID", "Type", "Status", "Details")
self.set_interval(5.0, self._manage_zerotier_server)
def on_unmount(self) -> None:
if hasattr(self, "_zt_server_proc") and self._zt_server_proc:
try:
self._zt_server_proc.terminate()
self._zt_server_proc.wait(timeout=2)
except Exception:
try:
self._zt_server_proc.kill()
except Exception:
pass
async def _manage_zerotier_server(self) -> None:
"""Background task to start/stop the ZeroTier storage server based on config."""
try:
cfg = load_config()
except Exception:
return
zt_conf = cfg.get("networking", {}).get("zerotier", {})
serve_target = zt_conf.get("serve")
port = zt_conf.get("port") or 999
api_key = zt_conf.get("api_key")
# Config hash to detect changes
config_id = f"{serve_target}|{port}|{api_key}"
if config_id == self._zt_server_last_config:
# Check if proc is still alive
if self._zt_server_proc:
if self._zt_server_proc.poll() is not None:
# Crashed?
self._zt_server_proc = None
self.notify("ZeroTier Host Server stopped unexpectedly", severity="warning")
else:
return
elif not serve_target:
return
# Stop existing if config changed
if self._zt_server_proc:
self.notify("Stopping ZeroTier Host Server (config change)...")
self._zt_server_proc.terminate()
self._zt_server_proc.wait()
self._zt_server_proc = None
self._zt_server_last_config = config_id
if not serve_target:
return
# Resolve path
storage_path = None
folders = cfg.get("store", {}).get("folder", {})
for name, block in folders.items():
if name.lower() == serve_target.lower():
storage_path = block.get("path") or block.get("PATH")
break
if not storage_path:
# Fallback to direct path
storage_path = serve_target
if not Path(storage_path).exists():
return
# Start server
cmd = [sys.executable, str(REPO_ROOT / "scripts" / "remote_storage_server.py"),
"--storage-path", str(storage_path),
"--port", str(port)]
if api_key:
cmd += ["--api-key", str(api_key)]
try:
# Run in a way that doesn't create a visible window on Windows if possible,
# though for scripts it's fine.
self._zt_server_proc = subprocess.Popen(
cmd,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
cwd=str(REPO_ROOT)
)
self.notify(f"ZeroTier Host: Sharing '{serve_target}' on port {port}")
except Exception as e:
self.notify(f"Failed to start ZeroTier server: {e}", severity="error")
self._zt_server_proc = None
# Initialize the store choices cache at startup (filters disabled stores)
try:
from cmdlet._shared import SharedArgs