diff options
Diffstat (limited to 'packaging')
| -rw-r--r-- | packaging/win/README.md | 4 | ||||
| -rw-r--r-- | packaging/win/build-node-runtime.ps1 | 6 | ||||
| -rw-r--r-- | packaging/win/electron-builder.msix.yml | 82 | ||||
| -rw-r--r-- | packaging/win/meshbay-node.spec | 25 | ||||
| -rw-r--r-- | packaging/win/node-entry.py | 17 |
5 files changed, 79 insertions, 55 deletions
diff --git a/packaging/win/README.md b/packaging/win/README.md index b84ba98..eda728e 100644 --- a/packaging/win/README.md +++ b/packaging/win/README.md @@ -15,7 +15,9 @@ Linux). `meshbay-common` rides along inside the node runtime. │ ├─ service.ps1 install/remove/status/run/end the boot-time task │ ├─ service-mode.ps1 elevated helper: service.ps1 + firewall.ps1 in one UAC prompt │ └─ node-runtime\ -│ ├─ meshbay-node.exe frozen daemon (PyInstaller onedir) +│ ├─ meshbay-node.exe frozen daemon and CLI (PyInstaller onedir) +│ ├─ meshbay-nodew.exe the same daemon without a console (the Store +│ │ package's startup task runs it) │ ├─ _internal\ … its Python + deps (aiortc, av, aioquic, …) │ ├─ ffmpeg.exe, ffprobe.exe bundled by default, see Video (ffmpeg) below │ ├─ av*.dll, swscale/swresample*.dll what those two link against diff --git a/packaging/win/build-node-runtime.ps1 b/packaging/win/build-node-runtime.ps1 index 42d1faa..aa5e759 100644 --- a/packaging/win/build-node-runtime.ps1 +++ b/packaging/win/build-node-runtime.ps1 @@ -105,8 +105,10 @@ finally { } $frozen = Join-Path $pyiDist "meshbay-node" -if (-not (Test-Path (Join-Path $frozen "meshbay-node.exe"))) { - throw "PyInstaller did not produce meshbay-node.exe at $frozen" +foreach ($name in "meshbay-node.exe", "meshbay-nodew.exe") { + if (-not (Test-Path (Join-Path $frozen $name))) { + throw "PyInstaller did not produce $name at $frozen" + } } # --- 3b. licences ---------------------------------------------------- diff --git a/packaging/win/electron-builder.msix.yml b/packaging/win/electron-builder.msix.yml index d3adad6..577e039 100644 --- a/packaging/win/electron-builder.msix.yml +++ b/packaging/win/electron-builder.msix.yml @@ -1,8 +1,22 @@ -# Standalone electron-builder config for the "MSIX" Windows target: same -# feature set as Full (bundled node + ffmpeg), packaged for Microsoft Store -# submission instead of NSIS. The package carries none of installer.nsh's -# elevation logic: an AppX/MSIX install never elevates, by design. What is -# still unverified here is called out at each declaration below. +# Standalone electron-builder config for the "MSIX" Windows target: the +# bundled node + ffmpeg, packaged for Microsoft Store submission instead of +# NSIS. +# +# What the NSIS build does with scripts -- firewall rules, a Startup-folder +# launcher, a boot task, a PATH entry -- this package DECLARES in its manifest, +# and Windows creates it at install, carries it across updates and removes it +# with the package, all without an administrator prompt. Scripts could not do +# that job here: everything they write names the install folder, and a Store +# install lives in C:\Program Files\WindowsApps\MeshBay.MeshBay_<version>_..., +# which each update deletes. Measured on a real install (2026-10-08): +# - firewall: build/appx-manifest.xml declares the node's rules; +# - at sign-in: build/appx-extensions.xml declares a startup task, off by +# default, that the node's CLI switches (`meshbay-node autostart`), +# for the app's Node page and a terminal alike; +# - `meshbay-node` in a terminal: an execution alias, also in that file; +# - at boot, before anyone signs in: not offered. It needs a boot task, +# created elevated and left behind on uninstall; that is the .exe +# installer's job. # # Deliberately NOT layered onto package.json's `build` field, same reasoning # as electron-builder.light.yml: --config reads ONLY this file, so nothing @@ -42,33 +56,15 @@ win: icon: build/icon.ico artifactName: "MeshBay-${version}.${ext}" extraResources: - # Same bundle as Full (package.json's own build.win.extraResources) -- - # this target drops NSIS, not the node/ffmpeg runtime or the two service - # scripts. service-mode.ps1 in particular still works unmodified: it is - # invoked from main.js's winElevateServiceMode() on demand, from the - # running (unelevated) app, not from an installer step -- that path - # already existed before this target did (see "the other door" comment - # in src/main.js) and needs nothing new here beyond the file being - # present to find. + # The node runtime as Full ships it, both executables: meshbay-node.exe + # (CLI, and what the app starts) and meshbay-nodew.exe (no console, for + # the startup task). No scripts: firewall.ps1, the service scripts and + # ensure-node-path.ps1 are the manifest's job here (see the top of this + # file), and main.js offers no service mode without service-mode.ps1. - from: node-runtime to: node-runtime filter: - "**/*" - - from: ../../packaging/win/firewall.ps1 - to: firewall.ps1 - - from: ../../packaging/win/service.ps1 - to: service.ps1 - - from: ../../packaging/win/service-mode.ps1 - to: service-mode.ps1 - # Full's own installer adds node-runtime\ to the per-user PATH at install - # time (build/installer.nsh's customInstall) -- an unelevated HKCU write, - # never blocked by the no-elevation rule this target is built around, but - # MSIX has no install-time hook at all to run it from. main.js's - # winEnsureNodeOnPath() calls this itself on first launch instead - # (found missing by actually sideloading a build and checking, not - # anticipated in the original plan). - - from: ../../packaging/win/ensure-node-path.ps1 - to: ensure-node-path.ps1 # The application's own licence, beside the app (Electron's LICENSE and # LICENSES.chromium.html are put next to the exe by electron-builder). - from: ../../LICENSE @@ -99,26 +95,14 @@ appx: - it-IT - nl-NL - pl-PL - # Both are the "common" (general, non-restricted) capability group per - # app-builder-lib's AppxCapabilities.js -- no special Store justification - # needed, unlike the `rescap`-namespaced restricted ones. Matches - # firewall.ps1's own rules, which are `-Profile Any` (private AND public - # network). Whether Windows Firewall actually auto-exempts a full-trust - # packaged app on the strength of these declarations -- eliminating the - # elevation firewall.ps1 exists for entirely -- is an open item: verify - # live before relying on it, the declaration alone only proves the - # manifest is well-formed. - capabilities: - - internetClientServer - - privateNetworkClientServer - # windows.startupTask, the MSIX-native equivalent of the NSIS "at sign in" - # mode's Startup-folder .vbs (main.js's WIN_STARTUP_VBS) -- but pointed at - # the node daemon, not the Electron shell, which is what `addAutoLaunchExtension: - # true` would do instead (it always targets the package's own main - # executable, per AppxTarget.js's `executable` macro -- there is no config - # switch to point it at a different bundled exe). build/appx-extensions.xml - # declares that extension by hand for exactly this reason. Whether - # Windows actually launches a *non-primary* bundled exe through this - # mechanism is the other open item -- untested until sideloaded. + # Execution aliases need Windows 10 1709; 1809 is the oldest still + # serviced. electron-builder's default (10.0.14316.0, for both) predates both. + minVersion: 10.0.17763.0 + maxVersionTested: 10.0.26100.0 + # The stock template plus the package-level firewall rules. + customManifestPath: build/appx-manifest.xml + # The startup task and the execution alias. Not addAutoLaunchExtension: + # that one always starts the package's main executable, the Electron shell, + # where "at sign-in" means the node. customExtensionsPath: build/appx-extensions.xml showNameOnTiles: false diff --git a/packaging/win/meshbay-node.spec b/packaging/win/meshbay-node.spec index 3261778..a1173a2 100644 --- a/packaging/win/meshbay-node.spec +++ b/packaging/win/meshbay-node.spec @@ -153,8 +153,33 @@ exe = EXE( icon="../../packages/meshbay-client/build/icon.ico", version=_version_info, ) +# The same daemon without a console, for what starts it with nobody watching: +# the Store package's startup task runs its executable as is, and a console +# executable opened a window whose close button killed the node. The CLI stays +# meshbay-node.exe, which has to print. Same entry point and archive, same +# _internal\ beside both (pythonw.exe beside python.exe). +exe_windowless = EXE( + pyz, + a.scripts, + [], + exclude_binaries=True, + name="meshbay-nodew", + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=False, + console=False, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, + icon="../../packages/meshbay-client/build/icon.ico", + version=_version_info, +) coll = COLLECT( exe, + exe_windowless, a.binaries, a.datas, strip=False, diff --git a/packaging/win/node-entry.py b/packaging/win/node-entry.py index 6fadad7..a502a37 100644 --- a/packaging/win/node-entry.py +++ b/packaging/win/node-entry.py @@ -1,12 +1,23 @@ """PyInstaller entry point for the bundled Windows node daemon. `meshbay_node.daemon:main` is a module function; PyInstaller freezes a script. -This is that script — nothing more. The frozen binary is `meshbay-node.exe`, +This is that script. The frozen binary is `meshbay-node.exe`, relocatable, and is what the desktop client spawns and what the W3 autostart -launcher points at (`meshbay_node.platform._node_exe`). +launcher points at (`meshbay_node.platform._node_exe`). `meshbay-nodew.exe` is +the same script built without a console (meshbay-node.spec). """ -from meshbay_node.daemon import main +import os +import sys + +# meshbay-nodew.exe, the build without a console, starts with no stdio at all +# (sys.stdout and sys.stderr are None), and a library that writes to either or +# asks whether it is a terminal would raise. The daemon logs to node.log. +for _name in ("stdout", "stderr"): + if getattr(sys, _name) is None: + setattr(sys, _name, open(os.devnull, "w", encoding="utf-8")) + +from meshbay_node.daemon import main # noqa: E402 if __name__ == "__main__": main() |