Temp
This commit is contained in:
parent
4d4fcdd17f
commit
4f517ed01f
6 changed files with 220 additions and 88 deletions
|
|
@ -1527,6 +1527,7 @@ plist_fragment(
|
|||
<array>
|
||||
<string>{telegram_bundle_id}.refresh</string>
|
||||
<string>{telegram_bundle_id}.cleanup</string>
|
||||
<string>{telegram_bundle_id}.upload.*</string>
|
||||
</array>
|
||||
<key>CFBundleAllowMixedLocalizations</key>
|
||||
<true/>
|
||||
|
|
|
|||
|
|
@ -917,15 +917,47 @@ public final class AccountAuxiliaryMethods {
|
|||
}
|
||||
}
|
||||
|
||||
public struct AccountRunningImportantTasks: OptionSet {
|
||||
public var rawValue: Int32
|
||||
|
||||
public init(rawValue: Int32) {
|
||||
self.rawValue = rawValue
|
||||
public struct AccountRunningImportantTasks: Equatable {
|
||||
public struct TaskTypes: OptionSet {
|
||||
public var rawValue: Int32
|
||||
|
||||
public init(rawValue: Int32) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
public static let other = TaskTypes(rawValue: 1 << 0)
|
||||
}
|
||||
|
||||
public static let other = AccountRunningImportantTasks(rawValue: 1 << 0)
|
||||
public static let pendingMessages = AccountRunningImportantTasks(rawValue: 1 << 1)
|
||||
public var taskTypes: TaskTypes
|
||||
public var pendingMessageCount: Int
|
||||
public var pendingStoryCount: Int
|
||||
|
||||
public init(taskTypes: TaskTypes, pendingMessageCount: Int, pendingStoryCount: Int) {
|
||||
self.taskTypes = taskTypes
|
||||
self.pendingMessageCount = pendingMessageCount
|
||||
self.pendingStoryCount = pendingStoryCount
|
||||
}
|
||||
|
||||
public func combine(with other: AccountRunningImportantTasks) -> AccountRunningImportantTasks {
|
||||
return AccountRunningImportantTasks(
|
||||
taskTypes: self.taskTypes.union(other.taskTypes),
|
||||
pendingMessageCount: self.pendingMessageCount + other.pendingMessageCount,
|
||||
pendingStoryCount: self.pendingStoryCount + other.pendingStoryCount
|
||||
)
|
||||
}
|
||||
|
||||
public var isEmpty: Bool {
|
||||
if !self.taskTypes.isEmpty {
|
||||
return false
|
||||
}
|
||||
if self.pendingMessageCount != 0 {
|
||||
return false
|
||||
}
|
||||
if self.pendingStoryCount != 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public struct MasterNotificationKey: Codable {
|
||||
|
|
@ -1189,7 +1221,7 @@ public class Account {
|
|||
return self._loggedOut.get()
|
||||
}
|
||||
|
||||
private let _importantTasksRunning = ValuePromise<AccountRunningImportantTasks>([], ignoreRepeated: true)
|
||||
private let _importantTasksRunning = ValuePromise<AccountRunningImportantTasks>(AccountRunningImportantTasks(taskTypes: [], pendingMessageCount: 0, pendingStoryCount: 0), ignoreRepeated: true)
|
||||
public var importantTasksRunning: Signal<AccountRunningImportantTasks, NoError> {
|
||||
return self._importantTasksRunning.get()
|
||||
}
|
||||
|
|
@ -1393,51 +1425,55 @@ public class Account {
|
|||
|
||||
let extractedExpr1: [Signal<AccountRunningImportantTasks, NoError>] = [
|
||||
managedSynchronizeChatInputStateOperations(postbox: self.postbox, network: self.network) |> map { inputStates in
|
||||
if inputStates {
|
||||
//print("inputStates: true")
|
||||
}
|
||||
return inputStates ? AccountRunningImportantTasks.other : []
|
||||
return AccountRunningImportantTasks(
|
||||
taskTypes: inputStates ? .other : [],
|
||||
pendingMessageCount: 0,
|
||||
pendingStoryCount: 0
|
||||
)
|
||||
},
|
||||
self.pendingMessageManager.hasPendingMessages |> map { hasPendingMessages in
|
||||
if !hasPendingMessages.isEmpty {
|
||||
//print("hasPendingMessages: true")
|
||||
}
|
||||
return !hasPendingMessages.isEmpty ? AccountRunningImportantTasks.pendingMessages : []
|
||||
self.pendingMessageManager.pendingMessageCount |> map { pendingMessageCount in
|
||||
return AccountRunningImportantTasks(
|
||||
taskTypes: [],
|
||||
pendingMessageCount: pendingMessageCount.values.reduce(into: 0, { $0 += $1 }),
|
||||
pendingStoryCount: 0
|
||||
)
|
||||
},
|
||||
(self.pendingStoryManager?.hasPending ?? .single(false)) |> map { hasPending in
|
||||
if hasPending {
|
||||
//print("hasPending: true")
|
||||
}
|
||||
return hasPending ? AccountRunningImportantTasks.pendingMessages : []
|
||||
return AccountRunningImportantTasks(
|
||||
taskTypes: [],
|
||||
pendingMessageCount: 0,
|
||||
pendingStoryCount: hasPending ? 1 : 0
|
||||
)
|
||||
},
|
||||
self.pendingUpdateMessageManager.updatingMessageMedia |> map { updatingMessageMedia in
|
||||
if !updatingMessageMedia.isEmpty {
|
||||
//print("updatingMessageMedia: true")
|
||||
}
|
||||
return !updatingMessageMedia.isEmpty ? AccountRunningImportantTasks.pendingMessages : []
|
||||
return AccountRunningImportantTasks(
|
||||
taskTypes: [],
|
||||
pendingMessageCount: updatingMessageMedia.count,
|
||||
pendingStoryCount: 0
|
||||
)
|
||||
},
|
||||
self.pendingPeerMediaUploadManager.uploadingPeerMedia |> map { uploadingPeerMedia in
|
||||
if !uploadingPeerMedia.isEmpty {
|
||||
//print("uploadingPeerMedia: true")
|
||||
}
|
||||
return !uploadingPeerMedia.isEmpty ? AccountRunningImportantTasks.pendingMessages : []
|
||||
return AccountRunningImportantTasks(
|
||||
taskTypes: [],
|
||||
pendingMessageCount: uploadingPeerMedia.count,
|
||||
pendingStoryCount: 0
|
||||
)
|
||||
},
|
||||
self.accountPresenceManager.isPerformingUpdate() |> map { presenceUpdate in
|
||||
if presenceUpdate {
|
||||
//print("accountPresenceManager isPerformingUpdate: true")
|
||||
//return []
|
||||
}
|
||||
return presenceUpdate ? AccountRunningImportantTasks.other : []
|
||||
},
|
||||
//self.notificationAutolockReportManager.isPerformingUpdate() |> map { $0 ? AccountRunningImportantTasks.other : [] }
|
||||
return AccountRunningImportantTasks(
|
||||
taskTypes: presenceUpdate ? .other : [],
|
||||
pendingMessageCount: 0,
|
||||
pendingStoryCount: 0
|
||||
)
|
||||
}
|
||||
]
|
||||
let extractedExpr: [Signal<AccountRunningImportantTasks, NoError>] = extractedExpr1
|
||||
let importantBackgroundOperations: [Signal<AccountRunningImportantTasks, NoError>] = extractedExpr
|
||||
let importantBackgroundOperationsRunning = combineLatest(queue: Queue(), importantBackgroundOperations)
|
||||
|> map { values -> AccountRunningImportantTasks in
|
||||
var result: AccountRunningImportantTasks = []
|
||||
var result: AccountRunningImportantTasks = AccountRunningImportantTasks(taskTypes: [], pendingMessageCount: 0, pendingStoryCount: 0)
|
||||
for value in values {
|
||||
result.formUnion(value)
|
||||
result = result.combine(with: value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -219,9 +219,9 @@ public final class PendingMessageManager {
|
|||
|
||||
private let queue = Queue()
|
||||
|
||||
private let _hasPendingMessages = ValuePromise<Set<PeerId>>(Set(), ignoreRepeated: true)
|
||||
public var hasPendingMessages: Signal<Set<PeerId>, NoError> {
|
||||
return self._hasPendingMessages.get()
|
||||
private let _pendingMessageCount = ValuePromise<[PeerId: Int]>([:], ignoreRepeated: true)
|
||||
public var pendingMessageCount: Signal<[PeerId: Int], NoError> {
|
||||
return self._pendingMessageCount.get()
|
||||
}
|
||||
|
||||
private var messageContexts: [MessageId: PendingMessageContext] = [:]
|
||||
|
|
@ -344,14 +344,18 @@ public final class PendingMessageManager {
|
|||
})
|
||||
}
|
||||
|
||||
var peersWithPendingMessages = Set<PeerId>()
|
||||
var pendingMessageCount: [PeerId: Int] = [:]
|
||||
for id in self.pendingMessageIds {
|
||||
peersWithPendingMessages.insert(id.peerId)
|
||||
if let current = pendingMessageCount[id.peerId] {
|
||||
pendingMessageCount[id.peerId] = current + 1
|
||||
} else {
|
||||
pendingMessageCount[id.peerId] = 1
|
||||
}
|
||||
}
|
||||
|
||||
Logger.shared.log("PendingMessageManager", "pending messages: \(self.pendingMessageIds)")
|
||||
|
||||
self._hasPendingMessages.set(peersWithPendingMessages)
|
||||
self._pendingMessageCount.set(pendingMessageCount)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1521,31 +1521,6 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
|||
}
|
||||
}
|
||||
|
||||
/*if UIApplication.shared.isStatusBarHidden {
|
||||
UIApplication.shared.internalSetStatusBarHidden(false, animation: .none)
|
||||
}*/
|
||||
|
||||
/*if #available(iOS 13.0, *) {
|
||||
BGTaskScheduler.shared.register(forTaskWithIdentifier: baseAppBundleId + ".refresh", using: nil, launchHandler: { task in
|
||||
let _ = (self.sharedContextPromise.get()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { sharedApplicationContext in
|
||||
|
||||
sharedApplicationContext.wakeupManager.replaceCurrentExtensionWithExternalTime(completion: {
|
||||
task.setTaskCompleted(success: true)
|
||||
}, timeout: 29.0)
|
||||
let _ = (self.context.get()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { context in
|
||||
guard let context = context else {
|
||||
return
|
||||
}
|
||||
sharedApplicationContext.notificationManager.beginPollingState(account: context.context.account)
|
||||
})
|
||||
})
|
||||
})
|
||||
}*/
|
||||
|
||||
self.maybeCheckForUpdates()
|
||||
|
||||
#if canImport(AppCenter)
|
||||
|
|
@ -1557,9 +1532,9 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
|||
#endif
|
||||
|
||||
if #available(iOS 13.0, *) {
|
||||
let taskId = "\(baseAppBundleId).cleanup"
|
||||
let cleanupTaskId = "\(baseAppBundleId).cleanup"
|
||||
|
||||
BGTaskScheduler.shared.register(forTaskWithIdentifier: taskId, using: DispatchQueue.main) { task in
|
||||
BGTaskScheduler.shared.register(forTaskWithIdentifier: cleanupTaskId, using: DispatchQueue.main) { task in
|
||||
Logger.shared.log("App \(self.episodeId)", "Executing cleanup task")
|
||||
|
||||
let disposable = self.runCacheReindexTasks(lowImpact: true, completion: {
|
||||
|
|
@ -1575,11 +1550,11 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
|||
}
|
||||
|
||||
BGTaskScheduler.shared.getPendingTaskRequests(completionHandler: { tasks in
|
||||
if tasks.contains(where: { $0.identifier == taskId }) {
|
||||
if tasks.contains(where: { $0.identifier == cleanupTaskId }) {
|
||||
Logger.shared.log("App \(self.episodeId)", "Already have a cleanup task pending")
|
||||
return
|
||||
}
|
||||
let request = BGProcessingTaskRequest(identifier: taskId)
|
||||
let request = BGProcessingTaskRequest(identifier: cleanupTaskId)
|
||||
request.requiresExternalPower = true
|
||||
request.requiresNetworkConnectivity = false
|
||||
|
||||
|
|
|
|||
|
|
@ -2186,10 +2186,9 @@ extension ChatControllerImpl {
|
|||
let chatLocationPeerId = chatLocation.peerId
|
||||
|
||||
if let chatLocationPeerId = chatLocationPeerId {
|
||||
hasPendingMessages = context.account.pendingMessageManager.hasPendingMessages
|
||||
|> mapToSignal { peerIds -> Signal<Bool, NoError> in
|
||||
let value = peerIds.contains(chatLocationPeerId)
|
||||
if value {
|
||||
hasPendingMessages = context.account.pendingMessageManager.pendingMessageCount
|
||||
|> mapToSignal { pendingMessageCount -> Signal<Bool, NoError> in
|
||||
if let value = pendingMessageCount[chatLocationPeerId], value != 0 {
|
||||
return .single(true)
|
||||
} else {
|
||||
return .single(false)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import Foundation
|
||||
import BackgroundTasks
|
||||
import AVFAudio
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
|
|
@ -75,6 +76,10 @@ public final class SharedWakeupManager {
|
|||
|
||||
private var accountsAndTasks: [(Account, Bool, AccountTasks)] = []
|
||||
|
||||
private var pendingMessageTotalCount: Int?
|
||||
private var nextBackgroundProcessingTaskId: Int = 0
|
||||
private var backgroundProcessingTaskId: String?
|
||||
|
||||
public init(beginBackgroundTask: @escaping (String, @escaping () -> Void) -> UIBackgroundTaskIdentifier?, endBackgroundTask: @escaping (UIBackgroundTaskIdentifier) -> Void, backgroundTimeRemaining: @escaping () -> Double, acquireIdleExtension: @escaping () -> Disposable?, activeAccounts: Signal<(primary: Account?, accounts: [(AccountRecordId, Account)]), NoError>, liveLocationPolling: Signal<AccountRecordId?, NoError>, watchTasks: Signal<AccountRecordId?, NoError>, inForeground: Signal<Bool, NoError>, hasActiveAudioSession: Signal<Bool, NoError>, notificationManager: SharedNotificationManager?, mediaManager: MediaManager, callManager: PresentationCallManager?, accountUserInterfaceInUse: @escaping (AccountRecordId) -> Signal<Bool, NoError>) {
|
||||
assert(Queue.mainQueue().isCurrent())
|
||||
|
||||
|
|
@ -312,15 +317,12 @@ public final class SharedWakeupManager {
|
|||
var hasTasksForBackgroundExtension = false
|
||||
|
||||
var hasActiveCalls = false
|
||||
var hasPendingMessages = false
|
||||
var pendingMessageCount = 0
|
||||
for (_, _, tasks) in self.accountsAndTasks {
|
||||
if tasks.activeCalls {
|
||||
hasActiveCalls = true
|
||||
break
|
||||
}
|
||||
if tasks.importantTasks.contains(.pendingMessages) {
|
||||
hasPendingMessages = true
|
||||
}
|
||||
pendingMessageCount += tasks.importantTasks.pendingMessageCount
|
||||
}
|
||||
|
||||
var endTaskAfterTransactionsComplete: UIBackgroundTaskIdentifier?
|
||||
|
|
@ -417,20 +419,135 @@ public final class SharedWakeupManager {
|
|||
self.isInBackgroundExtension = false
|
||||
}
|
||||
}
|
||||
self.updateAccounts(hasTasks: hasTasksForBackgroundExtension, endTaskAfterTransactionsComplete: endTaskAfterTransactionsComplete)
|
||||
|
||||
if hasPendingMessages {
|
||||
let baseAppBundleId = Bundle.main.bundleIdentifier!
|
||||
|
||||
if pendingMessageCount != 0 && !self.inForeground {
|
||||
if self.keepIdleDisposable == nil {
|
||||
self.keepIdleDisposable = self.acquireIdleExtension()
|
||||
}
|
||||
if #available(iOS 26.0, *), self.backgroundProcessingTaskId == nil {
|
||||
let uploadTaskId = "\(baseAppBundleId).upload.\(self.nextBackgroundProcessingTaskId)"
|
||||
self.nextBackgroundProcessingTaskId += 1
|
||||
if let current = self.backgroundProcessingTaskId {
|
||||
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: current)
|
||||
}
|
||||
self.backgroundProcessingTaskId = uploadTaskId
|
||||
|
||||
BGTaskScheduler.shared.register(forTaskWithIdentifier: uploadTaskId, using: nil, launchHandler: { [weak self] task in
|
||||
guard let task = task as? BGContinuedProcessingTask else {
|
||||
return
|
||||
}
|
||||
guard let self else {
|
||||
task.setTaskCompleted(success: true)
|
||||
return
|
||||
}
|
||||
|
||||
var wasExpired = false
|
||||
|
||||
task.expirationHandler = { [weak self] in
|
||||
wasExpired = true
|
||||
|
||||
Queue.mainQueue().async {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if self.backgroundProcessingTaskId == task.identifier {
|
||||
self.backgroundProcessingTaskId = nil
|
||||
self.checkTasks()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Task { @MainActor [weak self] in
|
||||
guard let self else {
|
||||
task.setTaskCompleted(success: true)
|
||||
return
|
||||
}
|
||||
|
||||
while true {
|
||||
if wasExpired {
|
||||
break
|
||||
}
|
||||
var pendingMessageCount = 0
|
||||
for (_, _, tasks) in self.accountsAndTasks {
|
||||
pendingMessageCount += tasks.importantTasks.pendingMessageCount
|
||||
}
|
||||
if pendingMessageCount == 0 {
|
||||
self.pendingMessageTotalCount = nil
|
||||
task.setTaskCompleted(success: true)
|
||||
if self.backgroundProcessingTaskId == task.identifier {
|
||||
self.backgroundProcessingTaskId = nil
|
||||
self.checkTasks()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let totalCount: Int
|
||||
if let value = self.pendingMessageTotalCount {
|
||||
let maxValue = max(value, pendingMessageCount)
|
||||
totalCount = maxValue
|
||||
} else {
|
||||
totalCount = pendingMessageCount
|
||||
}
|
||||
self.pendingMessageTotalCount = totalCount
|
||||
//task.progress.totalUnitCount = Int64(totalCount)
|
||||
//task.progress.completedUnitCount = Int64(max(0, totalCount - pendingMessageCount))
|
||||
|
||||
task.progress.totalUnitCount = 200
|
||||
task.progress.completedUnitCount += 1
|
||||
|
||||
let title: String
|
||||
if totalCount == 1 {
|
||||
title = "Sending 1 Message"
|
||||
} else {
|
||||
title = "Sending \(totalCount) Messages"
|
||||
}
|
||||
if task.title != title {
|
||||
task.updateTitle(title, subtitle: "Running...")
|
||||
}
|
||||
|
||||
try await Task.sleep(for: .seconds(1.0))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let title: String
|
||||
if pendingMessageCount == 1 {
|
||||
title = "Sending 1 Message"
|
||||
} else {
|
||||
title = "Sending \(pendingMessageCount) Messages"
|
||||
}
|
||||
|
||||
let request = BGContinuedProcessingTaskRequest(
|
||||
identifier: uploadTaskId,
|
||||
title: title,
|
||||
subtitle: "Running..."
|
||||
)
|
||||
request.strategy = .fail
|
||||
|
||||
do {
|
||||
try BGTaskScheduler.shared.submit(request)
|
||||
} catch let e {
|
||||
Logger.shared.log("Wakeup", "BGTaskScheduler submit error: \(e)")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let keepIdleDisposable = self.keepIdleDisposable {
|
||||
self.keepIdleDisposable = nil
|
||||
keepIdleDisposable.dispose()
|
||||
}
|
||||
if let backgroundProcessingTaskId = self.backgroundProcessingTaskId {
|
||||
self.backgroundProcessingTaskId = nil
|
||||
|
||||
self.pendingMessageTotalCount = nil
|
||||
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: backgroundProcessingTaskId)
|
||||
}
|
||||
}
|
||||
|
||||
if !self.inForeground && hasPendingMessages && !self.hasActiveAudioSession {
|
||||
self.updateAccounts(hasTasks: hasTasksForBackgroundExtension, endTaskAfterTransactionsComplete: endTaskAfterTransactionsComplete)
|
||||
|
||||
/*if !self.inForeground && pendingMessageCount != 0 && !self.hasActiveAudioSession {
|
||||
if self.silenceAudioRenderer == nil {
|
||||
let audioSession = AVAudioSession()
|
||||
let _ = try? audioSession.setCategory(.ambient)
|
||||
|
|
@ -460,11 +577,11 @@ public final class SharedWakeupManager {
|
|||
} else if let silenceAudioRenderer = self.silenceAudioRenderer {
|
||||
self.silenceAudioRenderer = nil
|
||||
silenceAudioRenderer.stop()
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
private func updateAccounts(hasTasks: Bool, endTaskAfterTransactionsComplete: UIBackgroundTaskIdentifier?) {
|
||||
if self.inForeground || self.hasActiveAudioSession || self.isInBackgroundExtension || (hasTasks && self.currentExternalCompletion != nil) || self.activeExplicitExtensionTimer != nil || self.silenceAudioRenderer != nil {
|
||||
if self.inForeground || self.hasActiveAudioSession || self.isInBackgroundExtension || self.backgroundProcessingTaskId != nil || (hasTasks && self.currentExternalCompletion != nil) || self.activeExplicitExtensionTimer != nil || self.silenceAudioRenderer != nil {
|
||||
Logger.shared.log("Wakeup", "enableBeginTransactions: true (active)")
|
||||
|
||||
for (account, primary, tasks) in self.accountsAndTasks {
|
||||
|
|
@ -475,7 +592,7 @@ public final class SharedWakeupManager {
|
|||
} else {
|
||||
account.shouldBeServiceTaskMaster.set(.single(.never))
|
||||
}
|
||||
account.shouldExplicitelyKeepWorkerConnections.set(.single(tasks.backgroundAudio))
|
||||
account.shouldExplicitelyKeepWorkerConnections.set(.single(tasks.backgroundAudio || tasks.importantTasks.pendingStoryCount != 0 || tasks.importantTasks.pendingMessageCount != 0))
|
||||
account.shouldKeepOnlinePresence.set(.single(primary && self.inForeground))
|
||||
account.shouldKeepBackgroundDownloadConnections.set(.single(tasks.backgroundDownloads))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue