@@ -29,18 +29,18 @@ final class Downloader: NSObject, Sendable, ObservableObject {
29
29
}
30
30
31
31
private let broadcaster : Broadcaster < DownloadState > = Broadcaster< DownloadState> {
32
- return DownloadState . notStarted
32
+ DownloadState . notStarted
33
33
}
34
34
35
35
private let sessionConfig : URLSessionConfiguration
36
- let session : SessionActor = SessionActor ( )
37
- private let task : TaskActor = TaskActor ( )
36
+ let session : SessionActor = . init ( )
37
+ private let task : TaskActor = . init ( )
38
38
39
39
init (
40
40
to destination: URL ,
41
41
incompleteDestination: URL ,
42
42
inBackground: Bool = false ,
43
- chunkSize: Int = 10 * 1024 * 1024 // 10MB
43
+ chunkSize: Int = 10 * 1024 * 1024 // 10MB
44
44
) {
45
45
self . destination = destination
46
46
// Create incomplete file path based on destination
@@ -55,7 +55,7 @@ final class Downloader: NSObject, Sendable, ObservableObject {
55
55
config. isDiscretionary = false
56
56
config. sessionSendsLaunchEvents = true
57
57
}
58
- self . sessionConfig = config
58
+ sessionConfig = config
59
59
}
60
60
61
61
func download(
@@ -66,13 +66,13 @@ final class Downloader: NSObject, Sendable, ObservableObject {
66
66
timeout: TimeInterval = 10 ,
67
67
numRetries: Int = 5
68
68
) async -> AsyncStream < DownloadState > {
69
- if let task = await self . task. get ( ) {
69
+ if let task = await task. get ( ) {
70
70
task. cancel ( )
71
71
}
72
- await self . downloadResumeState. setExpectedSize ( expectedSize)
73
- let resumeSize = Self . incompleteFileSize ( at: self . incompleteDestination)
74
- await self . session. set ( URLSession ( configuration: self . sessionConfig, delegate: self , delegateQueue: nil ) )
75
- await self . setUpDownload (
72
+ await downloadResumeState. setExpectedSize ( expectedSize)
73
+ let resumeSize = Self . incompleteFileSize ( at: incompleteDestination)
74
+ await session. set ( URLSession ( configuration: sessionConfig, delegate: self , delegateQueue: nil ) )
75
+ await setUpDownload (
76
76
from: url,
77
77
with: authToken,
78
78
resumeSize: resumeSize,
@@ -81,7 +81,7 @@ final class Downloader: NSObject, Sendable, ObservableObject {
81
81
numRetries: numRetries
82
82
)
83
83
84
- return await self . broadcaster. subscribe ( )
84
+ return await broadcaster. subscribe ( )
85
85
}
86
86
87
87
/// Sets up and initiates a file download operation
@@ -102,8 +102,8 @@ final class Downloader: NSObject, Sendable, ObservableObject {
102
102
timeout: TimeInterval ,
103
103
numRetries: Int
104
104
) async {
105
- let resumeSize = Self . incompleteFileSize ( at: self . incompleteDestination)
106
- guard let tasks = await self . session. get ( ) ? . allTasks else {
105
+ let resumeSize = Self . incompleteFileSize ( at: incompleteDestination)
106
+ guard let tasks = await session. get ( ) ? . allTasks else {
107
107
return
108
108
}
109
109
@@ -123,7 +123,7 @@ final class Downloader: NSObject, Sendable, ObservableObject {
123
123
}
124
124
}
125
125
126
- await self . task. set (
126
+ await task. set (
127
127
Task {
128
128
do {
129
129
var request = URLRequest ( url: url)
@@ -132,7 +132,7 @@ final class Downloader: NSObject, Sendable, ObservableObject {
132
132
var requestHeaders = headers ?? [ : ]
133
133
134
134
// Populate header auth and range fields
135
- if let authToken = authToken {
135
+ if let authToken {
136
136
requestHeaders [ " Authorization " ] = " Bearer \( authToken) "
137
137
}
138
138
@@ -203,14 +203,14 @@ final class Downloader: NSObject, Sendable, ObservableObject {
203
203
tempFile: FileHandle ,
204
204
numRetries: Int
205
205
) async throws {
206
- guard let session = await self . session. get ( ) else {
206
+ guard let session = await session. get ( ) else {
207
207
throw DownloadError . unexpectedError
208
208
}
209
209
210
210
// Create a new request with Range header for resuming
211
211
var newRequest = request
212
- if await self . downloadResumeState. downloadedSize > 0 {
213
- newRequest. setValue ( " bytes= \( await self . downloadResumeState. downloadedSize) - " , forHTTPHeaderField: " Range " )
212
+ if await downloadResumeState. downloadedSize > 0 {
213
+ await newRequest. setValue ( " bytes= \( downloadResumeState. downloadedSize) - " , forHTTPHeaderField: " Range " )
214
214
}
215
215
216
216
// Start the download and get the byte stream
@@ -233,22 +233,22 @@ final class Downloader: NSObject, Sendable, ObservableObject {
233
233
buffer. append ( byte)
234
234
// When buffer is full, write to disk
235
235
if buffer. count == chunkSize {
236
- if !buffer. isEmpty { // Filter out keep-alive chunks
236
+ if !buffer. isEmpty { // Filter out keep-alive chunks
237
237
try tempFile. write ( contentsOf: buffer)
238
238
buffer. removeAll ( keepingCapacity: true )
239
239
240
- await self . downloadResumeState. incDownloadedSize ( chunkSize)
240
+ await downloadResumeState. incDownloadedSize ( chunkSize)
241
241
newNumRetries = 5
242
- guard let expectedSize = await self . downloadResumeState. expectedSize else { continue }
243
- let progress = expectedSize != 0 ? Double ( await self . downloadResumeState. downloadedSize) / Double( expectedSize) : 0
244
- await self . broadcaster. broadcast ( state: . downloading( progress) )
242
+ guard let expectedSize = await downloadResumeState. expectedSize else { continue }
243
+ let progress = await expectedSize != 0 ? Double ( downloadResumeState. downloadedSize) / Double( expectedSize) : 0
244
+ await broadcaster. broadcast ( state: . downloading( progress) )
245
245
}
246
246
}
247
247
}
248
248
249
249
if !buffer. isEmpty {
250
250
try tempFile. write ( contentsOf: buffer)
251
- await self . downloadResumeState. incDownloadedSize ( buffer. count)
251
+ await downloadResumeState. incDownloadedSize ( buffer. count)
252
252
buffer. removeAll ( keepingCapacity: true )
253
253
newNumRetries = 5
254
254
}
@@ -270,15 +270,15 @@ final class Downloader: NSObject, Sendable, ObservableObject {
270
270
271
271
// Verify the downloaded file size matches the expected size
272
272
let actualSize = try tempFile. seekToEnd ( )
273
- if let expectedSize = await self . downloadResumeState. expectedSize, expectedSize != actualSize {
273
+ if let expectedSize = await downloadResumeState. expectedSize, expectedSize != actualSize {
274
274
throw DownloadError . unexpectedError
275
275
}
276
276
}
277
277
278
278
func cancel( ) async {
279
- await self . session. get ( ) ? . invalidateAndCancel ( )
280
- await self . task. get ( ) ? . cancel ( )
281
- await self . broadcaster. broadcast ( state: . failed( URLError ( . cancelled) ) )
279
+ await session. get ( ) ? . invalidateAndCancel ( )
280
+ await task. get ( ) ? . cancel ( )
281
+ await broadcaster. broadcast ( state: . failed( URLError ( . cancelled) ) )
282
282
}
283
283
284
284
/// Check if an incomplete file exists for the destination and returns its size
@@ -305,7 +305,7 @@ extension Downloader: URLSessionDownloadDelegate {
305
305
func urlSession( _: URLSession , downloadTask _: URLSessionDownloadTask , didFinishDownloadingTo location: URL ) {
306
306
do {
307
307
// If the downloaded file already exists on the filesystem, overwrite it
308
- try FileManager . default. moveDownloadedFile ( from: location, to: self . destination)
308
+ try FileManager . default. moveDownloadedFile ( from: location, to: destination)
309
309
Task {
310
310
await self . broadcaster. broadcast ( state: . completed( destination) )
311
311
}
@@ -317,7 +317,7 @@ extension Downloader: URLSessionDownloadDelegate {
317
317
}
318
318
319
319
func urlSession( _ session: URLSession , task: URLSessionTask , didCompleteWithError error: Error ? ) {
320
- if let error = error {
320
+ if let error {
321
321
Task {
322
322
await self . broadcaster. broadcast ( state: . failed( error) )
323
323
}
@@ -347,15 +347,15 @@ private actor DownloadResumeState {
347
347
var downloadedSize : Int = 0
348
348
349
349
func setExpectedSize( _ size: Int ? ) {
350
- self . expectedSize = size
350
+ expectedSize = size
351
351
}
352
352
353
353
func setDownloadedSize( _ size: Int ) {
354
- self . downloadedSize = size
354
+ downloadedSize = size
355
355
}
356
356
357
357
func incDownloadedSize( _ size: Int ) {
358
- self . downloadedSize += size
358
+ downloadedSize += size
359
359
}
360
360
}
361
361
@@ -373,7 +373,7 @@ actor Broadcaster<E: Sendable> {
373
373
}
374
374
375
375
func subscribe( ) -> AsyncStream < E > {
376
- return AsyncStream { continuation in
376
+ AsyncStream { continuation in
377
377
let id = UUID ( )
378
378
self . continuations [ id] = continuation
379
379
@@ -396,11 +396,11 @@ actor Broadcaster<E: Sendable> {
396
396
}
397
397
398
398
private func unsubscribe( _ id: UUID ) {
399
- self . continuations. removeValue ( forKey: id)
399
+ continuations. removeValue ( forKey: id)
400
400
}
401
401
402
402
func broadcast( state: E ) async {
403
- self . latestState = state
403
+ latestState = state
404
404
await withTaskGroup ( of: Void . self) { group in
405
405
for continuation in continuations. values {
406
406
group. addTask {
@@ -412,25 +412,25 @@ actor Broadcaster<E: Sendable> {
412
412
}
413
413
414
414
actor SessionActor {
415
- private var urlSession : URLSession ? = nil
415
+ private var urlSession : URLSession ?
416
416
417
417
func set( _ urlSession: URLSession ? ) {
418
418
self . urlSession = urlSession
419
419
}
420
420
421
421
func get( ) -> URLSession ? {
422
- return self . urlSession
422
+ urlSession
423
423
}
424
424
}
425
425
426
426
actor TaskActor {
427
- private var task : Task < Void , Error > ? = nil
427
+ private var task : Task < Void , Error > ?
428
428
429
429
func set( _ task: Task < Void , Error > ? ) {
430
430
self . task = task
431
431
}
432
432
433
433
func get( ) -> Task < Void , Error > ? {
434
- return self . task
434
+ task
435
435
}
436
436
}
0 commit comments