mac: stop leaking ssh processes on quit
This commit is contained in:
@@ -234,9 +234,15 @@ actor AgentRPC {
|
||||
}
|
||||
}
|
||||
|
||||
func shutdown() async {
|
||||
await self.stop()
|
||||
}
|
||||
|
||||
private func stop() async {
|
||||
self.stdoutHandle?.readabilityHandler = nil
|
||||
self.process?.terminate()
|
||||
let proc = self.process
|
||||
proc?.terminate()
|
||||
proc?.waitUntilExit()
|
||||
self.process = nil
|
||||
self.stdinHandle = nil
|
||||
self.stdoutHandle = nil
|
||||
|
||||
@@ -111,6 +111,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSXPCListenerDelegate
|
||||
func applicationWillTerminate(_ notification: Notification) {
|
||||
RelayProcessManager.shared.stop()
|
||||
PresenceReporter.shared.stop()
|
||||
WebChatManager.shared.close()
|
||||
Task { await AgentRPC.shared.shutdown() }
|
||||
}
|
||||
|
||||
@MainActor
|
||||
|
||||
@@ -14,6 +14,7 @@ final class WebChatWindowController: NSWindowController, WKNavigationDelegate {
|
||||
private var baseEndpoint: URL?
|
||||
private let remotePort: Int
|
||||
private var reachabilityTask: Task<Void, Never>?
|
||||
private var tunnelRestartEnabled = false
|
||||
|
||||
init(sessionKey: String) {
|
||||
webChatLogger.debug("init WebChatWindowController sessionKey=\(sessionKey, privacy: .public)")
|
||||
@@ -46,7 +47,7 @@ final class WebChatWindowController: NSWindowController, WKNavigationDelegate {
|
||||
|
||||
@MainActor deinit {
|
||||
self.reachabilityTask?.cancel()
|
||||
self.tunnel?.terminate()
|
||||
self.stopTunnel(allowRestart: false)
|
||||
}
|
||||
|
||||
private func loadPlaceholder() {
|
||||
@@ -125,14 +126,16 @@ final class WebChatWindowController: NSWindowController, WKNavigationDelegate {
|
||||
|
||||
private func startOrRestartTunnel() async throws -> URL {
|
||||
// Kill existing tunnel if any
|
||||
self.tunnel?.terminate()
|
||||
self.stopTunnel(allowRestart: false)
|
||||
|
||||
let tunnel = try await WebChatTunnel.create(remotePort: self.remotePort, preferredLocalPort: 18_788)
|
||||
self.tunnel = tunnel
|
||||
self.tunnelRestartEnabled = true
|
||||
|
||||
// Auto-restart on unexpected termination while window lives
|
||||
tunnel.process.terminationHandler = { [weak self] _ in
|
||||
guard let self else { return }
|
||||
guard self.tunnelRestartEnabled else { return }
|
||||
webChatLogger.error("webchat tunnel terminated; restarting")
|
||||
Task { @MainActor [weak self] in
|
||||
guard let self else { return }
|
||||
@@ -152,6 +155,12 @@ final class WebChatWindowController: NSWindowController, WKNavigationDelegate {
|
||||
return URL(string: "http://127.0.0.1:\(port)/")!
|
||||
}
|
||||
|
||||
private func stopTunnel(allowRestart: Bool) {
|
||||
self.tunnelRestartEnabled = allowRestart
|
||||
self.tunnel?.terminate()
|
||||
self.tunnel = nil
|
||||
}
|
||||
|
||||
private func showError(_ text: String) {
|
||||
let html = """
|
||||
<html><body style='font-family:-apple-system;padding:24px;color:#c00'>Web chat failed to connect.<br><br>\(text)</body></html>
|
||||
@@ -159,6 +168,11 @@ final class WebChatWindowController: NSWindowController, WKNavigationDelegate {
|
||||
self.webView.loadHTMLString(html, baseURL: nil)
|
||||
}
|
||||
|
||||
func shutdown() {
|
||||
self.reachabilityTask?.cancel()
|
||||
self.stopTunnel(allowRestart: false)
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||
webChatLogger.debug("didFinish navigation url=\(webView.url?.absoluteString ?? "nil", privacy: .public)")
|
||||
}
|
||||
@@ -189,6 +203,12 @@ final class WebChatManager {
|
||||
self.controller?.window?.makeKeyAndOrderFront(nil)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
}
|
||||
|
||||
func close() {
|
||||
self.controller?.shutdown()
|
||||
self.controller?.close()
|
||||
self.controller = nil
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Port forwarding tunnel
|
||||
@@ -209,6 +229,7 @@ final class WebChatTunnel {
|
||||
func terminate() {
|
||||
if self.process.isRunning {
|
||||
self.process.terminate()
|
||||
self.process.waitUntilExit()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user