Combine.swift 36 KB

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