Enhance Windows instance management and path resolution
Some checks failed
farmcontrol/farmcontrol-ui/pipeline/head There was a failure building this commit
Some checks failed
farmcontrol/farmcontrol-ui/pipeline/head There was a failure building this commit
- Introduced a new function `isPrimaryInstanceReachable` to check the reachability of the primary instance, improving instance handling on Windows. - Updated `forwardDeeplinkToRunningInstance` to include an option for signal fallback, enhancing flexibility in deeplink forwarding. - Implemented `tryRecoverUnresponsivePrimaryLock` to handle unresponsive primary instances by removing stale lock files, improving application reliability. - Refactored `resolveWindowsBinDir` to utilize unique path resolution, ensuring accurate directory handling for Windows applications. - Enhanced the `ensureWindowsWorkingDirectory` function to streamline directory changes, improving application behavior.
This commit is contained in:
parent
e1051499f9
commit
de93658df1
@ -285,6 +285,24 @@ function patchNativeWrapperPath(nativeTsPath) {
|
||||
let source = readFileSync(nativeTsPath, 'utf8')
|
||||
|
||||
if (source.includes('function resolveNativeWrapperPath()')) {
|
||||
source = source.replace(
|
||||
/function resolveNativeWrapperPath\(\) \{[\s\S]*?\n\}/m,
|
||||
`function resolveNativeWrapperPath() {
|
||||
\tconst fileName = \`libNativeWrapper.\${suffix}\`;
|
||||
\tconst candidates = [
|
||||
\t\tjoin(dirname(process.argv0), fileName),
|
||||
\t\tjoin(dirname(process.execPath), fileName),
|
||||
\t\tjoin(process.cwd(), fileName),
|
||||
\t];
|
||||
\tfor (const candidate of candidates) {
|
||||
\t\tif (existsSync(candidate)) {
|
||||
\t\t\treturn candidate;
|
||||
\t\t}
|
||||
\t}
|
||||
\treturn candidates[0]!;
|
||||
}`
|
||||
)
|
||||
writeFileSync(nativeTsPath, source)
|
||||
return
|
||||
}
|
||||
|
||||
@ -311,6 +329,7 @@ function patchNativeWrapperPath(nativeTsPath) {
|
||||
function resolveNativeWrapperPath() {
|
||||
\tconst fileName = \`libNativeWrapper.\${suffix}\`;
|
||||
\tconst candidates = [
|
||||
\t\tjoin(dirname(process.argv0), fileName),
|
||||
\t\tjoin(dirname(process.execPath), fileName),
|
||||
\t\tjoin(process.cwd(), fileName),
|
||||
\t];
|
||||
|
||||
@ -204,14 +204,25 @@ async function tryForwardViaPipeWithRetries(payload) {
|
||||
return false
|
||||
}
|
||||
|
||||
export async function forwardDeeplinkToRunningInstance(payload) {
|
||||
export async function isPrimaryInstanceReachable() {
|
||||
if (process.platform === 'win32') {
|
||||
return tryForwardViaPipeWithRetries({ type: 'focus' })
|
||||
}
|
||||
|
||||
return isPrimaryInstanceRunning()
|
||||
}
|
||||
|
||||
export async function forwardDeeplinkToRunningInstance(
|
||||
payload,
|
||||
{ allowSignalFallback = true } = {}
|
||||
) {
|
||||
if (process.platform === 'win32') {
|
||||
if (await tryForwardViaPipeWithRetries(payload)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if (isPrimaryInstanceRunning()) {
|
||||
if (allowSignalFallback && isPrimaryInstanceRunning()) {
|
||||
writeDeeplinkSignal(payload)
|
||||
return true
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ import {
|
||||
getInstanceDir,
|
||||
getLockPath,
|
||||
getSignalPath,
|
||||
isPrimaryInstanceReachable,
|
||||
isProcessAlive,
|
||||
SIGNAL_FILE,
|
||||
WINDOWS_PIPE_NAME,
|
||||
@ -233,6 +234,23 @@ function startWindowsPipeServer() {
|
||||
pipeServer = server
|
||||
}
|
||||
|
||||
async function tryRecoverUnresponsivePrimaryLock() {
|
||||
if (!isPrimaryInstanceRunning()) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (await isPrimaryInstanceReachable()) {
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
unlinkSync(getLockPath())
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export async function ensureSingleInstanceLock({ launchUrl } = {}) {
|
||||
if (process.platform === 'darwin') {
|
||||
return true
|
||||
@ -241,7 +259,11 @@ export async function ensureSingleInstanceLock({ launchUrl } = {}) {
|
||||
const payload = buildLaunchPayload(launchUrl)
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
if (await forwardDeeplinkToRunningInstance(payload)) {
|
||||
if (
|
||||
await forwardDeeplinkToRunningInstance(payload, {
|
||||
allowSignalFallback: false
|
||||
})
|
||||
) {
|
||||
console.log('[deeplink] forwarded duplicate launcher instance to running app')
|
||||
return false
|
||||
}
|
||||
@ -251,6 +273,15 @@ export async function ensureSingleInstanceLock({ launchUrl } = {}) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (
|
||||
(await tryRecoverUnresponsivePrimaryLock()) &&
|
||||
tryAcquirePrimaryLock()
|
||||
) {
|
||||
startWindowsPipeServer()
|
||||
startInstanceSignalWatcher()
|
||||
return true
|
||||
}
|
||||
|
||||
writeInstanceSignal(payload)
|
||||
return false
|
||||
}
|
||||
|
||||
@ -1,26 +1,57 @@
|
||||
import { chdirSync, existsSync } from 'node:fs'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { dirname, join, resolve } from 'node:path'
|
||||
|
||||
const NATIVE_WRAPPER_DLL = 'libNativeWrapper.dll'
|
||||
|
||||
export function resolveWindowsBinDir() {
|
||||
const candidates = [
|
||||
dirname(process.execPath),
|
||||
process.cwd(),
|
||||
join(dirname(process.execPath), 'bin'),
|
||||
join(process.cwd(), 'bin')
|
||||
]
|
||||
function uniquePaths(paths) {
|
||||
const seen = new Set()
|
||||
const result = []
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (
|
||||
existsSync(join(candidate, 'launcher.exe')) ||
|
||||
existsSync(join(candidate, NATIVE_WRAPPER_DLL))
|
||||
) {
|
||||
for (const candidate of paths) {
|
||||
if (!candidate) {
|
||||
continue
|
||||
}
|
||||
|
||||
const normalized = resolve(candidate)
|
||||
if (seen.has(normalized)) {
|
||||
continue
|
||||
}
|
||||
|
||||
seen.add(normalized)
|
||||
result.push(normalized)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function hasAppBinMarker(dir) {
|
||||
return (
|
||||
existsSync(join(dir, 'launcher.exe')) ||
|
||||
existsSync(join(dir, NATIVE_WRAPPER_DLL)) ||
|
||||
existsSync(join(dir, 'bun.exe')) ||
|
||||
existsSync(join(dir, '..', 'Resources', 'version.json'))
|
||||
)
|
||||
}
|
||||
|
||||
export function resolveWindowsBinDir() {
|
||||
const roots = uniquePaths([
|
||||
dirname(process.argv0),
|
||||
dirname(process.execPath),
|
||||
process.cwd()
|
||||
])
|
||||
|
||||
const candidates = []
|
||||
for (const root of roots) {
|
||||
candidates.push(root, join(root, 'bin'))
|
||||
}
|
||||
|
||||
for (const candidate of uniquePaths(candidates)) {
|
||||
if (hasAppBinMarker(candidate)) {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
|
||||
return dirname(process.execPath)
|
||||
return dirname(process.argv0 || process.execPath)
|
||||
}
|
||||
|
||||
export function ensureWindowsWorkingDirectory() {
|
||||
@ -29,14 +60,13 @@ export function ensureWindowsWorkingDirectory() {
|
||||
}
|
||||
|
||||
const binDir = resolveWindowsBinDir()
|
||||
const wrapperInCwd = existsSync(join(process.cwd(), NATIVE_WRAPPER_DLL))
|
||||
const wrapperInBinDir = existsSync(join(binDir, NATIVE_WRAPPER_DLL))
|
||||
if (resolve(process.cwd()) === resolve(binDir)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!wrapperInCwd && wrapperInBinDir) {
|
||||
try {
|
||||
chdirSync(binDir)
|
||||
} catch {
|
||||
// Ignore if we cannot change directory.
|
||||
}
|
||||
try {
|
||||
chdirSync(binDir)
|
||||
} catch {
|
||||
// Ignore if we cannot change directory.
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user