Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

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