36 lines
1.3 KiB
Swift
36 lines
1.3 KiB
Swift
|
|
import AppKit
|
||
|
|
import Foundation
|
||
|
|
|
||
|
|
/// OS-level control of the `claire web` daemon and dashboard. All entry points
|
||
|
|
/// are nonisolated and safe to call from a detached task — they shell out to
|
||
|
|
/// `launchctl` / open a URL and don't touch UI state.
|
||
|
|
enum DaemonControl {
|
||
|
|
/// Restart the daemon: `launchctl kickstart -k gui/<uid>/<label>`.
|
||
|
|
/// `-k` kills the running instance first, then relaunches it under launchd.
|
||
|
|
/// This is the watchdog's recovery action and the "Restart" menu item.
|
||
|
|
static func restartDaemon(label: String) {
|
||
|
|
let status = run(["/bin/launchctl", "kickstart", "-k", "gui/\(getuid())/\(label)"])
|
||
|
|
NSLog("ClaireTray: kickstart \(label) -> exit \(status)")
|
||
|
|
}
|
||
|
|
|
||
|
|
static func openDashboard(baseURL: String) {
|
||
|
|
guard let url = URL(string: baseURL) else { return }
|
||
|
|
NSWorkspace.shared.open(url)
|
||
|
|
}
|
||
|
|
|
||
|
|
@discardableResult
|
||
|
|
private static func run(_ argv: [String]) -> Int32 {
|
||
|
|
let p = Process()
|
||
|
|
p.executableURL = URL(fileURLWithPath: argv[0])
|
||
|
|
p.arguments = Array(argv.dropFirst())
|
||
|
|
do {
|
||
|
|
try p.run()
|
||
|
|
p.waitUntilExit()
|
||
|
|
return p.terminationStatus
|
||
|
|
} catch {
|
||
|
|
NSLog("ClaireTray: process \(argv) failed: \(error)")
|
||
|
|
return -1
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|