From 3b382c792e9572f6692cdfcd2265ff2313c60eb5 Mon Sep 17 00:00:00 2001 From: Kai Luo Date: Sat, 23 Aug 2025 10:30:26 +0800 Subject: [PATCH] Add sleep helper to control user idle sleep event. --- Planet.xcodeproj/project.pbxproj | 6 ++++ Planet/API/PlanetAPIController.swift | 8 +++++ Planet/Helper/SleepHelper.swift | 53 ++++++++++++++++++++++++++++ Planet/IPFS/IPFSDaemon.swift | 8 +++++ Planet/versioning.xcconfig | 2 +- 5 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 Planet/Helper/SleepHelper.swift diff --git a/Planet.xcodeproj/project.pbxproj b/Planet.xcodeproj/project.pbxproj index 731c33b3..145025b5 100644 --- a/Planet.xcodeproj/project.pbxproj +++ b/Planet.xcodeproj/project.pbxproj @@ -77,6 +77,8 @@ 2A4AE87B2A89EF3600A27B5B /* GroupIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A4AE8792A89EF3600A27B5B /* GroupIndicatorView.swift */; }; 2A4AE87D2A89F49B00A27B5B /* SharedAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2A4AE87C2A89F49B00A27B5B /* SharedAssets.xcassets */; }; 2A4AE87E2A89F49B00A27B5B /* SharedAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2A4AE87C2A89F49B00A27B5B /* SharedAssets.xcassets */; }; + 2A5DA7572E5958510074549F /* SleepHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5DA7562E5958510074549F /* SleepHelper.swift */; }; + 2A5DA7582E5958510074549F /* SleepHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5DA7562E5958510074549F /* SleepHelper.swift */; }; 2A5DAE5E2BFEF20C001ED527 /* IPFSMigrationCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5DAE5D2BFEF20C001ED527 /* IPFSMigrationCommand.swift */; }; 2A5DAE5F2BFEF20C001ED527 /* IPFSMigrationCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5DAE5D2BFEF20C001ED527 /* IPFSMigrationCommand.swift */; }; 2A6247AE292CC5F400714BFA /* IndicatorLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A6247AD292CC5F400714BFA /* IndicatorLabelView.swift */; }; @@ -630,6 +632,7 @@ 2A466FD02A809E2C009FB646 /* IndicatorViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndicatorViews.swift; sourceTree = ""; }; 2A4AE8792A89EF3600A27B5B /* GroupIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupIndicatorView.swift; sourceTree = ""; }; 2A4AE87C2A89F49B00A27B5B /* SharedAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = SharedAssets.xcassets; sourceTree = ""; }; + 2A5DA7562E5958510074549F /* SleepHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SleepHelper.swift; sourceTree = ""; }; 2A5DAE5D2BFEF20C001ED527 /* IPFSMigrationCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPFSMigrationCommand.swift; sourceTree = ""; }; 2A6247AD292CC5F400714BFA /* IndicatorLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndicatorLabelView.swift; sourceTree = ""; }; 2A6DC6262AEB7F9D0025D6A7 /* PlanetStatusManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlanetStatusManager.swift; sourceTree = ""; }; @@ -1259,6 +1262,7 @@ 2A90A80229DBB6FC00D45E5E /* KeyboardShortcutHelper.swift */, 2A3967882D7ADB2F002CBE7A /* HttpRequest.swift */, 2A1B9CF52D942F9800EF5488 /* ScheduledTasksManager.swift */, + 2A5DA7562E5958510074549F /* SleepHelper.swift */, ); path = Helper; sourceTree = ""; @@ -1949,6 +1953,7 @@ 2A95E6E72A19A64F001288B8 /* SharingServicePicker.swift in Sources */, 2A95E68C2A19A3CA001288B8 /* WriterTextView.swift in Sources */, 2A95E64D2A19A398001288B8 /* PFDashboardContentView.swift in Sources */, + 2A5DA7572E5958510074549F /* SleepHelper.swift in Sources */, 6AA2C2032AFF538B00F6C633 /* MyArticleGridView.swift in Sources */, 6AB75A8E2A5496F20050AD58 /* MyPlanetTemplateSettingsView.swift in Sources */, 2A996ADA2A1DA6D100BEF898 /* PlanetDownloadsWebView.swift in Sources */, @@ -2275,6 +2280,7 @@ 6A52FAE92A8893E9000E85F0 /* PublicArticleModel.swift in Sources */, 6AC01AF0291ECC7E00EB6B5F /* WalletAccountView.swift in Sources */, 721145603D528B27CC6091D1 /* WriterDragAndDrop.swift in Sources */, + 2A5DA7582E5958510074549F /* SleepHelper.swift in Sources */, 2AA7974329496F730031E873 /* PFDashboardSidebarViewController.swift in Sources */, 2A3C6E762C22A3AA007B2CCD /* IPFSStatusWindowController.swift in Sources */, 2A391F052BF3137A006A3FD6 /* IPFSTrafficView.swift in Sources */, diff --git a/Planet/API/PlanetAPIController.swift b/Planet/API/PlanetAPIController.swift index 03baaf74..07b7a298 100644 --- a/Planet/API/PlanetAPIController.swift +++ b/Planet/API/PlanetAPIController.swift @@ -91,6 +91,9 @@ class PlanetAPIController: NSObject, ObservableObject { UserDefaults.standard.set(true, forKey: .settingsAPIEnabled) } startBonjourService() + DispatchQueue.main.async { + SleepHelper.shared.enablePreventingIdleSleep() + } } func stop(skipStatus: Bool = false) async throws { @@ -119,6 +122,11 @@ class PlanetAPIController: NSObject, ObservableObject { } } stopBonjourService() + DispatchQueue.main.async { + if !IPFSState.shared.online { + SleepHelper.shared.disablePreventingIdleSleep() + } + } } // MARK: - Bonjour Service diff --git a/Planet/Helper/SleepHelper.swift b/Planet/Helper/SleepHelper.swift new file mode 100644 index 00000000..63d4500f --- /dev/null +++ b/Planet/Helper/SleepHelper.swift @@ -0,0 +1,53 @@ +// +// SleepHelper.swift +// SleepHelper +// +// Created by Kai on 8/23/25. +// + +import Foundation +import os +import IOKit +import IOKit.pwr_mgt + + +class SleepHelper: NSObject { + static let shared = SleepHelper() + + static let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "SleepHelper") + + private var reason: CFString = "IPFS Daemon or API Server is running in background." as CFString + private var assertionID: IOPMAssertionID = 0 + private var returnStatus: IOReturn? + + // Preventing user idle sleep + // https://developer.apple.com/documentation/iokit/kiopmassertiontypepreventuseridlesystemsleep + func enablePreventingIdleSleep() { + if let previousReturnStatus = returnStatus, previousReturnStatus == kIOReturnSuccess { + Self.logger.info("Already enabled preventing user idle sleep, abort action.") + return + } + returnStatus = IOPMAssertionCreateWithName( + kIOPMAssertionTypePreventUserIdleSystemSleep as CFString, + IOPMAssertionLevel(kIOPMAssertionLevelOn), + reason, + &assertionID + ) + if let status = returnStatus, status == kIOReturnSuccess { + Self.logger.info("Preventing user idle sleep enabled.") + } else { + Self.logger.info("Failed to prevent user idle sleep.") + } + } + + func disablePreventingIdleSleep() { + guard let previousReturnStatus = returnStatus, previousReturnStatus == kIOReturnSuccess + else { + Self.logger.info("No need to disable preventing user idle sleep, abort action.") + return + } + _ = IOPMAssertionRelease(assertionID) + returnStatus = nil + Self.logger.info("Preventing user idle sleep disabled.") + } +} diff --git a/Planet/IPFS/IPFSDaemon.swift b/Planet/IPFS/IPFSDaemon.swift index b935b20d..dc35d730 100644 --- a/Planet/IPFS/IPFSDaemon.swift +++ b/Planet/IPFS/IPFSDaemon.swift @@ -316,6 +316,9 @@ actor IPFSDaemon { IPFSState.shared.updateOperatingStatus(false) } } + DispatchQueue.main.async { + SleepHelper.shared.enablePreventingIdleSleep() + } } }, errHandler: { data in @@ -380,6 +383,11 @@ actor IPFSDaemon { Task { @MainActor in IPFSState.shared.updateOperatingStatus(false) } + DispatchQueue.main.async { + if !PlanetAPIController.shared.serverIsRunning { + SleepHelper.shared.disablePreventingIdleSleep() + } + } } func generateKey(name: String) throws -> String { diff --git a/Planet/versioning.xcconfig b/Planet/versioning.xcconfig index a62839a2..33543f8c 100644 --- a/Planet/versioning.xcconfig +++ b/Planet/versioning.xcconfig @@ -1 +1 @@ -CURRENT_PROJECT_VERSION = 2548 +CURRENT_PROJECT_VERSION = 2549