feat(native-host): kill previous instance on startup and in installers
CI / Build & Test (push) Successful in 3m20s

- Add kill-previous-instance.mjs with PID lock file under BASE_DIR; on
  startup send SIGTERM to any existing native-host before binding ports
- Register removePidFile on shutdown and exit
- Run "stop any running native host" at the start of install.sh and
  install.ps1
- Use ESM with static imports so bare-pack includes the module in the
  bundle (dynamic require was not included and broke the built binary)
- Add kill-previous-instance.mjs to CI syntax check
This commit is contained in:
Raven Scott
2026-03-14 23:31:34 -04:00
parent 3bf9851390
commit 609f5d9353
5 changed files with 60 additions and 16 deletions
+1 -1
View File
@@ -75,7 +75,7 @@ jobs:
node --check native-host/managers/rdp-manager.js
node --check native-host/host/messenger.js
node --check native-host/host/paths.js
node --check native-host/host/kill-previous-instance.js
node --check native-host/host/kill-previous-instance.mjs
node --check native-host/host/logger.js
node --check native-host/host/startup.js
node --check native-host/host/message-router.js
@@ -1,11 +1,13 @@
/**
* Kill any previously running native-host instance (same installation) before
* we bind to ports. Uses a PID file under BASE_DIR so the lock is per-install.
* ESM so bare-pack includes it when bundling from index.mjs.
*/
const path = require('bare-path');
const fs = require('bare-fs');
const { BASE_DIR } = require('./paths.js');
import path from 'bare-path';
import fs from 'bare-fs';
import pathsModule from './paths.js';
const { BASE_DIR } = pathsModule;
const PID_FILE = path.join(BASE_DIR, '.holesail-browser-host.pid');
@@ -24,7 +26,7 @@ function isProcessAlive(pid) {
* SIGTERM. Then write our PID to the lock file. Does not wait for the old
* process to exit.
*/
function killPreviousInstanceSync() {
export function killPreviousInstanceSync() {
let existingPid = null;
try {
const raw = fs.readFileSync(PID_FILE, 'utf8');
@@ -43,20 +45,14 @@ function killPreviousInstanceSync() {
writePidFile();
}
function writePidFile() {
export function writePidFile() {
try {
fs.writeFileSync(PID_FILE, String(process.pid), 'utf8');
} catch (_) {}
}
function removePidFile() {
export function removePidFile() {
try {
fs.unlinkSync(PID_FILE);
} catch (_) {}
}
module.exports = {
killPreviousInstanceSync,
writePidFile,
removePidFile
};
+1 -3
View File
@@ -14,9 +14,7 @@
import 'bare-process/global';
import './set-tmpdir.mjs';
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const { killPreviousInstanceSync, removePidFile } = require('./host/kill-previous-instance.js');
import { killPreviousInstanceSync, removePidFile } from './host/kill-previous-instance.mjs';
import _messenger from './host/messenger.js';
import _host from './host/message-router.js';
@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID6TCCAtGgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBhjEcMBoGA1UEAxMTSG9s
ZXNhaWwgQnJvd3NlciBDQTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYD
VQQHEw1TYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBIb2xlc2FpbCBCcm93c2VyMRkw
FwYDVQQLExBIb2xlc2FpbCBSb290IENBMB4XDTI2MDMxNTAzMzEwN1oXDTM2MDMx
NTAzMzEwN1owgYYxHDAaBgNVBAMTE0hvbGVzYWlsIEJyb3dzZXIgQ0ExCzAJBgNV
BAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcG
A1UEChMQSG9sZXNhaWwgQnJvd3NlcjEZMBcGA1UECxMQSG9sZXNhaWwgUm9vdCBD
QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKDQBrJFw1wTO9iUr4UO
pU0SWhC0QfrfHbMkbqbgQx2WA11Hfblc2C/MwS1M46SbtkMCGVTedL0zmPnS0nX1
S8VEbDyqGnOh41CekQfinFhGL8vDJEHIJSB1pQV3RZFRZHJbnSfcsRG/WZU6FjOM
FD7x21oLzHPivFxktqPR68iCP/Xd2wXFupHrAIy9cgLh8CC3S2WAcG6HLKPIQ6LK
eW2l72+/yJef9EselZl2URrzDiKaMqvJ5Ybc653xXN+SASPJy3IPtzLPvZ1KhN4u
V0uLorri4Z8cYgzx+g7AwCix77WxXP1eKlsyw5MFRW/NoWzaavDIwZxc6BT04pC+
H28CAwEAAaNgMF4wDwYDVR0TBAgwBgEB/wIBADALBgNVHQ8EBAMCAQYwHQYDVR0O
BBYEFKyzccFCZF7DqyD40JwG2I5oX43UMB8GA1UdIwQYMBaAFKyzccFCZF7DqyD4
0JwG2I5oX43UMA0GCSqGSIb3DQEBCwUAA4IBAQCaGl27sR25Z4ZhbuWLA4eKLLmv
TNxl8aqVX/ItQIMN4lSHLe2vLGyJwYfqLNVFITaLhSp3gmEhMYOOUW145NFrkHHQ
D6RBKQGjLJbYWH8fgyzgG0l1x0dFcY7DIh4qkoNl4bZqNEwbSCSV1Cy4RFD6uKPU
xpIOWPCMkfJxsOFNOVjZ9IwrYfyNeFbR/qfbp79VG7XOaVpsvdlSL4MjFUtFedxz
ncqwcCboIyufRzvvgiLMSk8OzRwne3eUQFhfeDhM60pdscADRG40gpOv76hWhQyO
Dw4TVzgCl2+cvESXV0rlYEMo4vN63f6BEh4T5gCn3sTqVjfR0GayMrKs4Zxx
-----END CERTIFICATE-----
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAoNAGskXDXBM72JSvhQ6lTRJaELRB+t8dsyRupuBDHZYDXUd9
uVzYL8zBLUzjpJu2QwIZVN50vTOY+dLSdfVLxURsPKoac6HjUJ6RB+KcWEYvy8Mk
QcglIHWlBXdFkVFkcludJ9yxEb9ZlToWM4wUPvHbWgvMc+K8XGS2o9HryII/9d3b
BcW6kesAjL1yAuHwILdLZYBwbocso8hDosp5baXvb7/Il5/0Sx6VmXZRGvMOIpoy
q8nlhtzrnfFc35IBI8nLcg+3Ms+9nUqE3i5XS4uiuuLhnxxiDPH6DsDAKLHvtbFc
/V4qWzLDkwVFb82hbNpq8MjBnFzoFPTikL4fbwIDAQABAoIBAG5WrfGOCoBXth1h
z5ilNuhN6jxB4m+mvTMYkU+w2nwnXQGYtvwDZ1ZM0FMryZo9OO57NzRTOphDGfh4
He3PtACTdQyezm1+q4C6e9qEMzAiYFMX/v2fvVGrRuIcN0CBL0GD+K3MMDZ0K5xH
ccpGl/GkcxQyukLdVM60T9jRhU1acuRBPw2LXgKDJkykbcru2IBKqcnmztHAimEF
RlGOL6270JIpwKlY9fAYjskccB6Vhzn+m3sMlMLM/qs3PdBuJa11D0fwjEvWUXYe
6Wkhijpb2sTXI2+mLuqiQDSmE4MQmCWhpCNS4kb8GbCvT24DF86lbL7ySsfCaP03
S9ARWMkCgYEAzKyeYx0C0izDNkWFLZvvUWm/JAC0t/nqoLafBA3INzLM7/r8xaAd
apnrLLySxI2pq5WNAzVJqRAeKW06Tjv08ZfgS5uDE7ihcA4oY2EbLwLFm2ZCqEJg
iJycSPa8YU5ltjyNFkhqOOYiTFehAEQNgf5xKZEfjqAcG1OnCb3KC40CgYEAySOj
hbF9nru3sd4WaHc0F+tVTadST9S1WEaW+Xv9mbc0QYY0FpWl9tPxWRVkKOOViVW4
uGxCPWO/sIYFO/JGWVv+vd6lWFrnxo0iB/AXkrjtKu/NX8qoWmS4TV/rOqH1Zfxp
4A4vlI8BZedOHLVdrenAA/L3/5gCMdOA0Ron2esCgYAGO8unIR8Q36QiZwOjW/hx
9lKH+i2G3Om0c1tseC7832M2e+Ju8m1y7bUn66ZcriPYwflFe73+lCsW/+iisVjI
cuO16cqYMytXilbYkACP8fmqvfaRwVPHVV29KyaZoBWg8z8oypPRn9CzmoegxnHS
37j6lxzq7x1sB6Qyu8EHkQKBgQCkSeHU36a1sqpWNAqlhUgdiXEBnnuTDTCaS/4h
BW+c0JF0O8Pr9ou60l693sUSyOFpbYUVzgdE0WbPLoiz8C4Z6xRlzafMRWQvPzPe
u/LlOvstKPXdGlDslHwdZw1htMwWY1evVKb0duIzc/zPYiyEUvstvpVmRaj1PcZo
BS8rxQKBgAhC1nXDFQDgRxbMly/MuDTWsjBI7yK6gVg3ujXMW2x5NFQfENukO8O4
oV1yDqNitM8AYHOP9j/mYQ7VfJz0ZlYCmAYwk7roSpuYAK6dk54ZtKtOpD0mlAHU
W8kWpEmyAbJWdAUfVK60mS3hu4iFLKQmJO8qViHcvwNDjcYHMvkG
-----END RSA PRIVATE KEY-----