diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-05 13:06:55 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-05 13:06:55 +0200 |
| commit | e89a57bb97b5a0d624e8d490b6b8aa38ba140817 (patch) | |
| tree | 3e51dfb630510508cdab16f0b0205772816f4896 /packages/meshbay-node/src/meshbay_node/daemon.py | |
| parent | 7601991ccb1d75637c055062c38b1852eeef9700 (diff) | |
| download | meshbay-e89a57bb97b5a0d624e8d490b6b8aa38ba140817.tar.gz | |
fix(win): graceful shutdown, one startup-mode control, and a stray-\r bug
Windows-only changes, all found by actually running the previous session's
work rather than by review alone:
- CTRL_CLOSE_EVENT/LOGOFF/SHUTDOWN handler (platform.py, ctypes
SetConsoleCtrlHandler) so closing a console window, signing off, or a
system shutdown runs the daemon's real _shutdown() instead of Windows
just ending the process — closing WebRTC sessions and any in-flight
ffmpeg transcode instead of orphaning it. `taskkill /F` itself stays
uncatchable (like SIGKILL), so autostart_run() now spawns with
CREATE_NEW_PROCESS_GROUP instead of DETACHED_PROCESS and autostart_end()
tries CTRL_BREAK_EVENT against the recorded pid first, falling back to
the hard kill only if that doesn't stop it in time.
- Replaced the Node page's two independent autostart/service-mode toggles
with one "start automatically" select (off / at sign-in / as a
background service). The old pair let both be active at once — starting
the daemon twice, at boot and at sign-in — and their layout broke
wrapping inside .node-service's flex row. The new control always removes
whichever mechanism is active before installing the target; platform.py's
service_install() does the same on the CLI side. The "background
service" option disables itself (with a hint pointing at the CLI) when
running unpackaged, since service-mode.ps1/service.ps1/firewall.ps1 all
assume an installed build's layout — verified live rather than assumed
by actually running those scripts unelevated.
- findNodeBinary() no longer bakes a stray \r into resolved paths. Found by
rebooting after enabling per-user autostart: where.exe listed two
matches, and stdout.trim().split('\n')[0] only strips the whole string's
ends, leaving line one's own trailing \r attached — which landed inside
the Startup .vbs's quoted path and broke it with "Unterminated string
constant" at boot. Fixed by splitting on \r?\n and trimming every line.
- Dependency audit for the Windows installer (docs/WINDOWS-PORT.md): no
VC++ Redistributable needed, confirmed by inspecting the built
node-runtime's actual import table rather than assuming. New
docs/windows-build.md: a concise clone-to-installer build guide.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/daemon.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/daemon.py | 18 |
1 files changed, 17 insertions, 1 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/daemon.py b/packages/meshbay-node/src/meshbay_node/daemon.py index b932c16..ea13680 100644 --- a/packages/meshbay-node/src/meshbay_node/daemon.py +++ b/packages/meshbay-node/src/meshbay_node/daemon.py @@ -678,9 +678,18 @@ class NodeDaemon: # 12. Wait for shutdown stop_event = asyncio.Event() loop = asyncio.get_event_loop() + console_shutdown_done = None if sys.platform == "win32": - for sig in (signal.SIGINT, signal.SIGTERM): + # SIGBREAK: CTRL_BREAK_EVENT, how platform.autostart_end() asks + # a per-user-mode daemon to stop gracefully instead of only + # ever taskkill /F. + for sig in (signal.SIGINT, signal.SIGTERM, signal.SIGBREAK): signal.signal(sig, lambda *_: stop_event.set()) + # CTRL_CLOSE/LOGOFF/SHUTDOWN reach no Python signal at all -- + # see platform.install_console_close_handler for why this is + # a separate mechanism rather than another signal.signal() line. + from meshbay_node.platform import install_console_close_handler + console_shutdown_done = install_console_close_handler(loop, stop_event) else: for sig in (signal.SIGINT, signal.SIGTERM): loop.add_signal_handler(sig, stop_event.set) @@ -694,6 +703,13 @@ class NodeDaemon: await stop_event.wait() await self._shutdown() + if console_shutdown_done is not None: + # Releases the console-control handler's blocking wait (see + # platform.install_console_close_handler) so it can return and + # let Windows actually end the process for CTRL_CLOSE/LOGOFF/ + # SHUTDOWN, now that cleanup is genuinely done rather than just + # started. + console_shutdown_done.set() async def _reload_config(self) -> None: """ |