mirror of
https://github.com/X1a0He/Adobe-Downloader.git
synced 2025-11-25 03:14:57 +08:00
177 lines
6.1 KiB
Swift
177 lines
6.1 KiB
Swift
//
|
|
// HelperMigrationManager.swift
|
|
// Adobe Downloader
|
|
//
|
|
// Created by X1a0He on 2025/07/20.
|
|
//
|
|
|
|
import Foundation
|
|
import ServiceManagement
|
|
import os.log
|
|
|
|
class HelperMigrationManager {
|
|
|
|
private let logger = Logger(subsystem: "com.x1a0he.macOS.Adobe-Downloader", category: "Migration")
|
|
|
|
static func performMigrationIfNeeded() async throws {
|
|
let migrationManager = HelperMigrationManager()
|
|
|
|
if migrationManager.needsMigration() {
|
|
try await migrationManager.performMigration()
|
|
}
|
|
}
|
|
|
|
private func needsMigration() -> Bool {
|
|
// 检查是否存在旧的 SMJobBless 安装
|
|
let legacyPlistPath = "/Library/LaunchDaemons/com.x1a0he.macOS.Adobe-Downloader.helper.plist"
|
|
let legacyHelperPath = "/Library/PrivilegedHelperTools/com.x1a0he.macOS.Adobe-Downloader.helper"
|
|
|
|
let hasLegacyFiles = FileManager.default.fileExists(atPath: legacyPlistPath) ||
|
|
FileManager.default.fileExists(atPath: legacyHelperPath)
|
|
|
|
let appService = SMAppService.daemon(plistName: "com.x1a0he.macOS.Adobe-Downloader.helper")
|
|
let hasModernService = appService.status != .notRegistered
|
|
|
|
logger.info("迁移检查 - 旧文件存在: \(hasLegacyFiles), 新服务已注册: \(hasModernService)")
|
|
|
|
return hasLegacyFiles && !hasModernService
|
|
}
|
|
|
|
private func performMigration() async throws {
|
|
logger.info("开始 Helper 迁移过程")
|
|
|
|
try await stopLegacyService()
|
|
|
|
try await cleanupLegacyFiles()
|
|
|
|
try await registerModernService()
|
|
|
|
try await validateNewService()
|
|
|
|
logger.info("Helper 迁移完成")
|
|
}
|
|
|
|
private func stopLegacyService() async throws {
|
|
logger.info("停止旧的 Helper 服务")
|
|
|
|
let script = """
|
|
#!/bin/bash
|
|
# 停止旧的 LaunchDaemon
|
|
sudo /bin/launchctl unload /Library/LaunchDaemons/com.x1a0he.macOS.Adobe-Downloader.helper.plist 2>/dev/null || true
|
|
|
|
# 终止可能运行的进程
|
|
sudo /usr/bin/killall -u root -9 com.x1a0he.macOS.Adobe-Downloader.helper 2>/dev/null || true
|
|
|
|
exit 0
|
|
"""
|
|
|
|
try await executePrivilegedScript(script, description: "停止旧服务")
|
|
}
|
|
|
|
private func cleanupLegacyFiles() async throws {
|
|
logger.info("清理旧的安装文件")
|
|
|
|
let script = """
|
|
#!/bin/bash
|
|
# 删除旧的 plist 文件
|
|
sudo /bin/rm -f /Library/LaunchDaemons/com.x1a0he.macOS.Adobe-Downloader.helper.plist
|
|
|
|
# 删除旧的 Helper 文件
|
|
sudo /bin/rm -f /Library/PrivilegedHelperTools/com.x1a0he.macOS.Adobe-Downloader.helper
|
|
|
|
exit 0
|
|
"""
|
|
|
|
try await executePrivilegedScript(script, description: "清理旧文件")
|
|
}
|
|
|
|
private func registerModernService() async throws {
|
|
logger.info("注册新的 SMAppService")
|
|
|
|
let modernManager = ModernPrivilegedHelperManager.shared
|
|
await modernManager.checkAndInstallHelper()
|
|
|
|
try await Task.sleep(nanoseconds: 2_000_000_000) // 2 seconds
|
|
}
|
|
|
|
private func validateNewService() async throws {
|
|
logger.info("验证新服务")
|
|
|
|
let modernManager = ModernPrivilegedHelperManager.shared
|
|
let status = await modernManager.getHelperStatus()
|
|
|
|
switch status {
|
|
case .installed:
|
|
logger.info("新服务验证成功")
|
|
case .needsApproval:
|
|
logger.warning("新服务需要用户批准")
|
|
throw MigrationError.requiresUserApproval
|
|
default:
|
|
logger.error("新服务验证失败: \(String(describing: status))")
|
|
throw MigrationError.validationFailed
|
|
}
|
|
}
|
|
|
|
private func executePrivilegedScript(_ script: String, description: String) async throws {
|
|
let tempDir = FileManager.default.temporaryDirectory
|
|
let scriptURL = tempDir.appendingPathComponent("migration_\(UUID().uuidString).sh")
|
|
|
|
try script.write(to: scriptURL, atomically: true, encoding: .utf8)
|
|
try FileManager.default.setAttributes([.posixPermissions: 0o755], ofItemAtPath: scriptURL.path)
|
|
|
|
defer {
|
|
try? FileManager.default.removeItem(at: scriptURL)
|
|
}
|
|
|
|
return try await withCheckedThrowingContinuation { continuation in
|
|
let task = Process()
|
|
task.executableURL = URL(fileURLWithPath: "/usr/bin/osascript")
|
|
task.arguments = ["-e", "do shell script \"\(scriptURL.path)\" with administrator privileges"]
|
|
|
|
do {
|
|
try task.run()
|
|
task.waitUntilExit()
|
|
|
|
if task.terminationStatus == 0 {
|
|
self.logger.info("\(description) 执行成功")
|
|
continuation.resume()
|
|
} else {
|
|
self.logger.error("\(description) 执行失败: \(task.terminationStatus)")
|
|
continuation.resume(throwing: MigrationError.scriptExecutionFailed(description))
|
|
}
|
|
} catch {
|
|
self.logger.error("\(description) 启动失败: \(error)")
|
|
continuation.resume(throwing: error)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
enum MigrationError: LocalizedError {
|
|
case requiresUserApproval
|
|
case validationFailed
|
|
case scriptExecutionFailed(String)
|
|
|
|
var errorDescription: String? {
|
|
switch self {
|
|
case .requiresUserApproval:
|
|
return String(localized: "迁移完成,但需要在系统设置中批准新的 Helper 服务")
|
|
case .validationFailed:
|
|
return String(localized: "新 Helper 服务验证失败")
|
|
case .scriptExecutionFailed(let description):
|
|
return String(localized: "\(description) 执行失败")
|
|
}
|
|
}
|
|
}
|
|
|
|
extension ModernPrivilegedHelperManager {
|
|
static func initializeWithMigration() async throws -> ModernPrivilegedHelperManager {
|
|
try await HelperMigrationManager.performMigrationIfNeeded()
|
|
|
|
let manager = ModernPrivilegedHelperManager.shared
|
|
await manager.checkAndInstallHelper()
|
|
|
|
return manager
|
|
}
|
|
}
|