From e833fe1bfc8eb6f66cc5dc53997cc4158bab583f Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Wed, 7 Oct 2026 21:25:47 +0200 Subject: fix: set the Windows node up at sign-in, and stop it for real Found by the first Windows beta tester, then reproduced on a clean install. After a service-mode install nothing set the node up for the account that signed in: the boot task started a node that quit ("hub.username not set"), and the sidebar showed Node / Create group only once the hub held a node key. The only way to the wizard that provisions was the home page's welcome card, which an account already in a group never sees. The way out was `meshbay-node init` and the key pasted on the profile page -- which is also what PACKAGING-GUIDE.md told people to do. - main.js `node:ensure`, called by app.js at sign-in: provisions, starts and links the node this build ships (Windows, bundled node only). A node set up for another account, or an account linked to another node, is left alone. node:start waits for it, so the two never race. - The sidebar shows the Node section when a node exists on this machine. - The Node page's status is the node's: its control API and the process list, not the service task's state (a node started from a terminal ran while the page said Stopped). Stop says Stopped only once no meshbay-node.exe is left, and stays offered for a process that answers nothing. - CLI stop kills the pid that answered when a graceful stop does not finish, and fails with the reason when a node process is still there. - The daemon ends its process 3s after _shutdown(): Python's exit waited for a busy indexer thread, with the control API already closed. Armed by main() only, never by a daemon run inside a test. - node.toml is read as utf-8-sig (PowerShell 5.1 writes a BOM), and a config that cannot be read is logged instead of dying silently in service mode. - "Pair this browser" queues the code for the next group of this node to open instead of saying "Paired successfully"; no banner before a group. - test_e2e_windows_app.py (opt-in, MESHBAY_WIN_E2E=1) drives the installed app against a throwaway hub: fresh account to linked node, Stop, Start, Restart, checked against the real processes. Co-Authored-By: Claude Opus 5.5 --- packages/meshbay-node/src/meshbay_node/platform.py | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'packages/meshbay-node/src/meshbay_node/platform.py') diff --git a/packages/meshbay-node/src/meshbay_node/platform.py b/packages/meshbay-node/src/meshbay_node/platform.py index 88db83d..c0e4d00 100644 --- a/packages/meshbay-node/src/meshbay_node/platform.py +++ b/packages/meshbay-node/src/meshbay_node/platform.py @@ -397,6 +397,35 @@ def autostart_end() -> None: subprocess.run(argv, capture_output=True) +def node_pids() -> list[int]: + """Every meshbay-node.exe running, in any session, except this process and + its parent (the CLI is meshbay-node.exe too). Empty off Windows. + + What says whether a node is still there after a stop: its control API + closes first, so a process that has not exited yet answers nothing and + used to count as gone. + """ + if sys.platform != "win32": + return [] + r = subprocess.run(["tasklist", "/FI", f"IMAGENAME eq {NODE_IMAGE}", "/NH", "/FO", "CSV"], + capture_output=True, text=True) + mine = {os.getpid(), os.getppid()} + pids = [] + for line in r.stdout.splitlines(): + cells = [c.strip('"') for c in line.split('","')] + if len(cells) > 1 and cells[1].isdigit() and int(cells[1]) not in mine: + pids.append(int(cells[1])) + return pids + + +def kill_pid(pid: int) -> None: + """Force-stop one process and its children (its ffmpeg transcodes). Reaches + this session only, unless the caller is elevated. Windows only: systemd + stops the node everywhere else.""" + if sys.platform == "win32": + subprocess.run(["taskkill", "/F", "/T", "/PID", str(pid)], capture_output=True) + + # ── Service mode (Windows, opt-in at install time) ─────────────────────────── # # The Startup-folder .vbs above only ever runs after *this* user signs in. A -- cgit v1.2.3