mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-27 15:17:38 +00:00
79 lines
2.5 KiB
Swift
79 lines
2.5 KiB
Swift
import Foundation
|
|
import IOKit.pwr_mgt
|
|
import Observation
|
|
import OSLog
|
|
|
|
/// Manages system power assertions to prevent the Mac from sleeping while VibeTunnel is running.
|
|
///
|
|
/// This service uses IOKit's power management APIs to create power assertions that prevent
|
|
/// the system from entering idle sleep when terminal sessions are active. The service is
|
|
/// integrated with ServerManager to automatically manage sleep prevention based on server
|
|
/// state and user preferences.
|
|
@Observable
|
|
@MainActor
|
|
final class PowerManagementService {
|
|
static let shared = PowerManagementService()
|
|
|
|
private(set) var isSleepPrevented = false
|
|
|
|
private var assertionID: IOPMAssertionID = 0
|
|
private var isAssertionActive = false
|
|
|
|
private let logger = Logger(subsystem: BundleIdentifiers.loggerSubsystem, category: "PowerManagement")
|
|
|
|
private init() {}
|
|
|
|
/// Prevents the system from sleeping
|
|
func preventSleep() {
|
|
guard !isAssertionActive else { return }
|
|
|
|
let reason = "VibeTunnel is running terminal sessions" as CFString
|
|
let assertionType = kIOPMAssertionTypeNoIdleSleep as CFString
|
|
|
|
let success = IOPMAssertionCreateWithName(
|
|
assertionType,
|
|
IOPMAssertionLevel(kIOPMAssertionLevelOn),
|
|
reason,
|
|
&assertionID
|
|
)
|
|
|
|
if success == kIOReturnSuccess {
|
|
isAssertionActive = true
|
|
isSleepPrevented = true
|
|
logger.info("Sleep prevention enabled")
|
|
} else {
|
|
logger.error("Failed to prevent sleep: \(success)")
|
|
}
|
|
}
|
|
|
|
/// Allows the system to sleep normally
|
|
func allowSleep() {
|
|
guard isAssertionActive else { return }
|
|
|
|
let success = IOPMAssertionRelease(assertionID)
|
|
|
|
if success == kIOReturnSuccess {
|
|
isAssertionActive = false
|
|
isSleepPrevented = false
|
|
assertionID = 0
|
|
logger.info("Sleep prevention disabled")
|
|
} else {
|
|
logger.error("Failed to release sleep assertion: \(success)")
|
|
}
|
|
}
|
|
|
|
/// Updates sleep prevention based on user preference and server state
|
|
func updateSleepPrevention(enabled: Bool, serverRunning: Bool) {
|
|
if enabled && serverRunning {
|
|
preventSleep()
|
|
} else {
|
|
allowSleep()
|
|
}
|
|
}
|
|
|
|
deinit {
|
|
// Deinit runs on arbitrary thread, but we need to check MainActor state
|
|
// Since we can't access MainActor properties directly in deinit,
|
|
// we handle cleanup in allowSleep() which is called when server stops
|
|
}
|
|
}
|