Concurrency.swift 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. //
  2. // Concurrency.swift
  3. //
  4. // Copyright (c) 2021 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 compiler(>=5.5.2) && canImport(_Concurrency)
  25. #if SWIFT_PACKAGE
  26. import Alamofire
  27. #endif
  28. import Foundation
  29. // MARK: - Request Event Streams
  30. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  31. extension Request {
  32. /// Creates a `StreamOf<Progress>` for the instance's upload progress.
  33. ///
  34. /// - Parameter bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default.
  35. ///
  36. /// - Returns: The `StreamOf<Progress>`.
  37. public func uploadProgress(bufferingPolicy: StreamOf<Progress>.BufferingPolicy = .unbounded) -> StreamOf<Progress> {
  38. stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in
  39. uploadProgress(queue: .singleEventQueue) { progress in
  40. continuation.yield(progress)
  41. }
  42. }
  43. }
  44. /// Creates a `StreamOf<Progress>` for the instance's download progress.
  45. ///
  46. /// - Parameter bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default.
  47. ///
  48. /// - Returns: The `StreamOf<Progress>`.
  49. public func downloadProgress(bufferingPolicy: StreamOf<Progress>.BufferingPolicy = .unbounded) -> StreamOf<Progress> {
  50. stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in
  51. downloadProgress(queue: .singleEventQueue) { progress in
  52. continuation.yield(progress)
  53. }
  54. }
  55. }
  56. /// Creates a `StreamOf<URLRequest>` for the `URLRequest`s produced for the instance.
  57. ///
  58. /// - Parameter bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default.
  59. ///
  60. /// - Returns: The `StreamOf<URLRequest>`.
  61. public func urlRequests(bufferingPolicy: StreamOf<URLRequest>.BufferingPolicy = .unbounded) -> StreamOf<URLRequest> {
  62. stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in
  63. onURLRequestCreation(on: .singleEventQueue) { request in
  64. continuation.yield(request)
  65. }
  66. }
  67. }
  68. /// Creates a `StreamOf<URLSessionTask>` for the `URLSessionTask`s produced for the instance.
  69. ///
  70. /// - Parameter bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default.
  71. ///
  72. /// - Returns: The `StreamOf<URLSessionTask>`.
  73. public func urlSessionTasks(bufferingPolicy: StreamOf<URLSessionTask>.BufferingPolicy = .unbounded) -> StreamOf<URLSessionTask> {
  74. stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in
  75. onURLSessionTaskCreation(on: .singleEventQueue) { task in
  76. continuation.yield(task)
  77. }
  78. }
  79. }
  80. /// Creates a `StreamOf<String>` for the cURL descriptions produced for the instance.
  81. ///
  82. /// - Parameter bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default.
  83. ///
  84. /// - Returns: The `StreamOf<String>`.
  85. public func cURLDescriptions(bufferingPolicy: StreamOf<String>.BufferingPolicy = .unbounded) -> StreamOf<String> {
  86. stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in
  87. cURLDescription(on: .singleEventQueue) { description in
  88. continuation.yield(description)
  89. }
  90. }
  91. }
  92. private func stream<T>(of type: T.Type = T.self,
  93. bufferingPolicy: StreamOf<T>.BufferingPolicy = .unbounded,
  94. yielder: @escaping (StreamOf<T>.Continuation) -> Void) -> StreamOf<T> {
  95. StreamOf<T>(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in
  96. yielder(continuation)
  97. // Must come after serializers run in order to catch retry progress.
  98. _onFinish {
  99. continuation.finish()
  100. }
  101. }
  102. }
  103. }
  104. // MARK: - DataTask
  105. /// Value used to `await` a `DataResponse` and associated values.
  106. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  107. public struct DataTask<Value> {
  108. /// `DataResponse` produced by the `DataRequest` and its response handler.
  109. public var response: DataResponse<Value, AFError> {
  110. get async {
  111. if shouldAutomaticallyCancel {
  112. return await withTaskCancellationHandler {
  113. self.cancel()
  114. } operation: {
  115. await task.value
  116. }
  117. } else {
  118. return await task.value
  119. }
  120. }
  121. }
  122. /// `Result` of any response serialization performed for the `response`.
  123. public var result: Result<Value, AFError> {
  124. get async { await response.result }
  125. }
  126. /// `Value` returned by the `response`.
  127. public var value: Value {
  128. get async throws {
  129. try await result.get()
  130. }
  131. }
  132. private let request: DataRequest
  133. private let task: Task<DataResponse<Value, AFError>, Never>
  134. private let shouldAutomaticallyCancel: Bool
  135. fileprivate init(request: DataRequest, task: Task<DataResponse<Value, AFError>, Never>, shouldAutomaticallyCancel: Bool) {
  136. self.request = request
  137. self.task = task
  138. self.shouldAutomaticallyCancel = shouldAutomaticallyCancel
  139. }
  140. /// Cancel the underlying `DataRequest` and `Task`.
  141. public func cancel() {
  142. task.cancel()
  143. }
  144. /// Resume the underlying `DataRequest`.
  145. public func resume() {
  146. request.resume()
  147. }
  148. /// Suspend the underlying `DataRequest`.
  149. public func suspend() {
  150. request.suspend()
  151. }
  152. }
  153. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  154. extension DataRequest {
  155. /// Creates a `DataTask` to `await` a `Data` value.
  156. ///
  157. /// - Parameters:
  158. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
  159. /// enclosing async context is cancelled. Only applies to `DataTask`'s async
  160. /// properties. `false` by default.
  161. /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before completion.
  162. /// - emptyResponseCodes: HTTP response codes for which empty responses are allowed. `[204, 205]` by default.
  163. /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default.
  164. ///
  165. /// - Returns: The `DataTask`.
  166. public func serializingData(automaticallyCancelling shouldAutomaticallyCancel: Bool = false,
  167. dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
  168. emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
  169. emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods) -> DataTask<Data> {
  170. serializingResponse(using: DataResponseSerializer(dataPreprocessor: dataPreprocessor,
  171. emptyResponseCodes: emptyResponseCodes,
  172. emptyRequestMethods: emptyRequestMethods),
  173. automaticallyCancelling: shouldAutomaticallyCancel)
  174. }
  175. /// Creates a `DataTask` to `await` serialization of a `Decodable` value.
  176. ///
  177. /// - Parameters:
  178. /// - type: `Decodable` type to decode from response data.
  179. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
  180. /// enclosing async context is cancelled. Only applies to `DataTask`'s async
  181. /// properties. `false` by default.
  182. /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the serializer.
  183. /// `PassthroughPreprocessor()` by default.
  184. /// - decoder: `DataDecoder` to use to decode the response. `JSONDecoder()` by default.
  185. /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default.
  186. /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default.
  187. ///
  188. /// - Returns: The `DataTask`.
  189. public func serializingDecodable<Value: Decodable>(_ type: Value.Type = Value.self,
  190. automaticallyCancelling shouldAutomaticallyCancel: Bool = false,
  191. dataPreprocessor: DataPreprocessor = DecodableResponseSerializer<Value>.defaultDataPreprocessor,
  192. decoder: DataDecoder = JSONDecoder(),
  193. emptyResponseCodes: Set<Int> = DecodableResponseSerializer<Value>.defaultEmptyResponseCodes,
  194. emptyRequestMethods: Set<HTTPMethod> = DecodableResponseSerializer<Value>.defaultEmptyRequestMethods) -> DataTask<Value> {
  195. serializingResponse(using: DecodableResponseSerializer<Value>(dataPreprocessor: dataPreprocessor,
  196. decoder: decoder,
  197. emptyResponseCodes: emptyResponseCodes,
  198. emptyRequestMethods: emptyRequestMethods),
  199. automaticallyCancelling: shouldAutomaticallyCancel)
  200. }
  201. /// Creates a `DataTask` to `await` serialization of a `String` value.
  202. ///
  203. /// - Parameters:
  204. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
  205. /// enclosing async context is cancelled. Only applies to `DataTask`'s async
  206. /// properties. `false` by default.
  207. /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the serializer.
  208. /// `PassthroughPreprocessor()` by default.
  209. /// - encoding: `String.Encoding` to use during serialization. Defaults to `nil`, in which case
  210. /// the encoding will be determined from the server response, falling back to the
  211. /// default HTTP character set, `ISO-8859-1`.
  212. /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default.
  213. /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default.
  214. ///
  215. /// - Returns: The `DataTask`.
  216. public func serializingString(automaticallyCancelling shouldAutomaticallyCancel: Bool = false,
  217. dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
  218. encoding: String.Encoding? = nil,
  219. emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
  220. emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods) -> DataTask<String> {
  221. serializingResponse(using: StringResponseSerializer(dataPreprocessor: dataPreprocessor,
  222. encoding: encoding,
  223. emptyResponseCodes: emptyResponseCodes,
  224. emptyRequestMethods: emptyRequestMethods),
  225. automaticallyCancelling: shouldAutomaticallyCancel)
  226. }
  227. /// Creates a `DataTask` to `await` serialization using the provided `ResponseSerializer` instance.
  228. ///
  229. /// - Parameters:
  230. /// - serializer: `ResponseSerializer` responsible for serializing the request, response, and data.
  231. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
  232. /// enclosing async context is cancelled. Only applies to `DataTask`'s async
  233. /// properties. `false` by default.
  234. ///
  235. /// - Returns: The `DataTask`.
  236. public func serializingResponse<Serializer: ResponseSerializer>(using serializer: Serializer,
  237. automaticallyCancelling shouldAutomaticallyCancel: Bool = false)
  238. -> DataTask<Serializer.SerializedObject> {
  239. dataTask(automaticallyCancelling: shouldAutomaticallyCancel) {
  240. self.response(queue: .singleEventQueue,
  241. responseSerializer: serializer,
  242. completionHandler: $0)
  243. }
  244. }
  245. /// Creates a `DataTask` to `await` serialization using the provided `DataResponseSerializerProtocol` instance.
  246. ///
  247. /// - Parameters:
  248. /// - serializer: `DataResponseSerializerProtocol` responsible for serializing the request,
  249. /// response, and data.
  250. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
  251. /// enclosing async context is cancelled. Only applies to `DataTask`'s async
  252. /// properties. `false` by default.
  253. ///
  254. /// - Returns: The `DataTask`.
  255. public func serializingResponse<Serializer: DataResponseSerializerProtocol>(using serializer: Serializer,
  256. automaticallyCancelling shouldAutomaticallyCancel: Bool = false)
  257. -> DataTask<Serializer.SerializedObject> {
  258. dataTask(automaticallyCancelling: shouldAutomaticallyCancel) {
  259. self.response(queue: .singleEventQueue,
  260. responseSerializer: serializer,
  261. completionHandler: $0)
  262. }
  263. }
  264. private func dataTask<Value>(automaticallyCancelling shouldAutomaticallyCancel: Bool,
  265. forResponse onResponse: @escaping (@escaping (DataResponse<Value, AFError>) -> Void) -> Void)
  266. -> DataTask<Value> {
  267. let task = Task {
  268. await withTaskCancellationHandler {
  269. self.cancel()
  270. } operation: {
  271. await withCheckedContinuation { continuation in
  272. onResponse {
  273. continuation.resume(returning: $0)
  274. }
  275. }
  276. }
  277. }
  278. return DataTask<Value>(request: self, task: task, shouldAutomaticallyCancel: shouldAutomaticallyCancel)
  279. }
  280. }
  281. // MARK: - DownloadTask
  282. /// Value used to `await` a `DownloadResponse` and associated values.
  283. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  284. public struct DownloadTask<Value> {
  285. /// `DownloadResponse` produced by the `DownloadRequest` and its response handler.
  286. public var response: DownloadResponse<Value, AFError> {
  287. get async {
  288. if shouldAutomaticallyCancel {
  289. return await withTaskCancellationHandler {
  290. self.cancel()
  291. } operation: {
  292. await task.value
  293. }
  294. } else {
  295. return await task.value
  296. }
  297. }
  298. }
  299. /// `Result` of any response serialization performed for the `response`.
  300. public var result: Result<Value, AFError> {
  301. get async { await response.result }
  302. }
  303. /// `Value` returned by the `response`.
  304. public var value: Value {
  305. get async throws {
  306. try await result.get()
  307. }
  308. }
  309. private let task: Task<AFDownloadResponse<Value>, Never>
  310. private let request: DownloadRequest
  311. private let shouldAutomaticallyCancel: Bool
  312. fileprivate init(request: DownloadRequest, task: Task<AFDownloadResponse<Value>, Never>, shouldAutomaticallyCancel: Bool) {
  313. self.request = request
  314. self.task = task
  315. self.shouldAutomaticallyCancel = shouldAutomaticallyCancel
  316. }
  317. /// Cancel the underlying `DownloadRequest` and `Task`.
  318. public func cancel() {
  319. task.cancel()
  320. }
  321. /// Resume the underlying `DownloadRequest`.
  322. public func resume() {
  323. request.resume()
  324. }
  325. /// Suspend the underlying `DownloadRequest`.
  326. public func suspend() {
  327. request.suspend()
  328. }
  329. }
  330. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  331. extension DownloadRequest {
  332. /// Creates a `DownloadTask` to `await` a `Data` value.
  333. ///
  334. /// - Parameters:
  335. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
  336. /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async
  337. /// properties. `false` by default.
  338. /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before completion.
  339. /// - emptyResponseCodes: HTTP response codes for which empty responses are allowed. `[204, 205]` by default.
  340. /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default.
  341. ///
  342. /// - Returns: The `DownloadTask`.
  343. public func serializingData(automaticallyCancelling shouldAutomaticallyCancel: Bool = false,
  344. dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
  345. emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
  346. emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods) -> DownloadTask<Data> {
  347. serializingDownload(using: DataResponseSerializer(dataPreprocessor: dataPreprocessor,
  348. emptyResponseCodes: emptyResponseCodes,
  349. emptyRequestMethods: emptyRequestMethods),
  350. automaticallyCancelling: shouldAutomaticallyCancel)
  351. }
  352. /// Creates a `DownloadTask` to `await` serialization of a `Decodable` value.
  353. ///
  354. /// - Note: This serializer reads the entire response into memory before parsing.
  355. ///
  356. /// - Parameters:
  357. /// - type: `Decodable` type to decode from response data.
  358. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
  359. /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async
  360. /// properties. `false` by default.
  361. /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the serializer.
  362. /// `PassthroughPreprocessor()` by default.
  363. /// - decoder: `DataDecoder` to use to decode the response. `JSONDecoder()` by default.
  364. /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default.
  365. /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default.
  366. ///
  367. /// - Returns: The `DownloadTask`.
  368. public func serializingDecodable<Value: Decodable>(_ type: Value.Type = Value.self,
  369. automaticallyCancelling shouldAutomaticallyCancel: Bool = false,
  370. dataPreprocessor: DataPreprocessor = DecodableResponseSerializer<Value>.defaultDataPreprocessor,
  371. decoder: DataDecoder = JSONDecoder(),
  372. emptyResponseCodes: Set<Int> = DecodableResponseSerializer<Value>.defaultEmptyResponseCodes,
  373. emptyRequestMethods: Set<HTTPMethod> = DecodableResponseSerializer<Value>.defaultEmptyRequestMethods) -> DownloadTask<Value> {
  374. serializingDownload(using: DecodableResponseSerializer<Value>(dataPreprocessor: dataPreprocessor,
  375. decoder: decoder,
  376. emptyResponseCodes: emptyResponseCodes,
  377. emptyRequestMethods: emptyRequestMethods),
  378. automaticallyCancelling: shouldAutomaticallyCancel)
  379. }
  380. /// Creates a `DownloadTask` to `await` serialization of the downloaded file's `URL` on disk.
  381. ///
  382. /// - Returns: The `DownloadTask`.
  383. public func serializingDownloadedFileURL() -> DownloadTask<URL> {
  384. serializingDownload(using: URLResponseSerializer())
  385. }
  386. /// Creates a `DownloadTask` to `await` serialization of a `String` value.
  387. ///
  388. /// - Parameters:
  389. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
  390. /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async
  391. /// properties. `false` by default.
  392. /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the
  393. /// serializer. `PassthroughPreprocessor()` by default.
  394. /// - encoding: `String.Encoding` to use during serialization. Defaults to `nil`, in which case
  395. /// the encoding will be determined from the server response, falling back to the
  396. /// default HTTP character set, `ISO-8859-1`.
  397. /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default.
  398. /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default.
  399. ///
  400. /// - Returns: The `DownloadTask`.
  401. public func serializingString(automaticallyCancelling shouldAutomaticallyCancel: Bool = false,
  402. dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
  403. encoding: String.Encoding? = nil,
  404. emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
  405. emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods) -> DownloadTask<String> {
  406. serializingDownload(using: StringResponseSerializer(dataPreprocessor: dataPreprocessor,
  407. encoding: encoding,
  408. emptyResponseCodes: emptyResponseCodes,
  409. emptyRequestMethods: emptyRequestMethods),
  410. automaticallyCancelling: shouldAutomaticallyCancel)
  411. }
  412. /// Creates a `DownloadTask` to `await` serialization using the provided `ResponseSerializer` instance.
  413. ///
  414. /// - Parameters:
  415. /// - serializer: `ResponseSerializer` responsible for serializing the request, response, and data.
  416. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
  417. /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async
  418. /// properties. `false` by default.
  419. ///
  420. /// - Returns: The `DownloadTask`.
  421. public func serializingDownload<Serializer: ResponseSerializer>(using serializer: Serializer,
  422. automaticallyCancelling shouldAutomaticallyCancel: Bool = false)
  423. -> DownloadTask<Serializer.SerializedObject> {
  424. downloadTask(automaticallyCancelling: shouldAutomaticallyCancel) {
  425. self.response(queue: .singleEventQueue,
  426. responseSerializer: serializer,
  427. completionHandler: $0)
  428. }
  429. }
  430. /// Creates a `DownloadTask` to `await` serialization using the provided `DownloadResponseSerializerProtocol`
  431. /// instance.
  432. ///
  433. /// - Parameters:
  434. /// - serializer: `DownloadResponseSerializerProtocol` responsible for serializing the request,
  435. /// response, and data.
  436. /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
  437. /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async
  438. /// properties. `false` by default.
  439. ///
  440. /// - Returns: The `DownloadTask`.
  441. public func serializingDownload<Serializer: DownloadResponseSerializerProtocol>(using serializer: Serializer,
  442. automaticallyCancelling shouldAutomaticallyCancel: Bool = false)
  443. -> DownloadTask<Serializer.SerializedObject> {
  444. downloadTask(automaticallyCancelling: shouldAutomaticallyCancel) {
  445. self.response(queue: .singleEventQueue,
  446. responseSerializer: serializer,
  447. completionHandler: $0)
  448. }
  449. }
  450. private func downloadTask<Value>(automaticallyCancelling shouldAutomaticallyCancel: Bool,
  451. forResponse onResponse: @escaping (@escaping (DownloadResponse<Value, AFError>) -> Void) -> Void)
  452. -> DownloadTask<Value> {
  453. let task = Task {
  454. await withTaskCancellationHandler {
  455. self.cancel()
  456. } operation: {
  457. await withCheckedContinuation { continuation in
  458. onResponse {
  459. continuation.resume(returning: $0)
  460. }
  461. }
  462. }
  463. }
  464. return DownloadTask<Value>(request: self, task: task, shouldAutomaticallyCancel: shouldAutomaticallyCancel)
  465. }
  466. }
  467. // MARK: - DataStreamTask
  468. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  469. public struct DataStreamTask {
  470. // Type of created streams.
  471. public typealias Stream<Success, Failure: Error> = StreamOf<DataStreamRequest.Stream<Success, Failure>>
  472. private let request: DataStreamRequest
  473. fileprivate init(request: DataStreamRequest) {
  474. self.request = request
  475. }
  476. /// Creates a `Stream` of `Data` values from the underlying `DataStreamRequest`.
  477. ///
  478. /// - Parameters:
  479. /// - shouldAutomaticallyCancel: `Bool` indicating whether the underlying `DataStreamRequest` should be canceled
  480. /// which observation of the stream stops. `true` by default.
  481. /// - bufferingPolicy: ` BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default.
  482. ///
  483. /// - Returns: The `Stream`.
  484. public func streamingData(automaticallyCancelling shouldAutomaticallyCancel: Bool = true, bufferingPolicy: Stream<Data, Never>.BufferingPolicy = .unbounded) -> Stream<Data, Never> {
  485. createStream(automaticallyCancelling: shouldAutomaticallyCancel, bufferingPolicy: bufferingPolicy) { onStream in
  486. self.request.responseStream(on: .streamCompletionQueue(forRequestID: request.id), stream: onStream)
  487. }
  488. }
  489. /// Creates a `Stream` of `UTF-8` `String`s from the underlying `DataStreamRequest`.
  490. ///
  491. /// - Parameters:
  492. /// - shouldAutomaticallyCancel: `Bool` indicating whether the underlying `DataStreamRequest` should be canceled
  493. /// which observation of the stream stops. `true` by default.
  494. /// - bufferingPolicy: ` BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default.
  495. /// - Returns:
  496. public func streamingStrings(automaticallyCancelling shouldAutomaticallyCancel: Bool = true, bufferingPolicy: Stream<String, Never>.BufferingPolicy = .unbounded) -> Stream<String, Never> {
  497. createStream(automaticallyCancelling: shouldAutomaticallyCancel, bufferingPolicy: bufferingPolicy) { onStream in
  498. self.request.responseStreamString(on: .streamCompletionQueue(forRequestID: request.id), stream: onStream)
  499. }
  500. }
  501. /// Creates a `Stream` of `Decodable` values from the underlying `DataStreamRequest`.
  502. ///
  503. /// - Parameters:
  504. /// - type: `Decodable` type to be serialized from stream payloads.
  505. /// - shouldAutomaticallyCancel: `Bool` indicating whether the underlying `DataStreamRequest` should be canceled
  506. /// which observation of the stream stops. `true` by default.
  507. /// - bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default.
  508. ///
  509. /// - Returns: The `Stream`.
  510. public func streamingDecodables<T>(_ type: T.Type = T.self,
  511. automaticallyCancelling shouldAutomaticallyCancel: Bool = true,
  512. bufferingPolicy: Stream<T, AFError>.BufferingPolicy = .unbounded)
  513. -> Stream<T, AFError> where T: Decodable {
  514. streamingResponses(serializedUsing: DecodableStreamSerializer<T>(),
  515. automaticallyCancelling: shouldAutomaticallyCancel,
  516. bufferingPolicy: bufferingPolicy)
  517. }
  518. /// Creates a `Stream` of values using the provided `DataStreamSerializer` from the underlying `DataStreamRequest`.
  519. ///
  520. /// - Parameters:
  521. /// - serializer: `DataStreamSerializer` to use to serialize incoming `Data`.
  522. /// - shouldAutomaticallyCancel: `Bool` indicating whether the underlying `DataStreamRequest` should be canceled
  523. /// which observation of the stream stops. `true` by default.
  524. /// - bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default.
  525. ///
  526. /// - Returns: The `Stream`.
  527. public func streamingResponses<Serializer: DataStreamSerializer>(serializedUsing serializer: Serializer,
  528. automaticallyCancelling shouldAutomaticallyCancel: Bool = true,
  529. bufferingPolicy: Stream<Serializer.SerializedObject, AFError>.BufferingPolicy = .unbounded)
  530. -> Stream<Serializer.SerializedObject, AFError> {
  531. createStream(automaticallyCancelling: shouldAutomaticallyCancel, bufferingPolicy: bufferingPolicy) { onStream in
  532. self.request.responseStream(using: serializer,
  533. on: .streamCompletionQueue(forRequestID: request.id),
  534. stream: onStream)
  535. }
  536. }
  537. private func createStream<Success, Failure: Error>(automaticallyCancelling shouldAutomaticallyCancel: Bool = true,
  538. bufferingPolicy: Stream<Success, Failure>.BufferingPolicy = .unbounded,
  539. forResponse onResponse: @escaping (@escaping (DataStreamRequest.Stream<Success, Failure>) -> Void) -> Void)
  540. -> Stream<Success, Failure> {
  541. StreamOf(bufferingPolicy: bufferingPolicy) {
  542. guard shouldAutomaticallyCancel,
  543. request.isInitialized || request.isResumed || request.isSuspended else { return }
  544. cancel()
  545. } builder: { continuation in
  546. onResponse { stream in
  547. continuation.yield(stream)
  548. if case .complete = stream.event {
  549. continuation.finish()
  550. }
  551. }
  552. }
  553. }
  554. /// Cancel the underlying `DataStreamRequest`.
  555. public func cancel() {
  556. request.cancel()
  557. }
  558. /// Resume the underlying `DataStreamRequest`.
  559. public func resume() {
  560. request.resume()
  561. }
  562. /// Suspend the underlying `DataStreamRequest`.
  563. public func suspend() {
  564. request.suspend()
  565. }
  566. }
  567. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  568. extension DataStreamRequest {
  569. /// Creates a `DataStreamTask` used to `await` streams of serialized values.
  570. ///
  571. /// - Returns: The `DataStreamTask`.
  572. public func streamTask() -> DataStreamTask {
  573. DataStreamTask(request: self)
  574. }
  575. }
  576. extension DispatchQueue {
  577. fileprivate static let singleEventQueue = DispatchQueue(label: "org.alamofire.concurrencySingleEventQueue",
  578. attributes: .concurrent)
  579. fileprivate static func streamCompletionQueue(forRequestID id: UUID) -> DispatchQueue {
  580. DispatchQueue(label: "org.alamofire.concurrencyStreamCompletionQueue-\(id)", target: .singleEventQueue)
  581. }
  582. }
  583. /// An asynchronous sequence generated from an underlying `AsyncStream`. Only produced by Alamofire.
  584. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  585. public struct StreamOf<Element>: AsyncSequence {
  586. public typealias AsyncIterator = Iterator
  587. public typealias BufferingPolicy = AsyncStream<Element>.Continuation.BufferingPolicy
  588. fileprivate typealias Continuation = AsyncStream<Element>.Continuation
  589. private let bufferingPolicy: BufferingPolicy
  590. private let onTermination: (() -> Void)?
  591. private let builder: (Continuation) -> Void
  592. fileprivate init(bufferingPolicy: BufferingPolicy = .unbounded,
  593. onTermination: (() -> Void)? = nil,
  594. builder: @escaping (Continuation) -> Void) {
  595. self.bufferingPolicy = bufferingPolicy
  596. self.onTermination = onTermination
  597. self.builder = builder
  598. }
  599. public func makeAsyncIterator() -> Iterator {
  600. var continuation: AsyncStream<Element>.Continuation?
  601. let stream = AsyncStream<Element> { innerContinuation in
  602. continuation = innerContinuation
  603. builder(innerContinuation)
  604. }
  605. return Iterator(iterator: stream.makeAsyncIterator()) {
  606. continuation?.finish()
  607. self.onTermination?()
  608. }
  609. }
  610. public struct Iterator: AsyncIteratorProtocol {
  611. private final class Token {
  612. private let onDeinit: () -> Void
  613. init(onDeinit: @escaping () -> Void) {
  614. self.onDeinit = onDeinit
  615. }
  616. deinit {
  617. onDeinit()
  618. }
  619. }
  620. private var iterator: AsyncStream<Element>.AsyncIterator
  621. private let token: Token
  622. init(iterator: AsyncStream<Element>.AsyncIterator, onCancellation: @escaping () -> Void) {
  623. self.iterator = iterator
  624. token = Token(onDeinit: onCancellation)
  625. }
  626. public mutating func next() async -> Element? {
  627. await iterator.next()
  628. }
  629. }
  630. }
  631. #endif