Refactor task usage and profile auto update

This commit is contained in:
世界
2023-09-22 11:32:51 +08:00
parent 390e063f20
commit 3374f8e727
49 changed files with 823 additions and 636 deletions
@@ -2,44 +2,59 @@ import Foundation
import Library
public enum ProfileUpdateTask {
static let minUpdateInterval: TimeInterval = 15 * 60
static let defaultUpdateInterval: TimeInterval = 60 * 60
private static var timer: Timer?
public static func setup() throws {
var earliestBeginDate: Date?
if let updatedAt = try oldestUpdated() {
if updatedAt > Date(timeIntervalSinceNow: -taskInterval) {
earliestBeginDate = updatedAt.addingTimeInterval(taskInterval)
}
public static func configure() async throws {
timer?.invalidate()
timer = nil
let profiles = try await ProfileManager.listAutoUpdateEnabled()
if profiles.isEmpty {
return
}
timer = Timer(fire: earliestBeginDate ?? Date.now, interval: taskInterval, repeats: true, block: { _ in
do {
_ = try updateProfiles()
NSLog("profile update task succeed")
} catch {
NSLog("profile update task failed: \(error.localizedDescription)")
var updateInterval = profiles.map { it in
it.autoUpdateIntervalOrDefault
}.min()!
if updateInterval < minUpdateInterval {
updateInterval = minUpdateInterval
}
timer = Timer(fire: calculateEarliestBeginDate(profiles), interval: updateInterval, repeats: true, block: { _ in
Task {
await getAndupdateProfiles()
}
})
}
static let taskInterval: TimeInterval = 15 * 60
static func oldestUpdated() throws -> Date? {
let profiles = try ProfileManager.listAutoUpdateEnabled()
return profiles.map { profile in
profile.lastUpdated!
static func calculateEarliestBeginDate(_ profiles: [Profile]) -> Date {
let nowTime = Date.now
var earliestBeginDate = profiles.map { it in
it.lastUpdated!.addingTimeInterval(it.autoUpdateIntervalOrDefault)
}.min()!
if earliestBeginDate <= nowTime {
earliestBeginDate = nowTime
}
.min()
return earliestBeginDate
}
static func updateProfiles() throws -> Bool {
let profiles = try ProfileManager.listAutoUpdateEnabled()
private nonisolated static func getAndupdateProfiles() async {
do {
_ = try await updateProfiles(ProfileManager.listAutoUpdateEnabled())
NSLog("profile update task succeed")
} catch {
NSLog("profile update task failed: \(error.localizedDescription)")
}
}
static func updateProfiles(_ profiles: [Profile]) async throws -> Bool {
var success = true
for profile in profiles {
if profile.lastUpdated! > Date(timeIntervalSinceNow: -taskInterval) {
if profile.lastUpdated! > Date(timeIntervalSinceNow: -profile.autoUpdateIntervalOrDefault) {
continue
}
do {
try profile.updateRemoteProfile()
try await profile.updateRemoteProfile()
} catch {
NSLog("Update profile \(profile.name) failed: \(error.localizedDescription)")
success = false
@@ -48,3 +63,13 @@ public enum ProfileUpdateTask {
return success
}
}
extension Profile {
var autoUpdateIntervalOrDefault: TimeInterval {
if autoUpdateInterval > 0 {
return TimeInterval(autoUpdateInterval * 60)
} else {
return ProfileUpdateTask.defaultUpdateInterval
}
}
}
@@ -4,37 +4,49 @@ import Library
#if os(iOS) || os(tvOS)
public class UIProfileUpdateTask: BGAppRefreshTask {
public static let taskSchedulerPermittedIdentifier = "\(FilePath.packageName).update_profiles"
private static let taskSchedulerPermittedIdentifier = "\(FilePath.packageName).update_profiles"
public static func setup() async throws {
public static func configure() async throws {
let success = BGTaskScheduler.shared.register(forTaskWithIdentifier: taskSchedulerPermittedIdentifier, using: nil) { task in
NSLog("profile update task started")
do {
let success = try ProfileUpdateTask.updateProfiles()
try? scheduleUpdate(Date(timeIntervalSinceNow: ProfileUpdateTask.taskInterval))
task.setTaskCompleted(success: success)
NSLog("profile update task succeed")
} catch {
try? scheduleUpdate(nil)
task.setTaskCompleted(success: false)
NSLog("profile update task failed: \(error.localizedDescription)")
}
task.expirationHandler = {
try? scheduleUpdate(nil)
NSLog("profile update task expired")
Task {
await getAndupdateProfiles(task)
}
}
if !success {
throw NSError(domain: "register failed", code: 0)
}
if await BGTaskScheduler.shared.pendingTaskRequests().isEmpty {
var earliestBeginDate: Date? = nil
if let updatedAt = try ProfileUpdateTask.oldestUpdated() {
if updatedAt > Date(timeIntervalSinceNow: -ProfileUpdateTask.taskInterval) {
earliestBeginDate = updatedAt.addingTimeInterval(ProfileUpdateTask.taskInterval)
}
}
try scheduleUpdate(earliestBeginDate)
BGTaskScheduler.shared.cancelAllTaskRequests()
let profiles = try await ProfileManager.listAutoUpdateEnabled()
if profiles.isEmpty {
return
}
try scheduleUpdate(ProfileUpdateTask.calculateEarliestBeginDate(profiles))
}
private nonisolated static func getAndupdateProfiles(_ task: BGTask) async {
let profiles: [Profile]
do {
profiles = try await ProfileManager.listAutoUpdateEnabled()
} catch {
return
}
if profiles.isEmpty {
return
}
do {
let success = try await ProfileUpdateTask.updateProfiles(profiles)
try? scheduleUpdate(ProfileUpdateTask.calculateEarliestBeginDate(profiles))
task.setTaskCompleted(success: success)
NSLog("profile update task succeed")
} catch {
try? scheduleUpdate(nil)
task.setTaskCompleted(success: false)
NSLog("profile update task failed: \(error.localizedDescription)")
}
task.expirationHandler = {
try? scheduleUpdate(nil)
NSLog("profile update task expired")
}
}