aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-client/build
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-client/build')
-rw-r--r--packages/meshbay-client/build/installer.nsh123
-rw-r--r--packages/meshbay-client/build/stop-node.ps145
2 files changed, 149 insertions, 19 deletions
diff --git a/packages/meshbay-client/build/installer.nsh b/packages/meshbay-client/build/installer.nsh
index 3157f22..ef9c82a 100644
--- a/packages/meshbay-client/build/installer.nsh
+++ b/packages/meshbay-client/build/installer.nsh
@@ -55,7 +55,55 @@
!macroend
!macro customInit
+ ; What this machine already runs, before the previous version's uninstaller
+ ; deletes the sign-in launcher: an upgrade keeps the mode it finds, instead
+ ; of defaulting to "background service" -- which a silent upgrade cannot even
+ ; set up (no elevation), so an "at sign-in" install came out of one with no
+ ; autostart at all and its node stopped (found upgrading a real install).
+ ; A fresh install still defaults to the service.
StrCpy $MB_AutoMode "2"
+ nsExec::Exec 'schtasks /query /tn "MeshBay Node"'
+ Pop $0
+ ${If} $0 == 0
+ StrCpy $MB_AutoMode "2"
+ ${ElseIf} ${FileExists} "$APPDATA\Microsoft\Windows\Start Menu\Programs\Startup\MeshBay Node.vbs"
+ StrCpy $MB_AutoMode "1"
+ ${ElseIf} ${FileExists} "$INSTDIR\${APP_EXECUTABLE_FILENAME}"
+ StrCpy $MB_AutoMode "0"
+ ${EndIf}
+!macroend
+
+; ── stop the node before a single file is touched ─────────────────────────
+; electron-builder inserts customCheckAppRunning in place of its own
+; app-running check, which it runs before uninstallOldVersion and before the
+; files are extracted (installSection.nsh); customInstall only runs after both.
+; A service-mode daemon lives in the task's S4U logon session, where an
+; unelevated taskkill gets "Access is denied". Left running, it keeps
+; meshbay-node.exe and its DLLs locked, their copy fails, and electron-builder's
+; last-resort extract ignores the failure. build/stop-node.ps1 asks the node to
+; stop through its own control API first -- any session, no elevation, a proper
+; shutdown -- then Task Scheduler, then taskkill. It is embedded and run from
+; the plugins directory: the installed copy of anything may be what is being
+; replaced.
+
+; Defining customCheckAppRunning makes allowOnlyOneInstallerInstance.nsh skip
+; these two, which its own _CHECK_APP_RUNNING (inserted below) still needs.
+!include "getProcessInfo.nsh"
+Var pid
+
+!macro customCheckAppRunning
+ InitPluginsDir
+ File "/oname=$PLUGINSDIR\mb-stop-node.ps1" "${BUILD_RESOURCES_DIR}\stop-node.ps1"
+ mb_stop_node:
+ DetailPrint "Stopping the MeshBay node..."
+ nsExec::Exec `"${MB_PWSH}" -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "$PLUGINSDIR\mb-stop-node.ps1"`
+ Pop $0
+ ${If} $0 != 0
+ MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "The MeshBay node is still running and holds files that setup must replace. Stop it (meshbay-node service stop, or end meshbay-node.exe in Task Manager), then click Retry." /SD IDCANCEL IDRETRY mb_stop_node
+ Quit
+ ${EndIf}
+ !insertmacro IS_POWERSHELL_AVAILABLE
+ !insertmacro _CHECK_APP_RUNNING
!macroend
; ── the autostart choice, as a radio page ─────────────────────────────────
@@ -123,9 +171,8 @@
!macroend
!macro customInstall
- ; resources\node-runtime\meshbay-node.exe is about to be overwritten; a
- ; daemon still running from a previous version holds the file open.
- nsExec::Exec 'taskkill /IM meshbay-node.exe /F'
+ ; The node was stopped by customCheckAppRunning, before the files were
+ ; copied -- by the time this runs they already have been.
; Add the daemon dir to the per-user PATH (HKCU\Environment). WordAdd is a
; stock NSIS macro over a ';'-delimited list -- it is a no-op if the entry is
@@ -146,9 +193,12 @@
${If} $MB_AutoMode == "2"
; Background service: the boot-time Scheduled Task AND the firewall
; rules, in ONE elevation (service-mode.ps1 does both). Skip it only
- ; when the task already exists and the rules are already there.
+ ; when the task is already there and current and so are the rules. A
+ ; stale task (2: another executable, or the 72-hour / battery defaults
+ ; of an older setup) is registered again -- the owner cannot change it
+ ; without elevation.
nsExec::Exec '"${MB_PWSH}" -NoProfile -ExecutionPolicy Bypass -File "$INSTDIR\resources\service.ps1" status'
- Pop $R1 ; 0 = task installed
+ Pop $R1 ; 0 = installed and current, 1 = absent, 2 = stale
${If} $R1 == 0
${AndIf} $R0 == 0
Goto mb_auto_done
@@ -159,28 +209,58 @@
Goto mb_auto_done
${EndIf}
- ; Modes 0 and 1: no scheduled task. One elevation for the firewall rules,
- ; and only if one is actually missing.
+ ; Modes 0 and 1. A boot task left from an earlier "background service"
+ ; choice would start the node a second time, at boot and at sign-in: take
+ ; it out (service-mode.ps1 remove keeps the firewall rules every mode needs).
+ nsExec::Exec 'schtasks /query /tn "MeshBay Node"'
+ Pop $R1
+ ${If} $R1 == 0
+ ExecShellWait "runas" "${MB_PWSH}" \
+ '-NoProfile -ExecutionPolicy Bypass -File "$INSTDIR\resources\service-mode.ps1" -Action remove' \
+ SW_HIDE
+ ${EndIf}
+ ; One elevation for the firewall rules, and only if one is actually missing.
${If} $R0 != 0
ExecShellWait "runas" "${MB_PWSH}" \
'-NoProfile -ExecutionPolicy Bypass -File "$INSTDIR\resources\firewall.ps1" add' \
SW_HIDE
${EndIf}
- ; Mode 1 also drops the per-user sign-in launcher (no admin -- it is just
- ; a .vbs in this account's Startup folder). Idempotent, so a repeat run is
- ; harmless. meshbay_node.platform.service_install() removes this itself if
- ; the user later switches to service mode from the Node page.
- ${If} $MB_AutoMode == "1"
- nsExec::Exec '"${MB_NODE_BIN}\meshbay-node.exe" autostart install'
- ${EndIf}
-
mb_auto_done:
${EndIf}
+
+ ; The sign-in launcher as the mode wants it -- silent installs too: during an
+ ; upgrade the previous version's uninstaller has just deleted it. No admin,
+ ; idempotent; `autostart install` refuses while a boot task exists.
+ ${If} $MB_AutoMode == "1"
+ nsExec::Exec '"${MB_NODE_BIN}\meshbay-node.exe" autostart install'
+ ${Else}
+ nsExec::Exec '"${MB_NODE_BIN}\meshbay-node.exe" autostart remove'
+ ${EndIf}
+ Pop $R2
+
+ ; Start the node customCheckAppRunning stopped, the way this mode runs it,
+ ; rather than leave it down until the next boot or sign-in. Only a node that
+ ; has been set up: a fresh install's has no account yet, and node:start
+ ; provisions and starts it. Mode 0 is the app's to start (runAfterFinish).
+ ${If} ${FileExists} "$LOCALAPPDATA\meshbay\node.toml"
+ ${If} $MB_AutoMode == "2"
+ nsExec::Exec 'schtasks /query /tn "MeshBay Node"'
+ Pop $R2
+ ${If} $R2 == 0
+ nsExec::Exec 'schtasks /run /tn "MeshBay Node"'
+ Pop $R2
+ ${EndIf}
+ ${ElseIf} $MB_AutoMode == "1"
+ nsExec::Exec '"${MB_NODE_BIN}\meshbay-node.exe" autostart start'
+ Pop $R2
+ ${EndIf}
+ ${EndIf}
!macroend
!macro customUnInstall
- nsExec::Exec 'taskkill /IM meshbay-node.exe /F'
+ ; The node is already stopped: the uninstaller runs customCheckAppRunning
+ ; (un.checkAppRunning) before this.
; Take our entry back out of PATH, leaving the rest of it alone.
ReadRegStr $0 HKCU "Environment" "Path"
@@ -196,17 +276,22 @@
; default-No; a silent uninstall skips it entirely. customUnInstall runs
; before the files are removed, so service-mode.ps1 is still there.
${IfNot} ${Silent}
+ ${AndIfNot} ${isUpdated}
MessageBox MB_YESNO|MB_ICONQUESTION \
"Remove MeshBay's Windows Firewall rules and its boot-time service task, if you set one up? This needs one administrator confirmation. Both are harmless if left." \
/SD IDNO IDNO mb_keep_privileged
ExecShellWait "runas" "${MB_PWSH}" \
- '-NoProfile -ExecutionPolicy Bypass -File "$INSTDIR\resources\service-mode.ps1" -Action remove' \
+ '-NoProfile -ExecutionPolicy Bypass -File "$INSTDIR\resources\service-mode.ps1" -Action uninstall' \
SW_HIDE
mb_keep_privileged:
${EndIf}
; meshbay_node.platform.autostart_install() -- if the user picked "at sign-in"
; (here, or later in the client), this points wscript at the binary we are
- ; about to delete, and would error at every sign-in.
- Delete "$APPDATA\Microsoft\Windows\Start Menu\Programs\Startup\MeshBay Node.vbs"
+ ; about to delete, and would error at every sign-in. Not in an upgrade: the
+ ; new version is about to take this path's place, and deleting the launcher
+ ; here is what left upgraded "at sign-in" installs with no autostart at all.
+ ${IfNot} ${isUpdated}
+ Delete "$APPDATA\Microsoft\Windows\Start Menu\Programs\Startup\MeshBay Node.vbs"
+ ${EndIf}
!macroend
diff --git a/packages/meshbay-client/build/stop-node.ps1 b/packages/meshbay-client/build/stop-node.ps1
new file mode 100644
index 0000000..cfaf2f8
--- /dev/null
+++ b/packages/meshbay-client/build/stop-node.ps1
@@ -0,0 +1,45 @@
+# Stop every MeshBay node on this machine before setup touches its files, or
+# before the uninstaller removes them. Embedded in the installer and run from
+# its plugins directory: the installed copy of anything may be the one being
+# replaced.
+#
+# 1. Ask the node through its own control API (/api/shutdown, loopback, per-run
+# token): the only stop that reaches a node in any session with no
+# elevation, and the one that lets it shut down properly -- WebRTC sessions
+# closed, transcodes stopped.
+# 2. Task Scheduler for a background-service node (the owner may end the task;
+# taskkill from here gets "Access is denied" in its session).
+# 3. taskkill for anything left in this session.
+# Exit 0 once no meshbay-node.exe is left, 1 otherwise.
+$ErrorActionPreference = "SilentlyContinue"
+
+function NodeLeft { [bool](Get-Process -Name meshbay-node -ErrorAction SilentlyContinue) }
+function WaitGone([int]$Seconds) {
+ $deadline = (Get-Date).AddSeconds($Seconds)
+ while ((NodeLeft) -and (Get-Date) -lt $deadline) { Start-Sleep -Milliseconds 250 }
+ -not (NodeLeft)
+}
+
+if (-not (NodeLeft)) { exit 0 }
+
+$cfg = Join-Path $env:LOCALAPPDATA "meshbay"
+$port = 18000
+$toml = Join-Path $cfg "node.toml"
+if (Test-Path $toml) {
+ $m = Select-String -Path $toml -Pattern '^\s*ui_port\s*=\s*(\d+)' | Select-Object -First 1
+ if ($m) { $port = [int]$m.Matches[0].Groups[1].Value }
+}
+$tokenFile = Join-Path $cfg "data\ui-token"
+if (Test-Path $tokenFile) {
+ $token = (Get-Content $tokenFile -Raw).Trim()
+ try {
+ Invoke-WebRequest -UseBasicParsing -Method Post -TimeoutSec 5 `
+ -Uri "http://127.0.0.1:$port/api/shutdown?t=$token" | Out-Null
+ if (WaitGone 20) { exit 0 }
+ } catch { }
+}
+
+& schtasks /end /tn "MeshBay Node" 2>&1 | Out-Null
+Get-Process -Name meshbay-node -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
+if (WaitGone 20) { exit 0 }
+exit 1