Combine.swift 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  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 !((os(iOS) && (arch(i386) || arch(arm))) || os(Windows) || os(Linux))
  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. {
  46. self.request = request
  47. responseHandler = { request.response(queue: queue, responseSerializer: serializer, completionHandler: $0) }
  48. }
  49. /// Creates an instance which will serialize responses using the provided `DataResponseSerializerProtocol`.
  50. ///
  51. /// - Parameters:
  52. /// - request: `DataRequest` for which to publish the response.
  53. /// - queue: `DispatchQueue` on which the `DataResponse` value will be published. `.main` by default.
  54. /// - serializer: `DataResponseSerializerProtocol` used to produce the published `DataResponse`.
  55. public init<Serializer: DataResponseSerializerProtocol>(_ request: DataRequest,
  56. queue: DispatchQueue,
  57. serializer: Serializer)
  58. where Value == Serializer.SerializedObject
  59. {
  60. self.request = request
  61. responseHandler = { request.response(queue: queue, responseSerializer: serializer, completionHandler: $0) }
  62. }
  63. /// Publishes only the `Result` of the `DataResponse` value.
  64. ///
  65. /// - Returns: The `AnyPublisher` publishing the `Result<Value, AFError>` value.
  66. public func result() -> AnyPublisher<Result<Value, AFError>, Never> {
  67. map { $0.result }.eraseToAnyPublisher()
  68. }
  69. /// Publishes the `Result` of the `DataResponse` as a single `Value` or fail with the `AFError` instance.
  70. ///
  71. /// - Returns: The `AnyPublisher<Value, AFError>` publishing the stream.
  72. public func value() -> AnyPublisher<Value, AFError> {
  73. setFailureType(to: AFError.self).flatMap { $0.result.publisher }.eraseToAnyPublisher()
  74. }
  75. public func receive<S>(subscriber: S) where S: Subscriber, DataResponsePublisher.Failure == S.Failure, DataResponsePublisher.Output == S.Input {
  76. subscriber.receive(subscription: Inner(request: request,
  77. responseHandler: responseHandler,
  78. downstream: subscriber))
  79. }
  80. private final class Inner<Downstream: Subscriber>: Subscription, Cancellable
  81. where Downstream.Input == Output
  82. {
  83. typealias Failure = Downstream.Failure
  84. @Protected
  85. private var downstream: Downstream?
  86. private let request: DataRequest
  87. private let responseHandler: Handler
  88. init(request: DataRequest, responseHandler: @escaping Handler, downstream: Downstream) {
  89. self.request = request
  90. self.responseHandler = responseHandler
  91. self.downstream = downstream
  92. }
  93. func request(_ demand: Subscribers.Demand) {
  94. assert(demand > 0)
  95. guard let downstream = downstream else { return }
  96. self.downstream = nil
  97. responseHandler { response in
  98. _ = downstream.receive(response)
  99. downstream.receive(completion: .finished)
  100. }.resume()
  101. }
  102. func cancel() {
  103. request.cancel()
  104. downstream = nil
  105. }
  106. }
  107. }
  108. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  109. public extension DataResponsePublisher where Value == Data? {
  110. /// Creates an instance which publishes a `DataResponse<Data?, AFError>` value without serialization.
  111. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  112. init(_ request: DataRequest, queue: DispatchQueue) {
  113. self.request = request
  114. responseHandler = { request.response(queue: queue, completionHandler: $0) }
  115. }
  116. }
  117. public extension DataRequest {
  118. /// Creates a `DataResponsePublisher` for this instance using the given `ResponseSerializer` and `DispatchQueue`.
  119. ///
  120. /// - Parameters:
  121. /// - serializer: `ResponseSerializer` used to serialize response `Data`.
  122. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  123. ///
  124. /// - Returns: The `DataResponsePublisher`.
  125. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  126. func publishResponse<Serializer: ResponseSerializer, T>(using serializer: Serializer, on queue: DispatchQueue = .main) -> DataResponsePublisher<T>
  127. where Serializer.SerializedObject == T
  128. {
  129. DataResponsePublisher(self, queue: queue, serializer: serializer)
  130. }
  131. /// Creates a `DataResponsePublisher` for this instance and uses a `DataResponseSerializer` to serialize the
  132. /// response.
  133. ///
  134. /// - Parameters:
  135. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  136. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()`
  137. /// by default.
  138. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  139. /// default.
  140. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless of
  141. /// status code. `[.head]` by default.
  142. /// - Returns: The `DataResponsePublisher`.
  143. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  144. func publishData(queue: DispatchQueue = .main,
  145. preprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
  146. emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
  147. emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods) -> DataResponsePublisher<Data>
  148. {
  149. publishResponse(using: DataResponseSerializer(dataPreprocessor: preprocessor,
  150. emptyResponseCodes: emptyResponseCodes,
  151. emptyRequestMethods: emptyRequestMethods),
  152. on: queue)
  153. }
  154. /// Creates a `DataResponsePublisher` for this instance and uses a `StringResponseSerializer` to serialize the
  155. /// response.
  156. ///
  157. /// - Parameters:
  158. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  159. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()`
  160. /// by default.
  161. /// - encoding: `String.Encoding` to parse the response. `nil` by default, in which case the encoding
  162. /// will be determined by the server response, falling back to the default HTTP character
  163. /// set, `ISO-8859-1`.
  164. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  165. /// default.
  166. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless of
  167. /// status code. `[.head]` by default.
  168. ///
  169. /// - Returns: The `DataResponsePublisher`.
  170. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  171. func publishString(queue: DispatchQueue = .main,
  172. preprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
  173. encoding: String.Encoding? = nil,
  174. emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
  175. emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods) -> DataResponsePublisher<String>
  176. {
  177. publishResponse(using: StringResponseSerializer(dataPreprocessor: preprocessor,
  178. encoding: encoding,
  179. emptyResponseCodes: emptyResponseCodes,
  180. emptyRequestMethods: emptyRequestMethods),
  181. on: queue)
  182. }
  183. /// Creates a `DataResponsePublisher` for this instance and uses a `DecodableResponseSerializer` to serialize the
  184. /// response.
  185. ///
  186. /// - Parameters:
  187. /// - type: `Decodable` type to which to decode response `Data`. Inferred from the context by default.
  188. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  189. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()`
  190. /// by default.
  191. /// - decoder: `DataDecoder` instance used to decode response `Data`. `JSONDecoder()` by default.
  192. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  193. /// default.
  194. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless of
  195. /// status code. `[.head]` by default.
  196. ///
  197. /// - Returns: The `DataResponsePublisher`.
  198. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  199. func publishDecodable<T: Decodable>(type _: T.Type = T.self,
  200. queue: DispatchQueue = .main,
  201. preprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
  202. decoder: DataDecoder = JSONDecoder(),
  203. emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
  204. emptyResponseMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods) -> DataResponsePublisher<T>
  205. {
  206. publishResponse(using: DecodableResponseSerializer(dataPreprocessor: preprocessor,
  207. decoder: decoder,
  208. emptyResponseCodes: emptyResponseCodes,
  209. emptyRequestMethods: emptyResponseMethods),
  210. on: queue)
  211. }
  212. /// Creates a `DataResponsePublisher` for this instance which does not serialize the response before publishing.
  213. ///
  214. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  215. ///
  216. /// - Returns: The `DataResponsePublisher`.
  217. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  218. func publishUnserialized(queue: DispatchQueue = .main) -> DataResponsePublisher<Data?> {
  219. DataResponsePublisher(self, queue: queue)
  220. }
  221. }
  222. // A Combine `Publisher` that publishes a sequence of `Stream<Value, AFError>` values received by the provided `DataStreamRequest`.
  223. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  224. public struct DataStreamPublisher<Value>: Publisher {
  225. public typealias Output = DataStreamRequest.Stream<Value, AFError>
  226. public typealias Failure = Never
  227. private typealias Handler = (@escaping DataStreamRequest.Handler<Value, AFError>) -> DataStreamRequest
  228. private let request: DataStreamRequest
  229. private let streamHandler: Handler
  230. /// Creates an instance which will serialize responses using the provided `DataStreamSerializer`.
  231. ///
  232. /// - Parameters:
  233. /// - request: `DataStreamRequest` for which to publish the response.
  234. /// - queue: `DispatchQueue` on which the `Stream<Value, AFError>` values will be published. `.main` by
  235. /// default.
  236. /// - serializer: `DataStreamSerializer` used to produce the published `Stream<Value, AFError>` values.
  237. public init<Serializer: DataStreamSerializer>(_ request: DataStreamRequest, queue: DispatchQueue, serializer: Serializer)
  238. where Value == Serializer.SerializedObject
  239. {
  240. self.request = request
  241. streamHandler = { request.responseStream(using: serializer, on: queue, stream: $0) }
  242. }
  243. /// Publishes only the `Result` of the `DataStreamRequest.Stream`'s `Event`s.
  244. ///
  245. /// - Returns: The `AnyPublisher` publishing the `Result<Value, AFError>` value.
  246. public func result() -> AnyPublisher<Result<Value, AFError>, Never> {
  247. compactMap { stream in
  248. switch stream.event {
  249. case let .stream(result):
  250. return result
  251. // If the stream has completed with an error, send the error value downstream as a `.failure`.
  252. case let .complete(completion):
  253. return completion.error.map(Result.failure)
  254. }
  255. }
  256. .eraseToAnyPublisher()
  257. }
  258. /// Publishes the streamed values of the `DataStreamRequest.Stream` as a sequence of `Value` or fail with the
  259. /// `AFError` instance.
  260. ///
  261. /// - Returns: The `AnyPublisher<Value, AFError>` publishing the stream.
  262. public func value() -> AnyPublisher<Value, AFError> {
  263. result().setFailureType(to: AFError.self).flatMap { $0.publisher }.eraseToAnyPublisher()
  264. }
  265. public func receive<S>(subscriber: S) where S: Subscriber, DataStreamPublisher.Failure == S.Failure, DataStreamPublisher.Output == S.Input {
  266. subscriber.receive(subscription: Inner(request: request,
  267. streamHandler: streamHandler,
  268. downstream: subscriber))
  269. }
  270. private final class Inner<Downstream: Subscriber>: Subscription, Cancellable
  271. where Downstream.Input == Output
  272. {
  273. typealias Failure = Downstream.Failure
  274. @Protected
  275. private var downstream: Downstream?
  276. private let request: DataStreamRequest
  277. private let streamHandler: Handler
  278. init(request: DataStreamRequest, streamHandler: @escaping Handler, downstream: Downstream) {
  279. self.request = request
  280. self.streamHandler = streamHandler
  281. self.downstream = downstream
  282. }
  283. func request(_ demand: Subscribers.Demand) {
  284. assert(demand > 0)
  285. guard let downstream = downstream else { return }
  286. self.downstream = nil
  287. streamHandler { stream in
  288. _ = downstream.receive(stream)
  289. if case .complete = stream.event {
  290. downstream.receive(completion: .finished)
  291. }
  292. }.resume()
  293. }
  294. func cancel() {
  295. request.cancel()
  296. downstream = nil
  297. }
  298. }
  299. }
  300. public extension DataStreamRequest {
  301. /// Creates a `DataStreamPublisher` for this instance using the given `DataStreamSerializer` and `DispatchQueue`.
  302. ///
  303. /// - Parameters:
  304. /// - serializer: `DataStreamSerializer` used to serialize the streamed `Data`.
  305. /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default.
  306. /// - Returns: The `DataStreamPublisher`.
  307. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  308. func publishStream<Serializer: DataStreamSerializer>(using serializer: Serializer,
  309. on queue: DispatchQueue = .main) -> DataStreamPublisher<Serializer.SerializedObject>
  310. {
  311. DataStreamPublisher(self, queue: queue, serializer: serializer)
  312. }
  313. /// Creates a `DataStreamPublisher` for this instance which uses a `PassthroughStreamSerializer` to stream `Data`
  314. /// unserialized.
  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. func publishData(queue: DispatchQueue = .main) -> DataStreamPublisher<Data> {
  321. publishStream(using: PassthroughStreamSerializer(), on: queue)
  322. }
  323. /// Creates a `DataStreamPublisher` for this instance which uses a `StringStreamSerializer` to serialize stream
  324. /// `Data` values into `String` values.
  325. ///
  326. /// - Parameters:
  327. /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default.
  328. /// - Returns: The `DataStreamPublisher`.
  329. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  330. func publishString(queue: DispatchQueue = .main) -> DataStreamPublisher<String> {
  331. publishStream(using: StringStreamSerializer(), on: queue)
  332. }
  333. /// Creates a `DataStreamPublisher` for this instance which uses a `DecodableStreamSerializer` with the provided
  334. /// parameters to serialize stream `Data` values into the provided type.
  335. ///
  336. /// - Parameters:
  337. /// - type: `Decodable` type to which to decode stream `Data`. Inferred from the context by default.
  338. /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default.
  339. /// - decoder: `DataDecoder` instance used to decode stream `Data`. `JSONDecoder()` by default.
  340. /// - preprocessor: `DataPreprocessor` which filters incoming stream `Data` before serialization.
  341. /// `PassthroughPreprocessor()` by default.
  342. /// - Returns: The `DataStreamPublisher`.
  343. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  344. func publishDecodable<T: Decodable>(type _: T.Type = T.self,
  345. queue: DispatchQueue = .main,
  346. decoder: DataDecoder = JSONDecoder(),
  347. preprocessor: DataPreprocessor = PassthroughPreprocessor()) -> DataStreamPublisher<T>
  348. {
  349. publishStream(using: DecodableStreamSerializer(decoder: decoder,
  350. dataPreprocessor: preprocessor),
  351. on: queue)
  352. }
  353. }
  354. /// A Combine `Publisher` that publishes the `DownloadResponse<Value, AFError>` of the provided `DownloadRequest`.
  355. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  356. public struct DownloadResponsePublisher<Value>: Publisher {
  357. public typealias Output = DownloadResponse<Value, AFError>
  358. public typealias Failure = Never
  359. private typealias Handler = (@escaping (_ response: DownloadResponse<Value, AFError>) -> Void) -> DownloadRequest
  360. private let request: DownloadRequest
  361. private let responseHandler: Handler
  362. /// Creates an instance which will serialize responses using the provided `ResponseSerializer`.
  363. ///
  364. /// - Parameters:
  365. /// - request: `DownloadRequest` for which to publish the response.
  366. /// - queue: `DispatchQueue` on which the `DownloadResponse` value will be published. `.main` by default.
  367. /// - serializer: `ResponseSerializer` used to produce the published `DownloadResponse`.
  368. public init<Serializer: ResponseSerializer>(_ request: DownloadRequest, queue: DispatchQueue, serializer: Serializer)
  369. where Value == Serializer.SerializedObject
  370. {
  371. self.request = request
  372. responseHandler = { request.response(queue: queue, responseSerializer: serializer, completionHandler: $0) }
  373. }
  374. /// Creates an instance which will serialize responses using the provided `DownloadResponseSerializerProtocol` value.
  375. ///
  376. /// - Parameters:
  377. /// - request: `DownloadRequest` for which to publish the response.
  378. /// - queue: `DispatchQueue` on which the `DataResponse` value will be published. `.main` by default.
  379. /// - serializer: `DownloadResponseSerializerProtocol` used to produce the published `DownloadResponse`.
  380. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  381. public init<Serializer: DownloadResponseSerializerProtocol>(_ request: DownloadRequest,
  382. queue: DispatchQueue,
  383. serializer: Serializer)
  384. where Value == Serializer.SerializedObject
  385. {
  386. self.request = request
  387. responseHandler = { request.response(queue: queue, responseSerializer: serializer, completionHandler: $0) }
  388. }
  389. /// Publishes only the `Result` of the `DownloadResponse` value.
  390. ///
  391. /// - Returns: The `AnyPublisher` publishing the `Result<Value, AFError>` value.
  392. public func result() -> AnyPublisher<Result<Value, AFError>, Never> {
  393. map { $0.result }.eraseToAnyPublisher()
  394. }
  395. /// Publishes the `Result` of the `DownloadResponse` as a single `Value` or fail with the `AFError` instance.
  396. ///
  397. /// - Returns: The `AnyPublisher<Value, AFError>` publishing the stream.
  398. public func value() -> AnyPublisher<Value, AFError> {
  399. setFailureType(to: AFError.self).flatMap { $0.result.publisher }.eraseToAnyPublisher()
  400. }
  401. public func receive<S>(subscriber: S) where S: Subscriber, DownloadResponsePublisher.Failure == S.Failure, DownloadResponsePublisher.Output == S.Input {
  402. subscriber.receive(subscription: Inner(request: request,
  403. responseHandler: responseHandler,
  404. downstream: subscriber))
  405. }
  406. private final class Inner<Downstream: Subscriber>: Subscription, Cancellable
  407. where Downstream.Input == Output
  408. {
  409. typealias Failure = Downstream.Failure
  410. @Protected
  411. private var downstream: Downstream?
  412. private let request: DownloadRequest
  413. private let responseHandler: Handler
  414. init(request: DownloadRequest, responseHandler: @escaping Handler, downstream: Downstream) {
  415. self.request = request
  416. self.responseHandler = responseHandler
  417. self.downstream = downstream
  418. }
  419. func request(_ demand: Subscribers.Demand) {
  420. assert(demand > 0)
  421. guard let downstream = downstream else { return }
  422. self.downstream = nil
  423. responseHandler { response in
  424. _ = downstream.receive(response)
  425. downstream.receive(completion: .finished)
  426. }.resume()
  427. }
  428. func cancel() {
  429. request.cancel()
  430. downstream = nil
  431. }
  432. }
  433. }
  434. public extension DownloadRequest {
  435. /// Creates a `DownloadResponsePublisher` for this instance using the given `ResponseSerializer` and `DispatchQueue`.
  436. ///
  437. /// - Parameters:
  438. /// - serializer: `ResponseSerializer` used to serialize the response `Data` from disk.
  439. /// - queue: `DispatchQueue` on which the `DownloadResponse` will be published.`.main` by default.
  440. ///
  441. /// - Returns: The `DownloadResponsePublisher`.
  442. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  443. func publishResponse<Serializer: ResponseSerializer, T>(using serializer: Serializer, on queue: DispatchQueue = .main) -> DownloadResponsePublisher<T>
  444. where Serializer.SerializedObject == T
  445. {
  446. DownloadResponsePublisher(self, queue: queue, serializer: serializer)
  447. }
  448. /// Creates a `DownloadResponsePublisher` for this instance using the given `DownloadResponseSerializerProtocol` and
  449. /// `DispatchQueue`.
  450. ///
  451. /// - Parameters:
  452. /// - serializer: `DownloadResponseSerializer` used to serialize the response `Data` from disk.
  453. /// - queue: `DispatchQueue` on which the `DownloadResponse` will be published.`.main` by default.
  454. ///
  455. /// - Returns: The `DownloadResponsePublisher`.
  456. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  457. func publishResponse<Serializer: DownloadResponseSerializerProtocol, T>(using serializer: Serializer, on queue: DispatchQueue = .main) -> DownloadResponsePublisher<T>
  458. where Serializer.SerializedObject == T
  459. {
  460. DownloadResponsePublisher(self, queue: queue, serializer: serializer)
  461. }
  462. /// Creates a `DownloadResponsePublisher` for this instance and uses a `URLResponseSerializer` to serialize the
  463. /// response.
  464. ///
  465. /// - Parameter queue: `DispatchQueue` on which the `DownloadResponse` will be published. `.main` by default.
  466. ///
  467. /// - Returns: The `DownloadResponsePublisher`.
  468. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  469. func publishURL(queue: DispatchQueue = .main) -> DownloadResponsePublisher<URL> {
  470. publishResponse(using: URLResponseSerializer(), on: queue)
  471. }
  472. /// Creates a `DownloadResponsePublisher` for this instance and uses a `DataResponseSerializer` to serialize the
  473. /// response.
  474. ///
  475. /// - Parameters:
  476. /// - queue: `DispatchQueue` on which the `DownloadResponse` will be published. `.main` by default.
  477. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()`
  478. /// by default.
  479. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  480. /// default.
  481. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless of
  482. /// status code. `[.head]` by default.
  483. ///
  484. /// - Returns: The `DownloadResponsePublisher`.
  485. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  486. func publishData(queue: DispatchQueue = .main,
  487. preprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
  488. emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
  489. emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods) -> DownloadResponsePublisher<Data>
  490. {
  491. publishResponse(using: DataResponseSerializer(dataPreprocessor: preprocessor,
  492. emptyResponseCodes: emptyResponseCodes,
  493. emptyRequestMethods: emptyRequestMethods),
  494. on: queue)
  495. }
  496. /// Creates a `DataResponsePublisher` for this instance and uses a `StringResponseSerializer` to serialize the
  497. /// response.
  498. ///
  499. /// - Parameters:
  500. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  501. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()`
  502. /// by default.
  503. /// - encoding: `String.Encoding` to parse the response. `nil` by default, in which case the encoding
  504. /// will be determined by the server response, falling back to the default HTTP character
  505. /// set, `ISO-8859-1`.
  506. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  507. /// default.
  508. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless of
  509. /// status code. `[.head]` by default.
  510. ///
  511. /// - Returns: The `DownloadResponsePublisher`.
  512. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  513. func publishString(queue: DispatchQueue = .main,
  514. preprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
  515. encoding: String.Encoding? = nil,
  516. emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
  517. emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods) -> DownloadResponsePublisher<String>
  518. {
  519. publishResponse(using: StringResponseSerializer(dataPreprocessor: preprocessor,
  520. encoding: encoding,
  521. emptyResponseCodes: emptyResponseCodes,
  522. emptyRequestMethods: emptyRequestMethods),
  523. on: queue)
  524. }
  525. /// Creates a `DataResponsePublisher` for this instance and uses a `DecodableResponseSerializer` to serialize the
  526. /// response.
  527. ///
  528. /// - Parameters:
  529. /// - type: `Decodable` type to which to decode response `Data`. Inferred from the context by default.
  530. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  531. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()`
  532. /// by default.
  533. /// - decoder: `DataDecoder` instance used to decode response `Data`. `JSONDecoder()` by default.
  534. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  535. /// default.
  536. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless of
  537. /// status code. `[.head]` by default.
  538. ///
  539. /// - Returns: The `DownloadResponsePublisher`.
  540. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  541. func publishDecodable<T: Decodable>(type _: T.Type = T.self,
  542. queue: DispatchQueue = .main,
  543. preprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
  544. decoder: DataDecoder = JSONDecoder(),
  545. emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
  546. emptyResponseMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods) -> DownloadResponsePublisher<T>
  547. {
  548. publishResponse(using: DecodableResponseSerializer(dataPreprocessor: preprocessor,
  549. decoder: decoder,
  550. emptyResponseCodes: emptyResponseCodes,
  551. emptyRequestMethods: emptyResponseMethods),
  552. on: queue)
  553. }
  554. }
  555. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  556. public extension DownloadResponsePublisher where Value == URL? {
  557. /// Creates an instance which publishes a `DownloadResponse<URL?, AFError>` value without serialization.
  558. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  559. init(_ request: DownloadRequest, queue: DispatchQueue) {
  560. self.request = request
  561. responseHandler = { request.response(queue: queue, completionHandler: $0) }
  562. }
  563. }
  564. public extension DownloadRequest {
  565. /// Creates a `DownloadResponsePublisher` for this instance which does not serialize the response before publishing.
  566. ///
  567. /// - Parameter queue: `DispatchQueue` on which the `DownloadResponse` will be published. `.main` by default.
  568. ///
  569. /// - Returns: The `DownloadResponsePublisher`.
  570. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  571. func publishUnserialized(on queue: DispatchQueue = .main) -> DownloadResponsePublisher<URL?> {
  572. DownloadResponsePublisher(self, queue: queue)
  573. }
  574. }
  575. #endif