diff --git a/Sources/AsyncHTTPClient/FileDownloadDelegate.swift b/Sources/AsyncHTTPClient/FileDownloadDelegate.swift index c328c7211..9a351f3c1 100644 --- a/Sources/AsyncHTTPClient/FileDownloadDelegate.swift +++ b/Sources/AsyncHTTPClient/FileDownloadDelegate.swift @@ -31,8 +31,8 @@ public final class FileDownloadDelegate: HTTPClientResponseDelegate { private let filePath: String private(set) var fileIOThreadPool: NIOThreadPool? - private let reportHead: ((HTTPResponseHead) -> Void)? - private let reportProgress: ((Progress) -> Void)? + private let reportHead: ((HTTPClient.Task, HTTPResponseHead) -> Void)? + private let reportProgress: ((HTTPClient.Task, Progress) -> Void)? private var fileHandleFuture: EventLoopFuture? private var writeFuture: EventLoopFuture? @@ -41,25 +41,37 @@ public final class FileDownloadDelegate: HTTPClientResponseDelegate { /// /// - parameters: /// - path: Path to a file you'd like to write the download to. - /// - pool: A thread pool to use for asynchronous file I/O. + /// - pool: A thread pool to use for asynchronous file I/O. If nil, a shared thread pool will be used. Defaults to nil. /// - reportHead: A closure called when the response head is available. /// - reportProgress: A closure called when a body chunk has been downloaded, with /// the total byte count and download byte count passed to it as arguments. The callbacks /// will be invoked in the same threading context that the delegate itself is invoked, /// as controlled by `EventLoopPreference`. - public convenience init( + public init( path: String, - pool: NIOThreadPool, - reportHead: ((HTTPResponseHead) -> Void)? = nil, - reportProgress: ((Progress) -> Void)? = nil + pool: NIOThreadPool? = nil, + reportHead: ((HTTPClient.Task, HTTPResponseHead) -> Void)? = nil, + reportProgress: ((HTTPClient.Task, Progress) -> Void)? = nil ) throws { - try self.init(path: path, pool: .some(pool), reportHead: reportHead, reportProgress: reportProgress) + if let pool = pool { + self.fileIOThreadPool = pool + } else { + // we should use the shared thread pool from the HTTPClient which + // we will get from the `HTTPClient.Task` + self.fileIOThreadPool = nil + } + + self.filePath = path + + self.reportHead = reportHead + self.reportProgress = reportProgress } - /// Initializes a new file download delegate and uses the shared thread pool of the ``HTTPClient`` for file I/O. + /// Initializes a new file download delegate. /// /// - parameters: /// - path: Path to a file you'd like to write the download to. + /// - pool: A thread pool to use for asynchronous file I/O. /// - reportHead: A closure called when the response head is available. /// - reportProgress: A closure called when a body chunk has been downloaded, with /// the total byte count and download byte count passed to it as arguments. The callbacks @@ -67,37 +79,61 @@ public final class FileDownloadDelegate: HTTPClientResponseDelegate { /// as controlled by `EventLoopPreference`. public convenience init( path: String, + pool: NIOThreadPool, reportHead: ((HTTPResponseHead) -> Void)? = nil, reportProgress: ((Progress) -> Void)? = nil ) throws { - try self.init(path: path, pool: nil, reportHead: reportHead, reportProgress: reportProgress) + try self.init( + path: path, + pool: .some(pool), + reportHead: reportHead.map { reportHead in + return { _, head in + reportHead(head) + } + }, + reportProgress: reportProgress.map { reportProgress in + return { _, head in + reportProgress(head) + } + } + ) } - private init( + /// Initializes a new file download delegate and uses the shared thread pool of the ``HTTPClient`` for file I/O. + /// + /// - parameters: + /// - path: Path to a file you'd like to write the download to. + /// - reportHead: A closure called when the response head is available. + /// - reportProgress: A closure called when a body chunk has been downloaded, with + /// the total byte count and download byte count passed to it as arguments. The callbacks + /// will be invoked in the same threading context that the delegate itself is invoked, + /// as controlled by `EventLoopPreference`. + public convenience init( path: String, - pool: NIOThreadPool?, reportHead: ((HTTPResponseHead) -> Void)? = nil, reportProgress: ((Progress) -> Void)? = nil ) throws { - if let pool = pool { - self.fileIOThreadPool = pool - } else { - // we should use the shared thread pool from the HTTPClient which - // we will get from the `HTTPClient.Task` - self.fileIOThreadPool = nil - } - - self.filePath = path - - self.reportHead = reportHead - self.reportProgress = reportProgress + try self.init( + path: path, + pool: nil, + reportHead: reportHead.map { reportHead in + return { _, head in + reportHead(head) + } + }, + reportProgress: reportProgress.map { reportProgress in + return { _, head in + reportProgress(head) + } + } + ) } public func didReceiveHead( task: HTTPClient.Task, _ head: HTTPResponseHead ) -> EventLoopFuture { - self.reportHead?(head) + self.reportHead?(task, head) if let totalBytesString = head.headers.first(name: "Content-Length"), let totalBytes = Int(totalBytesString) { @@ -121,7 +157,7 @@ public final class FileDownloadDelegate: HTTPClientResponseDelegate { }() let io = NonBlockingFileIO(threadPool: threadPool) self.progress.receivedBytes += buffer.readableBytes - self.reportProgress?(self.progress) + self.reportProgress?(task, self.progress) let writeFuture: EventLoopFuture if let fileHandleFuture = self.fileHandleFuture {