Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  BlobDownloader.swift   Sprache: JAVA

 

import CocoaLumberjackSwift
import Foundation
import PromiseKit

/// Used to keep track of URLSessionTasks and their progress. Should not be called directly but rather through
/// BlobManager.
final class BlobDownloader: NSObject {
    
    enum BlobDownloaderError: Error {
        case downloadFailed(message: String)
        case invalidDownloadURL
    }
    
    private let blobURL: BlobURL
    private let queue: DispatchQueue
    private var urlSessionManager: URLSessionManager
    
    private var progressObservers = [NSManagedObjectID: NSKeyValueObservation]()
    private var activeTasks = [NSManagedObjectID: URLSessionTask]()

    // MARK: - Lifecycle
    
    init(
        blobURL: BlobURL,
        queue: DispatchQueue = DispatchQueue.main,
        sessionManager: URLSessionManager = .shared
    ) {
        self.blobURL = blobURL
        self.queue = queue
        self.urlSessionManager = sessionManager
        super.init()
    }
    
    @objc init(blobURL: BlobURL, queue: DispatchQueue = DispatchQueue.main) {
        self.blobURL = blobURL
        self.queue = queue
        self.urlSessionManager = .shared
        super.init()
    }
    
    // MARK: - Download
    
    /// Downloads given data and provides progress updates to its delegate
    /// - Parameters:
    ///   - blobData: Data to be downloaded
    ///   - origin: Origin of the Blob
    ///   - objectID: ObjectID used to track progress
    ///   - delegate: Delegate to send progress updates to
    /// - Returns: Received data from server
    func download(
        blobID: Data,
        origin: BlobOrigin,
        objectID: NSManagedObjectID,
        delegate: BlobManagerDelegate? = nil
    ) async throws -> Data {
        try await withCheckedThrowingContinuation { continuation in
            
            blobURL.download(blobID: blobID, origin: origin) { downloadURL, error in
                if let error {
                    continuation.resume(throwing: error)
                    return
                }
                
                guard let downloadURL else {
                    continuation.resume(throwing: BlobDownloaderError.invalidDownloadURL)
                    return
                }

                let task = self.startDownload(for: downloadURL, timeout: nil) { data, error in
                    // Download was completed
                    if let error {
                        continuation.resume(throwing: error)
                    }
                    else if let data {
                        continuation.resume(returning: data)
                    }
                    else {
                        continuation
                            .resume(throwing: BlobDownloaderError.downloadFailed(message: "[Blob] No data downloaded"))
                    }
                    
                    // Remove completed Task
                    self.progressObservers.removeValue(forKey: objectID)
                    self.activeTasks.removeValue(forKey: objectID)
                }
                
                // Add created task to keep track
                let observer = task.progress.observe(\.fractionCompleted) { progress, _ in
                    Task {
                        await delegate?.updateProgress(for: objectID, didUpdate: progress)
                    }
                }

                self.progressObservers[objectID] = observer
                self.activeTasks[objectID] = task
            }
        }
    }

    @objc func download(blobID: Data, origin: BlobOrigin, completion: @escaping (Data?, Error?) -> Void) {
        download(blobID: blobID, origin: origin, timeout: 60, completion: completion)
    }

    @objc func download(
        blobID: Data,
        origin: BlobOrigin,
        timeout: TimeInterval,
        completion: @escaping (Data?, Error?) -> Void
    ) {
        blobURL.download(blobID: blobID, origin: origin) { downloadURL, _ in
            guard let downloadURL else {
                completion(nil, BlobDownloaderError.invalidDownloadURL)
                return
            }
            
            self.startDownload(for: downloadURL, timeout: timeout, completion: completion)
        }
    }

    @objc func markDownloadDone(for blobID: Data, origin: BlobOrigin) {
        blobURL.done(
            blobID: blobID,
            origin: origin
        ) { doneURL, error in
            if let error {
                DDLogError("Marking blob ID \(blobID.hexString) failed: \(error)")
                return
            }

            guard let doneURL else {
                DDLogWarn("Download done URL for blob ID \(blobID.hexString) missing")
                return
            }

            Task {
                let httpClient = HTTPClient(sessionManager: self.urlSessionManager)
                try await httpClient.sendDone(url: doneURL)
            }
        }
    }
    
    @discardableResult
    private func startDownload(
        for url: URL,
        timeout: TimeInterval? = nil,
        completion: @escaping (Data?, Error?) -> Void
    ) -> URLSessionDataTask {
        let httpClient = HTTPClient(sessionManager: urlSessionManager)
        let task = httpClient.downloadData(
            url: url, contentType: .octetStream, timeout: timeout
        ) { data, response, error in

            var downloadError: Error?

            if let error {
                downloadError = error
            }
            else {
                if response is HTTPURLResponse {
                    if let response = response as? HTTPURLResponse,
                       !(200...299).contains(response.statusCode) {
                        downloadError = NSError(domain: "Download failed", code: response.statusCode)
                    }
                }
                else {
                    downloadError = BlobDownloaderError
                        .downloadFailed(message: "Download failed because response is missing")
                }
            }
            self.queue.async {
                completion(data, downloadError)
            }
        }
        return task
    }
    
    /// Cancels a download for a given objectID if it exists
    /// - Parameters:
    ///   - objectID: ObjectID of Blob
    public func cancelDownload(for objectID: NSManagedObjectID) {
        guard let task = activeTasks[objectID] else {
            return
        }
        
        task.cancel()
        activeTasks.removeValue(forKey: objectID)
        progressObservers.removeValue(forKey: objectID)
    }
}

Messung
CHZG
879310093

¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104845
#Domains=499168