Compare commits

..

No commits in common. "5f061f92eb14dbfbb2129fe53da6061787f333d6" and "282d0c66302b49d67c62bac30199aec9789c1754" have entirely different histories.

5 changed files with 25 additions and 96 deletions

View File

@ -1,4 +1,4 @@
!include "MUI2.nsh"
!include "MUI2.nsh"
!include "LogicLib.nsh"
!include "installer.nsh"
@ -10,10 +10,6 @@
!define VERSION "0.1.0"
!endif
!ifndef BUILD_NUMBER
!define BUILD_NUMBER "dev"
!endif
!ifndef APP_SOURCE_DIR
!define APP_SOURCE_DIR "app"
!endif
@ -25,7 +21,6 @@ InstallDirRegKey HKLM "Software\Tom Butcher\Farm Control" "InstallDir"
RequestExecutionLevel admin
!define MUI_ABORTWARNING
!define MUI_BRANDINGTEXT "Farm Control v${VERSION}-b${BUILD_NUMBER} Installer"
!ifndef INSTALLER_ICON
!define INSTALLER_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"

View File

@ -8,8 +8,6 @@ param(
[Parameter(Mandatory = $true)]
[string]$Version,
[string]$BuildNumber = "dev",
[long]$MinInstallerBytes = 10485760
)
@ -99,7 +97,6 @@ $makensisArgs = @(
"/NOCD"
"/DOUTFILE=$localInstallerName"
"/DVERSION=$Version"
"/DBUILD_NUMBER=$BuildNumber"
"/DAPP_SOURCE_DIR=app"
)

View File

@ -447,15 +447,6 @@ function buildWindowsNsis(appDir, arch) {
artifactDir,
getReleaseArtifactName(version, arch, 'exe')
)
const buildInfoPath = path.join(rootDir, 'src/buildInfo.json')
const buildInfo = existsSync(buildInfoPath)
? JSON.parse(readFileSync(buildInfoPath, 'utf8'))
: {}
const buildNumber =
process.env.BUILD_NUMBER ||
process.env.VITE_BUILD_NUMBER ||
buildInfo.buildNumber ||
'dev'
const powershell = process.env.SystemRoot
? path.join(
process.env.SystemRoot,
@ -479,9 +470,7 @@ function buildWindowsNsis(appDir, arch) {
'-OutputExe',
exePath,
'-Version',
version,
'-BuildNumber',
buildNumber
version
],
{ stdio: 'inherit' }
)

View File

@ -11,10 +11,7 @@ import { join } from 'node:path'
export const PROTOCOL_PREFIX = 'farmcontrol://'
export const WINDOWS_PIPE_NAME = '\\\\.\\pipe\\com.tombutcher.farmcontrol.instance'
export const SIGNAL_FILE = 'instance-signal.json'
export const LOCK_FILE = 'primary.lock'
const FORWARD_TIMEOUT_MS = 750
const PIPE_RETRY_ATTEMPTS = 3
const PIPE_RETRY_DELAY_MS = 100
export function getInstanceDir() {
if (process.platform === 'win32') {
@ -31,37 +28,6 @@ export function getSignalPath() {
return join(getInstanceDir(), SIGNAL_FILE)
}
export function getLockPath() {
return join(getInstanceDir(), LOCK_FILE)
}
export function isProcessAlive(pid) {
if (!Number.isInteger(pid) || pid <= 0) {
return false
}
try {
process.kill(pid, 0)
return true
} catch {
return false
}
}
export function isPrimaryInstanceRunning() {
const lockPath = getLockPath()
if (!existsSync(lockPath)) {
return false
}
try {
const existingPid = Number.parseInt(readFileSync(lockPath, 'utf8').trim(), 10)
return isProcessAlive(existingPid)
} catch {
return false
}
}
export function findProtocolUrl(args) {
const directMatch = args.find(
(arg) => typeof arg === 'string' && arg.startsWith(PROTOCOL_PREFIX)
@ -151,7 +117,7 @@ export function writeDeeplinkSignal(payload) {
unlinkSync(tempPath)
}
function tryForwardViaPipe(payload) {
export function forwardDeeplinkToRunningInstance(payload) {
return new Promise((resolve) => {
let settled = false
const finish = (forwarded) => {
@ -160,7 +126,7 @@ function tryForwardViaPipe(payload) {
resolve(forwarded)
}
const client = net.connect({ path: WINDOWS_PIPE_NAME })
const client = net.connect(WINDOWS_PIPE_NAME)
const message = JSON.stringify(payload)
client.on('connect', () => {
@ -179,38 +145,3 @@ function tryForwardViaPipe(payload) {
})
})
}
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
async function tryForwardViaPipeWithRetries(payload) {
for (let attempt = 0; attempt < PIPE_RETRY_ATTEMPTS; attempt += 1) {
if (await tryForwardViaPipe(payload)) {
return true
}
if (attempt < PIPE_RETRY_ATTEMPTS - 1) {
await delay(PIPE_RETRY_DELAY_MS)
}
}
return false
}
export async function forwardDeeplinkToRunningInstance(payload) {
if (process.platform === 'win32') {
if (await tryForwardViaPipeWithRetries(payload)) {
return true
}
}
if (isPrimaryInstanceRunning()) {
writeDeeplinkSignal(payload)
return true
}
return false
}

View File

@ -9,19 +9,20 @@ import {
writeFileSync
} from 'node:fs'
import net from 'node:net'
import { join } from 'node:path'
import {
buildDeeplinkPayload,
findProtocolUrl,
forwardDeeplinkToRunningInstance,
getInstanceDir,
getLockPath,
getSignalPath,
isProcessAlive,
SIGNAL_FILE,
WINDOWS_PIPE_NAME,
writeDeeplinkSignal
} from './deeplink-ipc.js'
const LOCK_FILE = 'primary.lock'
let lockFd = null
let pollInterval = null
let fsWatcher = null
@ -32,6 +33,23 @@ let handlers = {
}
const pendingMessages = []
function getLockPath() {
return join(getInstanceDir(), LOCK_FILE)
}
function isProcessAlive(pid) {
if (!Number.isInteger(pid) || pid <= 0) {
return false
}
try {
process.kill(pid, 0)
return true
} catch {
return false
}
}
function tryAcquirePrimaryLock() {
mkdirSync(getInstanceDir(), { recursive: true })
const lockPath = getLockPath()
@ -229,7 +247,7 @@ function startWindowsPipeServer() {
}
})
server.listen({ path: WINDOWS_PIPE_NAME })
server.listen(WINDOWS_PIPE_NAME)
pipeServer = server
}
@ -256,7 +274,6 @@ export async function ensureSingleInstanceLock({ launchUrl } = {}) {
}
startWindowsPipeServer()
startInstanceSignalWatcher()
return true
}