@@ -30,12 +30,12 @@ open class NetworkTask<T: Sendable>: @unchecked Sendable {
3030 private let session : Session
3131
3232 /// The thread safe state of the task.
33- private let state : NetworkTaskState < Response >
33+ private let values : NetworkTaskValues < Response >
3434
3535 /// The underlying ``URLSessionTask``.
3636 internal var sessionTask : URLSessionTask ? {
3737 get async {
38- return await state . sessionTask
38+ return await values . sessionTask
3939 }
4040 }
4141
@@ -47,7 +47,7 @@ open class NetworkTask<T: Sendable>: @unchecked Sendable {
4747 /// You can use this to inspect the request metadata or re-execute it.
4848 public var request : AnyRequest {
4949 get async {
50- return await state . request
50+ return await values . request
5151 }
5252 }
5353
@@ -59,7 +59,7 @@ open class NetworkTask<T: Sendable>: @unchecked Sendable {
5959 /// You can inspect this to view the final request sent over the network.
6060 public var urlRequest : URLRequest ? {
6161 get async {
62- return await state . urlRequest
62+ return await values . urlRequest
6363 }
6464 }
6565
@@ -75,7 +75,7 @@ open class NetworkTask<T: Sendable>: @unchecked Sendable {
7575 ) {
7676 self . id = request. id
7777 self . session = session
78- self . state = NetworkTaskState ( request: request)
78+ self . values = NetworkTaskValues ( request: request)
7979 }
8080
8181// MARK: - Functions
@@ -97,7 +97,9 @@ open class NetworkTask<T: Sendable>: @unchecked Sendable {
9797 ///
9898 /// - Note: This method is prefixed with `_` to indicate that it is not intended for public use.
9999 open func _finished( with error: NetworkingError ? ) async {
100- if let urlRequest = await state. urlRequest {
100+ await values. transition ( to: . completed)
101+ await values. finish ( )
102+ if let urlRequest = await values. urlRequest {
101103 await configurations. tasks. remove ( urlRequest)
102104 }
103105 }
@@ -106,6 +108,10 @@ open class NetworkTask<T: Sendable>: @unchecked Sendable {
106108 ///
107109 /// - Throws: A ``NetworkingError`` if request construction fails.
108110 @discardableResult public func response( ) async throws ( NetworkingError) -> sending Response {
111+ guard await state != . cancelled else {
112+ throw . cancellation
113+ }
114+ await values. transition ( to: . running)
109115 return try await currentTask ( ) . typedValue
110116 }
111117}
@@ -116,7 +122,7 @@ extension NetworkTask {
116122 ///
117123 /// - Returns: A task representing the lifecycle of the current request.
118124 private func currentTask( ) async -> Task < Response , any Error > {
119- return await state . activeTask {
125+ return await values . activeTask {
120126 let result = await self . perform ( )
121127 await self . _finished ( with: result. error)
122128 return try result. get ( )
@@ -146,13 +152,15 @@ extension NetworkTask {
146152 result = . failure( error)
147153 }
148154
155+ await values. transition ( to: . intercepting)
156+
149157 do throws ( NetworkingError) {
150158 try Task . checkTypedCancellation ( )
151159 let context = await InterceptorContext (
152160 configurations: configurations,
153161 status: result. value? . 1 . status,
154162 retryCount: retryCount,
155- urlRequest: state . urlRequest,
163+ urlRequest: values . urlRequest,
156164 error: result. error
157165 )
158166 let intercepted = try await configurations. taskInterceptor. intercept (
@@ -166,7 +174,7 @@ extension NetworkTask {
166174 case . failure( let error) :
167175 return . failure( error. networkingError)
168176 case . retry:
169- await state . resetTask ( )
177+ await values . resetTask ( )
170178 return await perform ( )
171179 }
172180 } catch {
@@ -185,7 +193,7 @@ extension NetworkTask {
185193 /// - Returns: A fully constructed and intercepted ``URLRequest``.
186194 /// - Throws: A ``NetworkingError`` if request construction fails.
187195 private func makeURLRequest( ) async throws ( NetworkingError) -> URLRequest {
188- if let oldRequest = await state . urlRequest {
196+ if let oldRequest = await values . urlRequest {
189197 await configurations. tasks. remove ( oldRequest)
190198 }
191199 var urlRequest = try await request. _makeURLRequest ( with: configurations)
@@ -196,7 +204,7 @@ extension NetworkTask {
196204 with: configurations
197205 )
198206 await configurations. tasks. add ( self , for: urlRequest)
199- await state . set ( urlRequest)
207+ await values . set ( urlRequest)
200208 return urlRequest
201209 }
202210}
@@ -233,14 +241,28 @@ extension NetworkTask: NetworkingTask {
233241 /// The number of retry attempts made for this task.
234242 public var retryCount : Int {
235243 get async {
236- return await state . retryCount
244+ return await values . retryCount
237245 }
238246 }
239247
240248 /// The current task metrics.
241249 public var metrics : URLSessionTaskMetrics ? {
242250 get async {
243- return await state. metrics
251+ return await values. metrics
252+ }
253+ }
254+
255+ /// The current execution state of a task.
256+ public var state : TaskState {
257+ get async {
258+ return await values. state
259+ }
260+ }
261+
262+ /// A stream that emits state updates throughout the task lifecycle.
263+ public var stateUpdates : AsyncStream < TaskState > {
264+ get async {
265+ return await values. stateStream
244266 }
245267 }
246268
@@ -250,37 +272,46 @@ extension NetworkTask: NetworkingTask {
250272 ///
251273 /// - Note: This method is prefixed with `_` to indicate that it is not intended for public use.
252274 public func _session( collected metrics: URLSessionTaskMetrics ) async {
253- await state . set ( metrics)
275+ await values . set ( metrics)
254276 }
255277
256278 /// Sets the ``URLSessionTask``.
257279 ///
258280 /// - Note: This method is prefixed with `_` to indicate that it is not intended for public use.
259281 @available ( iOS 16 . 0 , macOS 13 . 0 , watchOS 9 . 0 , tvOS 16 . 0 , visionOS 1 . 0 , macCatalyst 16 . 0 , * )
260282 public func _set( _ task: URLSessionTask ) async {
261- await state . set ( task)
283+ await values . set ( task)
262284 }
263285
264286 /// Cancels the current task if any is running.
265287 @discardableResult public func cancel( ) async -> Self {
266- await state. currentTask? . cancel ( )
288+ guard await values. transition ( to: . cancelled) else {
289+ return self
290+ }
291+ await values. currentTask? . cancel ( )
267292 return self
268293 }
269294
270295 /// Resumes the task by starting it or continuing it if already started.
271296 @discardableResult public func resume( ) async -> Self {
272- if await state. currentTask == nil {
297+ guard await values. transition ( to: . running) else {
298+ return self
299+ }
300+ if await values. currentTask == nil {
273301 _ = await currentTask ( )
274302 } else {
275- await state . sessionTask? . resume ( )
303+ await values . sessionTask? . resume ( )
276304 }
277305 return self
278306 }
279307
280308 /// Suspends the task if it's currently running.
281309 @available ( iOS 16 . 0 , macOS 13 . 0 , watchOS 9 . 0 , tvOS 16 . 0 , visionOS 1 . 0 , macCatalyst 16 . 0 , * )
282310 @discardableResult public func suspend( ) async -> Self {
283- await state. sessionTask? . suspend ( )
311+ guard await values. transition ( to: . suspended) else {
312+ return self
313+ }
314+ await values. sessionTask? . suspend ( )
284315 return self
285316 }
286317}
0 commit comments