Concurrency.swift 36 KB

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