Combine.swift 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  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. 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(\.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(\.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
  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. @_disfavoredOverload
  178. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  179. @available(*, deprecated, message: "Renamed publishDecodable(type:queue:preprocessor:decoder:emptyResponseCodes:emptyRequestMethods).")
  180. public func publishDecodable<T: Decodable>(type: T.Type = T.self,
  181. queue: DispatchQueue = .main,
  182. preprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
  183. decoder: DataDecoder = JSONDecoder(),
  184. emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
  185. emptyResponseMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods) -> DataResponsePublisher<T> {
  186. publishResponse(using: DecodableResponseSerializer(dataPreprocessor: preprocessor,
  187. decoder: decoder,
  188. emptyResponseCodes: emptyResponseCodes,
  189. emptyRequestMethods: emptyResponseMethods),
  190. on: queue)
  191. }
  192. /// Creates a `DataResponsePublisher` for this instance and uses a `DecodableResponseSerializer` to serialize the
  193. /// response.
  194. ///
  195. /// - Parameters:
  196. /// - type: `Decodable` type to which to decode response `Data`. Inferred from the context by
  197. /// default.
  198. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  199. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization.
  200. /// `PassthroughPreprocessor()` by default.
  201. /// - decoder: `DataDecoder` instance used to decode response `Data`. `JSONDecoder()` by default.
  202. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  203. /// default.
  204. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless of
  205. /// status code. `[.head]` by default.
  206. ///
  207. /// - Returns: The `DataResponsePublisher`.
  208. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  209. public func publishDecodable<T: Decodable>(type: T.Type = T.self,
  210. queue: DispatchQueue = .main,
  211. preprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
  212. decoder: DataDecoder = JSONDecoder(),
  213. emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
  214. emptyRequestMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods) -> DataResponsePublisher<T> {
  215. publishResponse(using: DecodableResponseSerializer(dataPreprocessor: preprocessor,
  216. decoder: decoder,
  217. emptyResponseCodes: emptyResponseCodes,
  218. emptyRequestMethods: emptyRequestMethods),
  219. on: queue)
  220. }
  221. /// Creates a `DataResponsePublisher` for this instance which does not serialize the response before publishing.
  222. ///
  223. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  224. ///
  225. /// - Returns: The `DataResponsePublisher`.
  226. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  227. public func publishUnserialized(queue: DispatchQueue = .main) -> DataResponsePublisher<Data?> {
  228. DataResponsePublisher(self, queue: queue)
  229. }
  230. }
  231. // A Combine `Publisher` that publishes a sequence of `Stream<Value, AFError>` values received by the provided `DataStreamRequest`.
  232. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  233. public struct DataStreamPublisher<Value>: Publisher {
  234. public typealias Output = DataStreamRequest.Stream<Value, AFError>
  235. public typealias Failure = Never
  236. private typealias Handler = (@escaping DataStreamRequest.Handler<Value, AFError>) -> DataStreamRequest
  237. private let request: DataStreamRequest
  238. private let streamHandler: Handler
  239. /// Creates an instance which will serialize responses using the provided `DataStreamSerializer`.
  240. ///
  241. /// - Parameters:
  242. /// - request: `DataStreamRequest` for which to publish the response.
  243. /// - queue: `DispatchQueue` on which the `Stream<Value, AFError>` values will be published. `.main` by
  244. /// default.
  245. /// - serializer: `DataStreamSerializer` used to produce the published `Stream<Value, AFError>` values.
  246. public init<Serializer: DataStreamSerializer>(_ request: DataStreamRequest, queue: DispatchQueue, serializer: Serializer)
  247. where Value == Serializer.SerializedObject {
  248. self.request = request
  249. streamHandler = { request.responseStream(using: serializer, on: queue, stream: $0) }
  250. }
  251. /// Publishes only the `Result` of the `DataStreamRequest.Stream`'s `Event`s.
  252. ///
  253. /// - Returns: The `AnyPublisher` publishing the `Result<Value, AFError>` value.
  254. public func result() -> AnyPublisher<Result<Value, AFError>, Never> {
  255. compactMap { stream in
  256. switch stream.event {
  257. case let .stream(result):
  258. return result
  259. // If the stream has completed with an error, send the error value downstream as a `.failure`.
  260. case let .complete(completion):
  261. return completion.error.map(Result.failure)
  262. }
  263. }
  264. .eraseToAnyPublisher()
  265. }
  266. /// Publishes the streamed values of the `DataStreamRequest.Stream` as a sequence of `Value` or fail with the
  267. /// `AFError` instance.
  268. ///
  269. /// - Returns: The `AnyPublisher<Value, AFError>` publishing the stream.
  270. public func value() -> AnyPublisher<Value, AFError> {
  271. result().setFailureType(to: AFError.self).flatMap(\.publisher).eraseToAnyPublisher()
  272. }
  273. public func receive<S>(subscriber: S) where S: Subscriber, DataStreamPublisher.Failure == S.Failure, DataStreamPublisher.Output == S.Input {
  274. subscriber.receive(subscription: Inner(request: request,
  275. streamHandler: streamHandler,
  276. downstream: subscriber))
  277. }
  278. private final class Inner<Downstream: Subscriber>: Subscription
  279. where Downstream.Input == Output {
  280. typealias Failure = Downstream.Failure
  281. @Protected
  282. private var downstream: Downstream?
  283. private let request: DataStreamRequest
  284. private let streamHandler: Handler
  285. init(request: DataStreamRequest, streamHandler: @escaping Handler, downstream: Downstream) {
  286. self.request = request
  287. self.streamHandler = streamHandler
  288. self.downstream = downstream
  289. }
  290. func request(_ demand: Subscribers.Demand) {
  291. assert(demand > 0)
  292. guard let downstream = downstream else { return }
  293. self.downstream = nil
  294. streamHandler { stream in
  295. _ = downstream.receive(stream)
  296. if case .complete = stream.event {
  297. downstream.receive(completion: .finished)
  298. }
  299. }.resume()
  300. }
  301. func cancel() {
  302. request.cancel()
  303. downstream = nil
  304. }
  305. }
  306. }
  307. extension DataStreamRequest {
  308. /// Creates a `DataStreamPublisher` for this instance using the given `DataStreamSerializer` and `DispatchQueue`.
  309. ///
  310. /// - Parameters:
  311. /// - serializer: `DataStreamSerializer` used to serialize the streamed `Data`.
  312. /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default.
  313. /// - Returns: The `DataStreamPublisher`.
  314. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  315. public func publishStream<Serializer: DataStreamSerializer>(using serializer: Serializer,
  316. on queue: DispatchQueue = .main) -> DataStreamPublisher<Serializer.SerializedObject> {
  317. DataStreamPublisher(self, queue: queue, serializer: serializer)
  318. }
  319. /// Creates a `DataStreamPublisher` for this instance which uses a `PassthroughStreamSerializer` to stream `Data`
  320. /// unserialized.
  321. ///
  322. /// - Parameters:
  323. /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default.
  324. /// - Returns: The `DataStreamPublisher`.
  325. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  326. public func publishData(queue: DispatchQueue = .main) -> DataStreamPublisher<Data> {
  327. publishStream(using: PassthroughStreamSerializer(), on: queue)
  328. }
  329. /// Creates a `DataStreamPublisher` for this instance which uses a `StringStreamSerializer` to serialize stream
  330. /// `Data` values into `String` values.
  331. ///
  332. /// - Parameters:
  333. /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default.
  334. /// - Returns: The `DataStreamPublisher`.
  335. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  336. public func publishString(queue: DispatchQueue = .main) -> DataStreamPublisher<String> {
  337. publishStream(using: StringStreamSerializer(), on: queue)
  338. }
  339. /// Creates a `DataStreamPublisher` for this instance which uses a `DecodableStreamSerializer` with the provided
  340. /// parameters to serialize stream `Data` values into the provided type.
  341. ///
  342. /// - Parameters:
  343. /// - type: `Decodable` type to which to decode stream `Data`. Inferred from the context by default.
  344. /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default.
  345. /// - decoder: `DataDecoder` instance used to decode stream `Data`. `JSONDecoder()` by default.
  346. /// - preprocessor: `DataPreprocessor` which filters incoming stream `Data` before serialization.
  347. /// `PassthroughPreprocessor()` by default.
  348. /// - Returns: The `DataStreamPublisher`.
  349. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  350. public func publishDecodable<T: Decodable>(type: T.Type = T.self,
  351. queue: DispatchQueue = .main,
  352. decoder: DataDecoder = JSONDecoder(),
  353. preprocessor: DataPreprocessor = PassthroughPreprocessor()) -> DataStreamPublisher<T> {
  354. publishStream(using: DecodableStreamSerializer(decoder: decoder,
  355. dataPreprocessor: preprocessor),
  356. on: queue)
  357. }
  358. }
  359. /// A Combine `Publisher` that publishes the `DownloadResponse<Value, AFError>` of the provided `DownloadRequest`.
  360. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  361. public struct DownloadResponsePublisher<Value>: Publisher {
  362. public typealias Output = DownloadResponse<Value, AFError>
  363. public typealias Failure = Never
  364. private typealias Handler = (@escaping (_ response: DownloadResponse<Value, AFError>) -> Void) -> DownloadRequest
  365. private let request: DownloadRequest
  366. private let responseHandler: Handler
  367. /// Creates an instance which will serialize responses using the provided `ResponseSerializer`.
  368. ///
  369. /// - Parameters:
  370. /// - request: `DownloadRequest` for which to publish the response.
  371. /// - queue: `DispatchQueue` on which the `DownloadResponse` value will be published. `.main` by default.
  372. /// - serializer: `ResponseSerializer` used to produce the published `DownloadResponse`.
  373. public init<Serializer: ResponseSerializer>(_ request: DownloadRequest, queue: DispatchQueue, serializer: Serializer)
  374. where Value == Serializer.SerializedObject {
  375. self.request = request
  376. responseHandler = { request.response(queue: queue, responseSerializer: serializer, completionHandler: $0) }
  377. }
  378. /// Creates an instance which will serialize responses using the provided `DownloadResponseSerializerProtocol` value.
  379. ///
  380. /// - Parameters:
  381. /// - request: `DownloadRequest` for which to publish the response.
  382. /// - queue: `DispatchQueue` on which the `DataResponse` value will be published. `.main` by default.
  383. /// - serializer: `DownloadResponseSerializerProtocol` used to produce the published `DownloadResponse`.
  384. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  385. public init<Serializer: DownloadResponseSerializerProtocol>(_ request: DownloadRequest,
  386. queue: DispatchQueue,
  387. serializer: Serializer)
  388. where Value == Serializer.SerializedObject {
  389. self.request = request
  390. responseHandler = { request.response(queue: queue, responseSerializer: serializer, completionHandler: $0) }
  391. }
  392. /// Publishes only the `Result` of the `DownloadResponse` value.
  393. ///
  394. /// - Returns: The `AnyPublisher` publishing the `Result<Value, AFError>` value.
  395. public func result() -> AnyPublisher<Result<Value, AFError>, Never> {
  396. map(\.result).eraseToAnyPublisher()
  397. }
  398. /// Publishes the `Result` of the `DownloadResponse` as a single `Value` or fail with the `AFError` instance.
  399. ///
  400. /// - Returns: The `AnyPublisher<Value, AFError>` publishing the stream.
  401. public func value() -> AnyPublisher<Value, AFError> {
  402. setFailureType(to: AFError.self).flatMap(\.result.publisher).eraseToAnyPublisher()
  403. }
  404. public func receive<S>(subscriber: S) where S: Subscriber, DownloadResponsePublisher.Failure == S.Failure, DownloadResponsePublisher.Output == S.Input {
  405. subscriber.receive(subscription: Inner(request: request,
  406. responseHandler: responseHandler,
  407. downstream: subscriber))
  408. }
  409. private final class Inner<Downstream: Subscriber>: Subscription
  410. where Downstream.Input == Output {
  411. typealias Failure = Downstream.Failure
  412. @Protected
  413. private var downstream: Downstream?
  414. private let request: DownloadRequest
  415. private let responseHandler: Handler
  416. init(request: DownloadRequest, responseHandler: @escaping Handler, downstream: Downstream) {
  417. self.request = request
  418. self.responseHandler = responseHandler
  419. self.downstream = downstream
  420. }
  421. func request(_ demand: Subscribers.Demand) {
  422. assert(demand > 0)
  423. guard let downstream = downstream else { return }
  424. self.downstream = nil
  425. responseHandler { response in
  426. _ = downstream.receive(response)
  427. downstream.receive(completion: .finished)
  428. }.resume()
  429. }
  430. func cancel() {
  431. request.cancel()
  432. downstream = nil
  433. }
  434. }
  435. }
  436. extension DownloadRequest {
  437. /// Creates a `DownloadResponsePublisher` for this instance using the given `ResponseSerializer` and `DispatchQueue`.
  438. ///
  439. /// - Parameters:
  440. /// - serializer: `ResponseSerializer` used to serialize the response `Data` from disk.
  441. /// - queue: `DispatchQueue` on which the `DownloadResponse` will be published.`.main` by default.
  442. ///
  443. /// - Returns: The `DownloadResponsePublisher`.
  444. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  445. public func publishResponse<Serializer: ResponseSerializer, T>(using serializer: Serializer, on queue: DispatchQueue = .main) -> DownloadResponsePublisher<T>
  446. where Serializer.SerializedObject == T {
  447. DownloadResponsePublisher(self, queue: queue, serializer: serializer)
  448. }
  449. /// Creates a `DownloadResponsePublisher` for this instance using the given `DownloadResponseSerializerProtocol` and
  450. /// `DispatchQueue`.
  451. ///
  452. /// - Parameters:
  453. /// - serializer: `DownloadResponseSerializer` used to serialize the response `Data` from disk.
  454. /// - queue: `DispatchQueue` on which the `DownloadResponse` will be published.`.main` by default.
  455. ///
  456. /// - Returns: The `DownloadResponsePublisher`.
  457. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  458. public func publishResponse<Serializer: DownloadResponseSerializerProtocol, T>(using serializer: Serializer, on queue: DispatchQueue = .main) -> DownloadResponsePublisher<T>
  459. where Serializer.SerializedObject == T {
  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. public 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. public 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. publishResponse(using: DataResponseSerializer(dataPreprocessor: preprocessor,
  491. emptyResponseCodes: emptyResponseCodes,
  492. emptyRequestMethods: emptyRequestMethods),
  493. on: queue)
  494. }
  495. /// Creates a `DownloadResponsePublisher` for this instance and uses a `StringResponseSerializer` to serialize the
  496. /// response.
  497. ///
  498. /// - Parameters:
  499. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  500. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()`
  501. /// by default.
  502. /// - encoding: `String.Encoding` to parse the response. `nil` by default, in which case the encoding
  503. /// will be determined by the server response, falling back to the default HTTP character
  504. /// set, `ISO-8859-1`.
  505. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  506. /// default.
  507. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless of
  508. /// status code. `[.head]` by default.
  509. ///
  510. /// - Returns: The `DownloadResponsePublisher`.
  511. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  512. public func publishString(queue: DispatchQueue = .main,
  513. preprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
  514. encoding: String.Encoding? = nil,
  515. emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
  516. emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods) -> DownloadResponsePublisher<String> {
  517. publishResponse(using: StringResponseSerializer(dataPreprocessor: preprocessor,
  518. encoding: encoding,
  519. emptyResponseCodes: emptyResponseCodes,
  520. emptyRequestMethods: emptyRequestMethods),
  521. on: queue)
  522. }
  523. @_disfavoredOverload
  524. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  525. @available(*, deprecated, message: "Renamed publishDecodable(type:queue:preprocessor:decoder:emptyResponseCodes:emptyRequestMethods).")
  526. public func publishDecodable<T: Decodable>(type: T.Type = T.self,
  527. queue: DispatchQueue = .main,
  528. preprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
  529. decoder: DataDecoder = JSONDecoder(),
  530. emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
  531. emptyResponseMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods) -> DownloadResponsePublisher<T> {
  532. publishResponse(using: DecodableResponseSerializer(dataPreprocessor: preprocessor,
  533. decoder: decoder,
  534. emptyResponseCodes: emptyResponseCodes,
  535. emptyRequestMethods: emptyResponseMethods),
  536. on: queue)
  537. }
  538. /// Creates a `DownloadResponsePublisher` for this instance and uses a `DecodableResponseSerializer` to serialize
  539. /// the response.
  540. ///
  541. /// - Parameters:
  542. /// - type: `Decodable` type to which to decode response `Data`. Inferred from the context by default.
  543. /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default.
  544. /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization.
  545. /// `PassthroughPreprocessor()` by default.
  546. /// - decoder: `DataDecoder` instance used to decode response `Data`. `JSONDecoder()` by default.
  547. /// - emptyResponseCodes: `Set<Int>` of HTTP status codes for which empty responses are allowed. `[204, 205]` by
  548. /// default.
  549. /// - emptyRequestMethods: `Set<HTTPMethod>` of `HTTPMethod`s for which empty responses are allowed, regardless
  550. /// of status code. `[.head]` by default.
  551. ///
  552. /// - Returns: The `DownloadResponsePublisher`.
  553. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  554. public func publishDecodable<T: Decodable>(type: T.Type = T.self,
  555. queue: DispatchQueue = .main,
  556. preprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
  557. decoder: DataDecoder = JSONDecoder(),
  558. emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
  559. emptyRequestMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods) -> DownloadResponsePublisher<T> {
  560. publishResponse(using: DecodableResponseSerializer(dataPreprocessor: preprocessor,
  561. decoder: decoder,
  562. emptyResponseCodes: emptyResponseCodes,
  563. emptyRequestMethods: emptyRequestMethods),
  564. on: queue)
  565. }
  566. }
  567. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  568. extension DownloadResponsePublisher where Value == URL? {
  569. /// Creates an instance which publishes a `DownloadResponse<URL?, AFError>` value without serialization.
  570. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  571. public init(_ request: DownloadRequest, queue: DispatchQueue) {
  572. self.request = request
  573. responseHandler = { request.response(queue: queue, completionHandler: $0) }
  574. }
  575. }
  576. extension DownloadRequest {
  577. /// Creates a `DownloadResponsePublisher` for this instance which does not serialize the response before publishing.
  578. ///
  579. /// - Parameter queue: `DispatchQueue` on which the `DownloadResponse` will be published. `.main` by default.
  580. ///
  581. /// - Returns: The `DownloadResponsePublisher`.
  582. @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
  583. public func publishUnserialized(on queue: DispatchQueue = .main) -> DownloadResponsePublisher<URL?> {
  584. DownloadResponsePublisher(self, queue: queue)
  585. }
  586. }
  587. #endif