Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  BlobUploader.swift   Sprache: JAVA

 

import CocoaLumberjackSwift
import Foundation
import PromiseKit
import ThreemaEssentials

protocol BlobUploaderProtocol {
    func upload(
        data: Data,
        origin: BlobOrigin,
        setPersistParam: Bool
    ) -> Promise<Data>
}

final class BlobUploader: NSObject, BlobUploaderProtocol {
    
    enum BlobUploaderError: Error {
        case uploadFailed(message: String)
        case invalidUploadURL
        case idGenerationFailed
    }
    
    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()
    }
    
    // MARK: - Upload
    
    /// Uploads given data and provides progress updates to its delegate
    /// - Parameters:
    ///   - blobData: Data to be uploaded
    ///   - origin: Origin of the Blob
    ///   - objectID: ObjectID used to track progress
    ///   - delegate: Delegate to send progress updates to
    /// - Returns: Received data from server
    @discardableResult
    func upload(
        blobData: Data,
        origin: BlobOrigin,
        setPersistParam: Bool,
        objectID: NSManagedObjectID,
        delegate: BlobManagerDelegate? = nil
    ) async throws -> Data {
        try await withCheckedThrowingContinuation { continuation in
            blobURL.upload(
                origin: origin,
                setPersistParam: setPersistParam,
                completionHandler: { uploadURL, authorization, error in
                
                    if let error {
                        continuation.resume(throwing: error)
                        return
                    }
                
                    guard let uploadURL else {
                        continuation.resume(throwing: BlobUploaderError.invalidUploadURL)
                        return
                    }
                
                    let task = self
                        .upload(for: uploadURL, and: blobData, authorization: authorization) { data, error in
                        
                            // Upload was completed
                            if let error {
                                continuation.resume(throwing: error)
                            }
                            else if let data {
                                // We got data, so we create the ID for it
                                guard let blobIDHex = String(bytes: data, encoding: .ascii),
                                      let blobID = BytesUtility.toBytes(hexString: blobIDHex) else {
                                    continuation.resume(throwing: BlobUploaderError.idGenerationFailed)
                                    return
                                }
                            
                                let id = Data(blobID)
                                continuation.resume(returning: id)
                            }
                            else {
                                continuation.resume(
                                    throwing: BlobUploaderError
                                        .uploadFailed(message: "[BlobUploader] Upload unsuccessful.")
                                )
                            }
                        
                            // Remove completed Task
                            self.progressObservers.removeValue(forKey: objectID)
                            self.activeTasks.removeValue(forKey: objectID)
                        }
                
                    // Add created task to keep track
                    self.activeTasks[objectID] = task
                    let observer = task.progress.observe(\.fractionCompleted) { progress, _ in
                        Task {
                            await delegate?.updateProgress(for: objectID, didUpdate: progress)
                        }
                    }
                    self.progressObservers[objectID] = observer
                }
            )
        }
    }

    func upload(
        data: Data,
        origin: BlobOrigin,
        setPersistParam: Bool
    ) -> Promise<Data> {
        Promise { seal in
            blobURL.upload(
                origin: .local,
                setPersistParam: setPersistParam,
                completionHandler: { uploadURL, authorization, error in
                    if let error {
                        seal.reject(error)
                        return
                    }

                    guard let uploadURL else {
                        seal.reject(BlobUploaderError.invalidUploadURL)
                        return
                    }

                    self.upload(for: uploadURL, and: data, authorization: authorization) { data, error in
                        if let error {
                            seal.reject(error)
                            return
                        }

                        guard let data,
                              let idHex = String(bytes: data, encoding: .ascii),
                              let id = BytesUtility.toBytes(hexString: idHex) else {
                            seal.reject(BlobUploaderError.uploadFailed(message: "[BlobUploader] Upload unsuccessful."))
                            return
                        }

                        seal.fulfill(Data(id))
                    }
                }
            )
        }
    }

    @discardableResult
    private func upload(
        for url: URL,
        and data: Data,
        authorization: String?,
        completion: @escaping (Data?, Error?) -> Void
    ) -> URLSessionDataTask {
        
        let client = HTTPClient(authorization: authorization, sessionManager: urlSessionManager)
        let task = client
            .uploadData(
                url: url,
                data: createUploadData(with: data),
                contentType: .multiPart
            ) { data, response, error in
            
                var uploadError: Error?
            
                if let error {
                    uploadError = error
                }
                else {
                    if response is HTTPURLResponse {
                        if let response = response as? HTTPURLResponse,
                           !(200...299).contains(response.statusCode) {
                            uploadError = BlobUploaderError
                                .uploadFailed(
                                    message: "[BlobUploader] Upload failed with response code: \(response.statusCode)."
                                )
                        }
                    }
                    else {
                        uploadError = BlobUploaderError.uploadFailed(message: "[BlobUploader] Response is missing")
                    }
                }
                self.queue.async {
                    completion(data, uploadError)
                }
            }
        return task
    }
    
    /// Cancels a upload for given objectID if it exists
    /// - Parameters:
    ///   - objectID: ObjectID of blob
    public func cancelUpload(for objectID: NSManagedObjectID) {
        guard let task = activeTasks[objectID] else {
            return
        }
        
        task.cancel()
        activeTasks.removeValue(forKey: objectID)
        progressObservers.removeValue(forKey: objectID)
    }
    
    // MARK: - Helpers
    
    private func createUploadData(with blobData: Data) -> Data {
        let boundary = "---------------------------Boundary_Line"
        
        var data = Data()
        data.append(contentsOf: "--\(boundary)\r\n".utf8)
        data.append(contentsOf: "Content-Disposition: form-data; name=\"blob\"; filename=\"blob.bin\"\r\n".utf8)
        data.append(contentsOf: "Content-Type: application/octet-stream\r\n\r\n".utf8)
        data.append(blobData)
        data.append(contentsOf: "\r\n--\(boundary)--\r\n".utf8)
        
        return data
    }
}

Messung
CHZG
869410093

¤ Dauer der Verarbeitung: 0.22 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