fix: enforce gateway single instance

This commit is contained in:
Peter Steinberger
2025-12-09 19:40:01 +00:00
parent 6329f60dff
commit 5df438fd2a
3 changed files with 38 additions and 0 deletions

View File

@@ -1,6 +1,7 @@
import Foundation
import OSLog
import Subprocess
import Network
#if canImport(Darwin)
import Darwin
#endif
@@ -153,6 +154,10 @@ final class GatewayProcessManager: ObservableObject {
self.appendLog("[gateway] starting: \(command.joined(separator: " ")) (cwd: \(cwd))\n")
do {
// Acquire the same UDS lock the CLI uses to guarantee a single instance.
let lockPath = FileManager.default.temporaryDirectory.appendingPathComponent("clawdis-gateway.lock").path
let listener = try self.acquireGatewayLock(path: lockPath)
let result = try await run(
.name(command.first ?? "clawdis"),
arguments: Arguments(Array(command.dropFirst())),
@@ -168,12 +173,31 @@ final class GatewayProcessManager: ObservableObject {
await err
}
// Release the lock after the process exits.
listener.cancel()
await self.handleTermination(status: result.terminationStatus)
} catch {
await self.handleError(error)
}
}
/// Minimal clone of the Node gateway lock: bind a UDS and return the listener.
private func acquireGatewayLock(path: String) throws -> NWListener {
// Remove stale socket if needed
try? FileManager.default.removeItem(atPath: path)
let params = NWParameters.tcp
params.allowLocalEndpointReuse = false
let endpoint = NWEndpoint.unix(path: path)
let listener = try NWListener(using: params, on: endpoint)
listener.newConnectionHandler = { connection in
// Any new connection indicates another starter; reject.
connection.cancel()
}
listener.start(queue: .global())
return listener
}
private func didStart(_ execution: Execution) {
self.execution = execution
self.stopping = false