Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 39 additions & 5 deletions Sources/HTTPClient/Interface/HTTPBody+Progress.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import Foundation

extension HTTPBody {
/// Tracks the progress of the body and calls the handler.
public func trackingProgress(handler: @escaping (Progress) -> Void) -> HTTPBody {
var totalBytesProcessed: Int64 = 0
public func trackingProgress(handler: @escaping @Sendable (Progress) -> Void) -> HTTPBody {
let totalLength: Int64? =
switch self.length {
case .known(let length):
Expand All @@ -12,16 +11,51 @@ extension HTTPBody {
nil
}

let sequence = self.map { chunk in
let sequence = ProgressTrackingSequence(
base: self,
totalLength: totalLength,
handler: handler
)

return HTTPBody(sequence, length: self.length, iterationBehavior: self.iterationBehavior)
}
}

/// An async sequence that tracks progress and forwards chunks from the underlying sequence.
private struct ProgressTrackingSequence: AsyncSequence, Sendable {
typealias Element = HTTPBody.ByteChunk

let base: HTTPBody
let totalLength: Int64?
let handler: @Sendable (Progress) -> Void

func makeAsyncIterator() -> Iterator {
Iterator(
base: base.makeAsyncIterator(),
totalLength: totalLength,
handler: handler
)
}

struct Iterator: AsyncIteratorProtocol {
var base: HTTPBody.Iterator
let totalLength: Int64?
let handler: @Sendable (Progress) -> Void
var totalBytesProcessed: Int64 = 0

mutating func next() async throws -> Element? {
guard let chunk = try await base.next() else {
return nil
}

let chunkSize = Int64(chunk.count)
totalBytesProcessed += chunkSize

let progress = Progress(completed: totalBytesProcessed, total: totalLength)
handler(progress)

return chunk
}

return HTTPBody(sequence, length: self.length, iterationBehavior: self.iterationBehavior)
}
}

Expand Down
Loading