Combine.swift 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. //
  2. // Combine.swift
  3. //
  4. // Copyright (c) 2020 Alamofire Software Foundation (http://alamofire.org/)
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to deal
  8. // in the Software without restriction, including without limitation the rights
  9. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. // copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. // THE SOFTWARE.
  23. //
  24. #if canImport(Combine)
  25. import Combine
  26. import Dispatch
  27. import Foundation
  28. // MARK: - DataRequest / UploadRequest
  29. /// A Combine `Publisher` that publishes the `DataResponse<Value, AFError>` of the provided `DataRequest`.
  30. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  31. public struct DataResponsePublisher<Value>: Publisher {
  32. public typealias Output = DataResponse<Value, AFError>
  33. public typealias Failure = Never
  34. private typealias Handler = (@escaping (_ response: DataResponse<Value, AFError>) -> Void) -> DataRequest
  35. private let request: DataRequest
  36. private let responseHandler: Handler
  37. /// Creates an instance which will serialize responses using the provided `ResponseSerializer`.
  38. ///
  39. /// - Parameters:
  40. /// - request: `DataRequest` for which to publish the response.
  41. /// - queue: `DispatchQueue` on which the `DataResponse` value will be published. `.main` by default.
  42. /// - serializer: `ResponseSerializer` used to produce the published `DataResponse`.
  43. public init<Serializer: ResponseSerializer>(_ request: DataRequest, queue: DispatchQueue, serializer: Serializer)
  44. where Value == Serializer.SerializedObject {
  45. self.request = request
  46. responseHandler = { request.response(queue: queue, responseSerializer: serializer, completionHandler: $0) }
  47. }
  48. /// Creates an instance which will serialize responses using the provided `DataResponseSerializerProtocol`.
  49. ///
  50. /// - Parameters:
  51. /// - request: `DataRequest` for which to publish the response.
  52. /// - queue: `DispatchQueue` on which the `DataResponse` value will be published. `.main` by default.
  53. /// - serializer: `DataResponseSerializerProtocol` used to produce the published `DataResponse`.
  54. public init<Serializer: DataResponseSerializerProtocol>(_ request: DataRequest,
  55. queue: DispatchQueue,
  56. serializer: Serializer)
  57. where Value == Serializer.SerializedObject {
  58. self.request = request
  59. responseHandler = { request.response(queue: queue, responseSerializer: serializer, completionHandler: $0) }
  60. }
  61. /// Publishes only the `Result` of the `DataResponse` value.
  62. ///
  63. /// - Returns: The `AnyPublisher` publishing the `Result<Value, AFError>` value.
  64. public func result() -> AnyPublisher<Result<Value, AFError>, Never> {
  65. map { $0.result }.eraseToAnyPublisher()
  66. }
  67. /// Publishes the `Result` of the `DataResponse` as a single `Value` or fail with the `AFError` instance.
  68. ///
  69. /// - Returns: The `AnyPublisher<Value, AFError>` publishing the stream.
  70. public func value() -> AnyPublisher<Value, AFError> {
  71. setFailureType(to: AFError.self).flatMap { $0.result.publisher }.eraseToAnyPublisher()
  72. }
  73. public func receive<S>(subscriber: S) where S: Subscriber, DataResponsePublisher.Failure == S.Failure, DataResponsePublisher.Output == S.Input {
  74. subscriber.receive(subscription: Inner(request: request,
  75. responseHandler: responseHandler,
  76. downstream: subscriber))
  77. }
  78. private final class Inner<Downstream: Subscriber>: Subscription, Cancellable
  79. where Downstream.Input == Output {
  80. typealias Failure = Downstream.Failure
  81. @Protected
  82. private var downstream: Downstream?
  83. private let request: DataRequest
  84. private let responseHandler: Handler
  85. init(request: DataRequest, responseHandler: @escaping Handler, downstream: Downstream) {
  86. self.request = request
  87. self.responseHandler = responseHandler
  88. self.downstream = downstream
  89. }
  90. func request(_ demand: Subscribers.Demand) {
  91. assert(demand > 0)
  92. guard let downstream = downstream else { return }
  93. self.downstream = nil
  94. responseHandler { response in
  95. _ = downstream.receive(response)
  96. downstream.receive(completion: .finished)
  97. }.resume()
  98. }
  99. func cancel() {
  100. request.cancel()
  101. downstream = nil
  102. }
  103. }
  104. }
  105. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  106. extension DataResponsePublisher where Value == Data? {
  107. /// Creates an instance which publishes a `DataResponse<Data?, AFError>` value without serialization.
  108. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  109. public init(_ request: DataRequest, queue: DispatchQueue) {
  110. self.request = request
  111. responseHandler = { request.response(queue: queue, completionHandler: $0) }
  112. }
  113. }
  114. extension DataRequest {
  115. /// Creates a `DataResponsePublisher` for this instance using the given `ResponseSerializer` and `DispatchQueue`.
  116. ///
  117. /// - Parameters:
  118. /// - serializer: `ResponseSerializer` used to serialize response `Data`.
  119. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  120. ///
  121. /// - Returns: The `DataResponsePublisher`.
  122. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  123. public func publishResponse<Serializer: ResponseSerializer, T>(using serializer: Serializer, on queue: DispatchQueue = .main) -> DataResponsePublisher<T>
  124. where Serializer.SerializedObject == T {
  125. DataResponsePublisher(self, queue: queue, serializer: serializer)
  126. }
  127. /// Creates a `DataResponsePublisher` for this instance and uses a `DataResponseSerializer` to serialize the
  128. /// response.
  129. ///
  130. /// - Parameters:
  131. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  132. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()`
  133. /// by default.
  134. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  135. /// default.
  136. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless of
  137. /// status code. `[.head]` by default.
  138. /// - Returns: The `DataResponsePublisher`.
  139. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  140. public func publishData(queue: DispatchQueue = .main,
  141. preprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
  142. emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
  143. emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods) -> DataResponsePublisher<Data> {
  144. publishResponse(using: DataResponseSerializer(dataPreprocessor: preprocessor,
  145. emptyResponseCodes: emptyResponseCodes,
  146. emptyRequestMethods: emptyRequestMethods),
  147. on: queue)
  148. }
  149. /// Creates a `DataResponsePublisher` for this instance and uses a `StringResponseSerializer` to serialize the
  150. /// response.
  151. ///
  152. /// - Parameters:
  153. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  154. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()`
  155. /// by default.
  156. /// - encoding: `String.Encoding` to parse the response. `nil` by default, in which case the encoding
  157. /// will be determined by the server response, falling back to the default HTTP character
  158. /// set, `ISO-8859-1`.
  159. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  160. /// default.
  161. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless of
  162. /// status code. `[.head]` by default.
  163. ///
  164. /// - Returns: The `DataResponsePublisher`.
  165. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  166. public func publishString(queue: DispatchQueue = .main,
  167. preprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
  168. encoding: String.Encoding? = nil,
  169. emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
  170. emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods) -> DataResponsePublisher<String> {
  171. publishResponse(using: StringResponseSerializer(dataPreprocessor: preprocessor,
  172. encoding: encoding,
  173. emptyResponseCodes: emptyResponseCodes,
  174. emptyRequestMethods: emptyRequestMethods),
  175. on: queue)
  176. }
  177. /// Creates a `DataResponsePublisher` for this instance and uses a `DecodableResponseSerializer` to serialize the
  178. /// response.
  179. ///
  180. /// - Parameters:
  181. /// - type: `Decodable` type to which to decode response `Data`. Inferred from the context by default.
  182. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  183. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()`
  184. /// by default.
  185. /// - decoder: `DataDecoder` instance used to decode response `Data`. `JSONDecoder()` by default.
  186. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  187. /// default.
  188. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless of
  189. /// status code. `[.head]` by default.
  190. ///
  191. /// - Returns: The `DataResponsePublisher`.
  192. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  193. public func publishDecodable<T: Decodable>(type: T.Type = T.self,
  194. queue: DispatchQueue = .main,
  195. preprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
  196. decoder: DataDecoder = JSONDecoder(),
  197. emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
  198. emptyResponseMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods) -> DataResponsePublisher<T> {
  199. publishResponse(using: DecodableResponseSerializer(dataPreprocessor: preprocessor,
  200. decoder: decoder,
  201. emptyResponseCodes: emptyResponseCodes,
  202. emptyRequestMethods: emptyResponseMethods),
  203. on: queue)
  204. }
  205. /// Creates a `DataResponsePublisher` for this instance which does not serialize the response before publishing.
  206. ///
  207. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  208. ///
  209. /// - Returns: The `DataResponsePublisher`.
  210. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  211. public func publishUnserialized(queue: DispatchQueue = .main) -> DataResponsePublisher<Data?> {
  212. DataResponsePublisher(self, queue: queue)
  213. }
  214. }
  215. // A Combine `Publisher` that publishes a sequence of `Stream<Value, AFError>` values received by the provided `DataStreamRequest`.
  216. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  217. public struct DataStreamPublisher<Value>: Publisher {
  218. public typealias Output = DataStreamRequest.Stream<Value, AFError>
  219. public typealias Failure = Never
  220. private typealias Handler = (@escaping DataStreamRequest.Handler<Value, AFError>) -> DataStreamRequest
  221. private let request: DataStreamRequest
  222. private let streamHandler: Handler
  223. /// Creates an instance which will serialize responses using the provided `DataStreamSerializer`.
  224. ///
  225. /// - Parameters:
  226. /// - request: `DataStreamRequest` for which to publish the response.
  227. /// - queue: `DispatchQueue` on which the `Stream<Value, AFError>` values will be published. `.main` by
  228. /// default.
  229. /// - serializer: `DataStreamSerializer` used to produce the published `Stream<Value, AFError>` values.
  230. public init<Serializer: DataStreamSerializer>(_ request: DataStreamRequest, queue: DispatchQueue, serializer: Serializer)
  231. where Value == Serializer.SerializedObject {
  232. self.request = request
  233. streamHandler = { request.responseStream(using: serializer, on: queue, stream: $0) }
  234. }
  235. /// Publishes only the `Result` of the `DataStreamRequest.Stream`'s `Event`s.
  236. ///
  237. /// - Returns: The `AnyPublisher` publishing the `Result<Value, AFError>` value.
  238. public func result() -> AnyPublisher<Result<Value, AFError>, Never> {
  239. compactMap { stream in
  240. switch stream.event {
  241. case let .stream(result):
  242. return result
  243. // If the stream has completed with an error, send the error value downstream as a `.failure`.
  244. case let .complete(completion):
  245. return completion.error.map(Result.failure)
  246. }
  247. }
  248. .eraseToAnyPublisher()
  249. }
  250. /// Publishes the streamed values of the `DataStreamRequest.Stream` as a sequence of `Value` or fail with the
  251. /// `AFError` instance.
  252. ///
  253. /// - Returns: The `AnyPublisher<Value, AFError>` publishing the stream.
  254. public func value() -> AnyPublisher<Value, AFError> {
  255. result().setFailureType(to: AFError.self).flatMap { $0.publisher }.eraseToAnyPublisher()
  256. }
  257. public func receive<S>(subscriber: S) where S: Subscriber, DataStreamPublisher.Failure == S.Failure, DataStreamPublisher.Output == S.Input {
  258. subscriber.receive(subscription: Inner(request: request,
  259. streamHandler: streamHandler,
  260. downstream: subscriber))
  261. }
  262. private final class Inner<Downstream: Subscriber>: Subscription, Cancellable
  263. where Downstream.Input == Output {
  264. typealias Failure = Downstream.Failure
  265. @Protected
  266. private var downstream: Downstream?
  267. private let request: DataStreamRequest
  268. private let streamHandler: Handler
  269. init(request: DataStreamRequest, streamHandler: @escaping Handler, downstream: Downstream) {
  270. self.request = request
  271. self.streamHandler = streamHandler
  272. self.downstream = downstream
  273. }
  274. func request(_ demand: Subscribers.Demand) {
  275. assert(demand > 0)
  276. guard let downstream = downstream else { return }
  277. self.downstream = nil
  278. streamHandler { stream in
  279. _ = downstream.receive(stream)
  280. if case .complete = stream.event {
  281. downstream.receive(completion: .finished)
  282. }
  283. }.resume()
  284. }
  285. func cancel() {
  286. request.cancel()
  287. downstream = nil
  288. }
  289. }
  290. }
  291. extension DataStreamRequest {
  292. /// Creates a `DataStreamPublisher` for this instance using the given `DataStreamSerializer` and `DispatchQueue`.
  293. ///
  294. /// - Parameters:
  295. /// - serializer: `DataStreamSerializer` used to serialize the streamed `Data`.
  296. /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default.
  297. /// - Returns: The `DataStreamPublisher`.
  298. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  299. public func publishStream<Serializer: DataStreamSerializer>(using serializer: Serializer,
  300. on queue: DispatchQueue = .main) -> DataStreamPublisher<Serializer.SerializedObject> {
  301. DataStreamPublisher(self, queue: queue, serializer: serializer)
  302. }
  303. /// Creates a `DataStreamPublisher` for this instance which uses a `PassthroughStreamSerializer` to stream `Data`
  304. /// unserialized.
  305. ///
  306. /// - Parameters:
  307. /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default.
  308. /// - Returns: The `DataStreamPublisher`.
  309. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  310. public func publishData(queue: DispatchQueue = .main) -> DataStreamPublisher<Data> {
  311. publishStream(using: PassthroughStreamSerializer(), on: queue)
  312. }
  313. /// Creates a `DataStreamPublisher` for this instance which uses a `StringStreamSerializer` to serialize stream
  314. /// `Data` values into `String` values.
  315. ///
  316. /// - Parameters:
  317. /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default.
  318. /// - Returns: The `DataStreamPublisher`.
  319. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  320. public func publishString(queue: DispatchQueue = .main) -> DataStreamPublisher<String> {
  321. publishStream(using: StringStreamSerializer(), on: queue)
  322. }
  323. /// Creates a `DataStreamPublisher` for this instance which uses a `DecodableStreamSerializer` with the provided
  324. /// parameters to serialize stream `Data` values into the provided type.
  325. ///
  326. /// - Parameters:
  327. /// - type: `Decodable` type to which to decode stream `Data`. Inferred from the context by default.
  328. /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default.
  329. /// - decoder: `DataDecoder` instance used to decode stream `Data`. `JSONDecoder()` by default.
  330. /// - preprocessor: `DataPreprocessor` which filters incoming stream `Data` before serialization.
  331. /// `PassthroughPreprocessor()` by default.
  332. /// - Returns: The `DataStreamPublisher`.
  333. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  334. public func publishDecodable<T: Decodable>(type: T.Type = T.self,
  335. queue: DispatchQueue = .main,
  336. decoder: DataDecoder = JSONDecoder(),
  337. preprocessor: DataPreprocessor = PassthroughPreprocessor()) -> DataStreamPublisher<T> {
  338. publishStream(using: DecodableStreamSerializer(decoder: decoder,
  339. dataPreprocessor: preprocessor),
  340. on: queue)
  341. }
  342. }
  343. /// A Combine `Publisher` that publishes the `DownloadResponse<Value, AFError>` of the provided `DownloadRequest`.
  344. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  345. public struct DownloadResponsePublisher<Value>: Publisher {
  346. public typealias Output = DownloadResponse<Value, AFError>
  347. public typealias Failure = Never
  348. private typealias Handler = (@escaping (_ response: DownloadResponse<Value, AFError>) -> Void) -> DownloadRequest
  349. private let request: DownloadRequest
  350. private let responseHandler: Handler
  351. /// Creates an instance which will serialize responses using the provided `ResponseSerializer`.
  352. ///
  353. /// - Parameters:
  354. /// - request: `DownloadRequest` for which to publish the response.
  355. /// - queue: `DispatchQueue` on which the `DownloadResponse` value will be published. `.main` by default.
  356. /// - serializer: `ResponseSerializer` used to produce the published `DownloadResponse`.
  357. public init<Serializer: ResponseSerializer>(_ request: DownloadRequest, queue: DispatchQueue, serializer: Serializer)
  358. where Value == Serializer.SerializedObject {
  359. self.request = request
  360. responseHandler = { request.response(queue: queue, responseSerializer: serializer, completionHandler: $0) }
  361. }
  362. /// Creates an instance which will serialize responses using the provided `DownloadResponseSerializerProtocol` value.
  363. ///
  364. /// - Parameters:
  365. /// - request: `DownloadRequest` for which to publish the response.
  366. /// - queue: `DispatchQueue` on which the `DataResponse` value will be published. `.main` by default.
  367. /// - serializer: `DownloadResponseSerializerProtocol` used to produce the published `DownloadResponse`.
  368. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  369. public init<Serializer: DownloadResponseSerializerProtocol>(_ request: DownloadRequest,
  370. queue: DispatchQueue,
  371. serializer: Serializer)
  372. where Value == Serializer.SerializedObject {
  373. self.request = request
  374. responseHandler = { request.response(queue: queue, responseSerializer: serializer, completionHandler: $0) }
  375. }
  376. /// Publishes only the `Result` of the `DownloadResponse` value.
  377. ///
  378. /// - Returns: The `AnyPublisher` publishing the `Result<Value, AFError>` value.
  379. public func result() -> AnyPublisher<Result<Value, AFError>, Never> {
  380. map { $0.result }.eraseToAnyPublisher()
  381. }
  382. /// Publishes the `Result` of the `DownloadResponse` as a single `Value` or fail with the `AFError` instance.
  383. ///
  384. /// - Returns: The `AnyPublisher<Value, AFError>` publishing the stream.
  385. public func value() -> AnyPublisher<Value, AFError> {
  386. setFailureType(to: AFError.self).flatMap { $0.result.publisher }.eraseToAnyPublisher()
  387. }
  388. public func receive<S>(subscriber: S) where S: Subscriber, DownloadResponsePublisher.Failure == S.Failure, DownloadResponsePublisher.Output == S.Input {
  389. subscriber.receive(subscription: Inner(request: request,
  390. responseHandler: responseHandler,
  391. downstream: subscriber))
  392. }
  393. private final class Inner<Downstream: Subscriber>: Subscription, Cancellable
  394. where Downstream.Input == Output {
  395. typealias Failure = Downstream.Failure
  396. @Protected
  397. private var downstream: Downstream?
  398. private let request: DownloadRequest
  399. private let responseHandler: Handler
  400. init(request: DownloadRequest, responseHandler: @escaping Handler, downstream: Downstream) {
  401. self.request = request
  402. self.responseHandler = responseHandler
  403. self.downstream = downstream
  404. }
  405. func request(_ demand: Subscribers.Demand) {
  406. assert(demand > 0)
  407. guard let downstream = downstream else { return }
  408. self.downstream = nil
  409. responseHandler { response in
  410. _ = downstream.receive(response)
  411. downstream.receive(completion: .finished)
  412. }.resume()
  413. }
  414. func cancel() {
  415. request.cancel()
  416. downstream = nil
  417. }
  418. }
  419. }
  420. extension DownloadRequest {
  421. /// Creates a `DownloadResponsePublisher` for this instance using the given `ResponseSerializer` and `DispatchQueue`.
  422. ///
  423. /// - Parameters:
  424. /// - serializer: `ResponseSerializer` used to serialize the response `Data` from disk.
  425. /// - queue: `DispatchQueue` on which the `DownloadResponse` will be published.`.main` by default.
  426. ///
  427. /// - Returns: The `DownloadResponsePublisher`.
  428. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  429. public func publishResponse<Serializer: ResponseSerializer, T>(using serializer: Serializer, on queue: DispatchQueue = .main) -> DownloadResponsePublisher<T>
  430. where Serializer.SerializedObject == T {
  431. DownloadResponsePublisher(self, queue: queue, serializer: serializer)
  432. }
  433. /// Creates a `DownloadResponsePublisher` for this instance using the given `DownloadResponseSerializerProtocol` and
  434. /// `DispatchQueue`.
  435. ///
  436. /// - Parameters:
  437. /// - serializer: `DownloadResponseSerializer` used to serialize the response `Data` from disk.
  438. /// - queue: `DispatchQueue` on which the `DownloadResponse` will be published.`.main` by default.
  439. ///
  440. /// - Returns: The `DownloadResponsePublisher`.
  441. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  442. public func publishResponse<Serializer: DownloadResponseSerializerProtocol, T>(using serializer: Serializer, on queue: DispatchQueue = .main) -> DownloadResponsePublisher<T>
  443. where Serializer.SerializedObject == T {
  444. DownloadResponsePublisher(self, queue: queue, serializer: serializer)
  445. }
  446. /// Creates a `DownloadResponsePublisher` for this instance and uses a `URLResponseSerializer` to serialize the
  447. /// response.
  448. ///
  449. /// - Parameter queue: `DispatchQueue` on which the `DownloadResponse` will be published. `.main` by default.
  450. ///
  451. /// - Returns: The `DownloadResponsePublisher`.
  452. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  453. public func publishURL(queue: DispatchQueue = .main) -> DownloadResponsePublisher<URL> {
  454. publishResponse(using: URLResponseSerializer(), on: queue)
  455. }
  456. /// Creates a `DownloadResponsePublisher` for this instance and uses a `DataResponseSerializer` to serialize the
  457. /// response.
  458. ///
  459. /// - Parameters:
  460. /// - queue: `DispatchQueue` on which the `DownloadResponse` will be published. `.main` by default.
  461. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()`
  462. /// by default.
  463. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  464. /// default.
  465. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless of
  466. /// status code. `[.head]` by default.
  467. ///
  468. /// - Returns: The `DownloadResponsePublisher`.
  469. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  470. public func publishData(queue: DispatchQueue = .main,
  471. preprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
  472. emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
  473. emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods) -> DownloadResponsePublisher<Data> {
  474. publishResponse(using: DataResponseSerializer(dataPreprocessor: preprocessor,
  475. emptyResponseCodes: emptyResponseCodes,
  476. emptyRequestMethods: emptyRequestMethods),
  477. on: queue)
  478. }
  479. /// Creates a `DataResponsePublisher` for this instance and uses a `StringResponseSerializer` to serialize the
  480. /// response.
  481. ///
  482. /// - Parameters:
  483. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  484. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()`
  485. /// by default.
  486. /// - encoding: `String.Encoding` to parse the response. `nil` by default, in which case the encoding
  487. /// will be determined by the server response, falling back to the default HTTP character
  488. /// set, `ISO-8859-1`.
  489. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  490. /// default.
  491. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless of
  492. /// status code. `[.head]` by default.
  493. ///
  494. /// - Returns: The `DownloadResponsePublisher`.
  495. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  496. public func publishString(queue: DispatchQueue = .main,
  497. preprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
  498. encoding: String.Encoding? = nil,
  499. emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
  500. emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods) -> DownloadResponsePublisher<String> {
  501. publishResponse(using: StringResponseSerializer(dataPreprocessor: preprocessor,
  502. encoding: encoding,
  503. emptyResponseCodes: emptyResponseCodes,
  504. emptyRequestMethods: emptyRequestMethods),
  505. on: queue)
  506. }
  507. /// Creates a `DataResponsePublisher` for this instance and uses a `DecodableResponseSerializer` to serialize the
  508. /// response.
  509. ///
  510. /// - Parameters:
  511. /// - type: `Decodable` type to which to decode response `Data`. Inferred from the context by default.
  512. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  513. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()`
  514. /// by default.
  515. /// - decoder: `DataDecoder` instance used to decode response `Data`. `JSONDecoder()` by default.
  516. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  517. /// default.
  518. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless of
  519. /// status code. `[.head]` by default.
  520. ///
  521. /// - Returns: The `DownloadResponsePublisher`.
  522. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  523. public func publishDecodable<T: Decodable>(type: T.Type = T.self,
  524. queue: DispatchQueue = .main,
  525. preprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
  526. decoder: DataDecoder = JSONDecoder(),
  527. emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
  528. emptyResponseMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods) -> DownloadResponsePublisher<T> {
  529. publishResponse(using: DecodableResponseSerializer(dataPreprocessor: preprocessor,
  530. decoder: decoder,
  531. emptyResponseCodes: emptyResponseCodes,
  532. emptyRequestMethods: emptyResponseMethods),
  533. on: queue)
  534. }
  535. }
  536. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  537. extension DownloadResponsePublisher where Value == URL? {
  538. /// Creates an instance which publishes a `DownloadResponse<URL?, AFError>` value without serialization.
  539. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  540. public init(_ request: DownloadRequest, queue: DispatchQueue) {
  541. self.request = request
  542. responseHandler = { request.response(queue: queue, completionHandler: $0) }
  543. }
  544. }
  545. extension DownloadRequest {
  546. /// Creates a `DownloadResponsePublisher` for this instance which does not serialize the response before publishing.
  547. ///
  548. /// - Parameter queue: `DispatchQueue` on which the `DownloadResponse` will be published. `.main` by default.
  549. ///
  550. /// - Returns: The `DownloadResponsePublisher`.
  551. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  552. public func publishUnserialized(on queue: DispatchQueue = .main) -> DownloadResponsePublisher<URL?> {
  553. DownloadResponsePublisher(self, queue: queue)
  554. }
  555. }
  556. #endif