Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Threema/ThreemaFramework/TaskManager/   (Social Medium ©)  Datei vom 26.9.2026 mit Größe 9 kB image not shown  

Quelle  TaskManager.swift   Sprache: JAVA

 

import CocoaLumberjackSwift
import FileUtility
import Foundation
import PromiseKit

enum TaskManagerError: Error {
    case flushedTask, noTaskQueueFound
}

typealias TaskReceiverNonce = [String: Data]

public final class TaskManager: NSObject, TaskManagerProtocol {
    private let entityManager: EntityManager?
    private let serverConnector: ServerConnectorProtocol

    private static var taskQueue: TaskQueue?

    private static let addTaskQueue = DispatchQueue(label: "ch.threema.TaskManager.addTaskQueue")

    @objc required init(
        backgroundEntityManager entityManager: EntityManager?,
        serverConnector: ServerConnectorProtocol
    ) {
        self.entityManager = entityManager
        self.serverConnector = serverConnector
        super.init()

        load()
    }

    override convenience init() {
        self.init(backgroundEntityManager: nil, serverConnector: ServerConnector.shared())
    }

    func add(taskDefinition: TaskDefinitionProtocol) -> CancelableTask? {
        TaskManager.addTaskQueue.async {
            do {
                try self.add(task: taskDefinition, completionHandler: nil)
            }
            catch {
                DDLogError("Failed add task to queue \(error)")
            }

            self.spool()
        }
        
        assert(taskDefinition is TaskDefinition, "We always expect a `TaskDefinition`")
        
        // Only drop on disconnect tasks are cancelable
        if let task = taskDefinition as? TaskDefinition, task.type == .dropOnDisconnect {
            return CancelableDropOnDisconnectTask(taskDefinition: task, serverConnector: serverConnector)
        }
        else {
            return nil
        }
    }
    
    /// Caution: Tasks with retry the completion handler might be called multiple times!
    func addWithWait(taskDefinition: TaskDefinitionProtocol) -> (WaitTask, CancelableTask?) {

        // This is a bit crazy, but the best we could come up with
        let completionTask: Task<Void, Error> = Task {
            try await withCheckedThrowingContinuation { continuation in
                TaskManager.addTaskQueue.async {
                    do {
                        try self.add(task: taskDefinition) { _, error in
                            if let error {
                                continuation.resume(throwing: error)
                            }
                            else {
                                continuation.resume()
                            }
                        }
                    }
                    catch {
                        DDLogError("Failed add task to queue \(error)")
                    }
                    
                    self.spool()
                }
            }
        }
        
        let waitTask = DefaultWaitTask(completionTask: completionTask)
        
        assert(taskDefinition is TaskDefinition, "We always expect a `TaskDefinition`")
        
        // Only drop on disconnect tasks are cancelable
        if let task = taskDefinition as? TaskDefinition, task.type == .dropOnDisconnect {
            let cancelableTask = CancelableDropOnDisconnectTask(taskDefinition: task, serverConnector: serverConnector)
            return (waitTask, cancelableTask)
        }
        else {
            return (waitTask, nil)
        }
    }

    func add(
        taskDefinition: TaskDefinitionProtocol,
        completionHandler: @escaping TaskCompletionHandler
    ) -> CancelableTask? {
        TaskManager.addTaskQueue.async {
            do {
                try self.add(task: taskDefinition, completionHandler: completionHandler)
            }
            catch {
                DDLogError("Failed add task to queue \(error)")
            }

            self.spool()
        }
        
        assert(taskDefinition is TaskDefinition, "We always expect a `TaskDefinition`")
        
        // Only drop on disconnect tasks are cancelable
        if let task = taskDefinition as? TaskDefinition, task.type == .dropOnDisconnect {
            return CancelableDropOnDisconnectTask(taskDefinition: task, serverConnector: serverConnector)
        }
        else {
            return nil
        }
    }

    func add(taskDefinitionTuples: [(
        taskDefinition: TaskDefinitionProtocol,
        completionHandler: TaskCompletionHandler
    )]) -> [CancelableTask?] {
        TaskManager.addTaskQueue.async {
            do {
                for taskDefinitionTuple in taskDefinitionTuples {
                    try self.add(
                        task: taskDefinitionTuple.taskDefinition,
                        completionHandler: taskDefinitionTuple.completionHandler
                    )
                }
            }
            catch {
                DDLogError("Failed add task to queue \(error)")
            }

            self.spool()
        }
        
        var cancellableTasks = [CancelableTask?]()
        for taskDefinitionTuple in taskDefinitionTuples {
            
            assert(taskDefinitionTuple.taskDefinition is TaskDefinition, "We always expect a `TaskDefinition`")
            
            // Only drop on disconnect tasks are cancelable
            if let task = taskDefinitionTuple.taskDefinition as? TaskDefinition, task.type == .dropOnDisconnect {
                cancellableTasks.append(CancelableDropOnDisconnectTask(
                    taskDefinition: task,
                    serverConnector: serverConnector
                ))
            }
            else {
                cancellableTasks.append(nil)
            }
        }
        
        assert(cancellableTasks.count == taskDefinitionTuples.count)
        
        return cancellableTasks
    }

    private func add(task: TaskDefinitionProtocol, completionHandler: TaskCompletionHandler? = nil) throws {
        guard let queue = TaskManager.taskQueue, let task = task as? TaskDefinition else {
            throw TaskManagerError.noTaskQueueFound
        }
        
        try queue.enqueue(task: task, completionHandler: completionHandler)
    }

    func executeSubTask(taskDefinition: any TaskDefinitionProtocol) async throws {
        try await TaskManager.taskQueue?.executeSubTask(taskDefinition: taskDefinition)
    }

    @objc public static func interrupt() {
        TaskManager.taskQueue?.interrupt()
    }

    @objc public static func removeAllTasks() {
        TaskManager.taskQueue?.removeAll()
    }

    public static func removeCurrentTask() {
        TaskManager.taskQueue?.removeCurrent()
    }

    public static func isEmpty() -> Bool {
        TaskManager.taskQueue?.list.isEmpty ?? true
    }

    /// Get notification name for particular reflecting/acking of a message.
    ///
    /// - Returns: kNotificationMediatorMessageAck + hex string of reflect ID
    @objc static func mediatorMessageAckObserverName(reflectID: Data) -> Notification.Name {
        Notification.Name("\(kNotificationMediatorMessageAck)\(reflectID.hexString)")
    }

    /// Get notification name for particular sending/acking of a message.
    ///
    /// - Returns: kNotificationChatMessageAck + hex string of message ID
    @objc static func chatMessageAckObserverName(messageID: Data, toIdentity: String) -> Notification.Name {
        Notification.Name("\(kNotificationChatMessageAck)\(messageID.hexString)\(toIdentity)")
    }

    /// Execute all pending tasks.
    @objc func spool() {
        TaskManager.taskQueue?.spool()
    }

    private func load() {
        TaskManager.addTaskQueue.async {
            if TaskManager.taskQueue == nil {
                TaskManager.taskQueue = TaskQueue(
                    frameworkInjectorResolver: FrameworkInjectorResolver(backgroundEntityManager: self.entityManager)
                )

                if let queuePath = TaskManager.taskQueue?.queuePath(),
                   FileUtility.shared.fileExists(at: queuePath) {
                    if let data = FileUtility.shared.read(fileURL: queuePath) {
                        FileUtility.shared.deleteIfExists(at: queuePath)

                        TaskManager.taskQueue?.decode(data)
                    }
                }
            }
        }
    }
}

// MARK: Objective-C extension for the TaskManager

extension TaskManager {
    @available(swift, obsoleted: 1.0, renamed: "add(taskDefinition:)", message: "Only use from Objective-C")
    @objc func addObjc(taskDefinition: AnyObject) {
        assert(taskDefinition is TaskDefinition)
        guard let taskDefinition = taskDefinition as? TaskDefinition else {
            DDLogError("Worng type for taskDefinition")
            return
        }
        
        _ = add(taskDefinition: taskDefinition)
    }

    @available(
        swift,
        obsoleted: 1.0,
        renamed: "add(taskDefinition:completionHandler:)",
        message: "Only use from Objective-C"
    )
    @objc func addObjc(taskDefinition: AnyObject, completionHandler: @escaping (AnyObject, Error?) -> Void) {
        assert(taskDefinition is TaskDefinition)
        guard let taskDefinition = taskDefinition as? TaskDefinition else {
            DDLogError("Worng type for taskDefinition")
            return
        }

        _ = add(taskDefinition: taskDefinition) { task, error in
            completionHandler(task as! TaskDefinition, error)
        }
    }
}

Messung
CHZG
859610093

¤ Dauer der Verarbeitung: 0.0 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.