Skip to content

Latest commit

 

History

History
91 lines (66 loc) · 4.16 KB

4.Handle_LargeData_Requests.md

File metadata and controls

91 lines (66 loc) · 4.16 KB

Handle Large Data Request

When sending relatively small amounts of data to a server using JSON or URL encoded parameters and data you don't need to setup anything.

Track Progress

If you need to send much larger amounts of data from Data in memory, a file URL, or an InputStream, we suggest setting the appropriate .largeData options for the transferMode property.

This allows you to track the progress of the upload:

let req = HTTPRequest {
    $0.url = URL(string: "http://ipv4.download.thinkbroadband.com/5MB.zip")!
    $0.transferMode = .largeData
    $0.method = .get
}
        
// You can monitor the progress via Combine APIs
req.$progress.sink { progress in
    print("Downloading percentage: \(progress?.percentage ?? 0)%")
}.store(in: &observerBag)
        
let response = try await req.fetch(client)

When using .largeData transfer mode, the data is automatically downloaded into a temporary file located by the .dataFileURL property.

NOTE: If you call .data instead of .dataFileURL the data contained in the file will be automatically loaded into RAM. This should be considered carefully for especially large file transfers.

The progress property is of type HTTPProgress which is a struct with the following properties:

  • event: kind of progress event (upload or download is triggered multiple times during the transfer operation. failed or resumed is sent once only when download has failed, as last track report, or resumed as first track report followed by upload/download events).
  • progress: the instance of Progress object you can use to update the UI
  • currentLength and expectedLength with the current status of the transfer and the total expected size (not all servers will return this data, so you may find both values set to 0).
  • percentage: if tracking is available from the server side, then this value represents the percentage of the transfer.
  • partialData: if the transfer fails, then this contains the partially downloaded data.

Cancel Downloads with resumable data

Bad things happened. If your download fails due to network failure or because your user wanted to cancel it, you may want to store the partially downloaded data in order to attempt to resume the download later.

If you want to cancel a download be sure to call cancel(byProducingResumeData:) with a valid callback.
The callback will contain a copy of the partial data that you can store in a temporary directory to resume the download.

For example:

// Somewhere in your code you may want to cancel the download
// and leave the option to resume it.
req.cancel(byProducingResumeData: { partialData in
    let partialDataURL = URL(file: "/sandbox/location")
    try partialData.write(to: partialDataURL) // resumable data
})

If your download fails due to network error the last progress message contains the path to the resumable data:

req.$progress.sink { progress in
    if progress?.event == .failed, let partialData = progress?.partialData {
       // save it somewhere or assign directly to a new request's `.partialData`
       saveDataInTempLocation(partialData)
    }
}.store(in: &observerBag)

Moreover, the HTTPResponse object returned contains the dataFileURL with the temporary data written to file.

NOTE: It is your responsibility to remove these partial data files from disk.

Resume Downloads

In order to resume downloads with partial data you set the partialData property of the HTTPRequest (and set transferMode to .largeData):

let req = HTTPRequest(...)
req.partialData = ... // your saved partial data

req.$progress.sink { progress in
    // You will receive a first progress.event == .resumed message if
    // resume has succeeded.
    // If you don't receive it, then resume has failed and the download started over.
    // The next progress messages will be download/upload or fail.
}.store(in: &observerBag)
        
let response = try await req.fetch(client)