This commit is contained in:
2026-01-14 02:39:31 -08:00
parent 7a0d226443
commit 883f270f90
6 changed files with 337 additions and 91 deletions

87
TUI.py
View File

@@ -48,6 +48,7 @@ from SYS.cmdlet_catalog import ensure_registry_loaded, list_cmdlet_names # type
from SYS.cli_syntax import validate_pipeline_text # type: ignore # noqa: E402
from TUI.pipeline_runner import PipelineRunner # type: ignore # noqa: E402
from SYS.background_services import ensure_zerotier_server_running, stop_zerotier_server
def _dedup_preserve_order(items: List[str]) -> List[str]:
@@ -503,92 +504,14 @@ 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)
self.set_interval(5.0, ensure_zerotier_server_running)
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
stop_zerotier_server()
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
# Method removed - logic moved to SYS.background_services
pass
# Initialize the store choices cache at startup (filters disabled stores)
try: