@@ -89,12 +89,18 @@ class Downloader: NSObject, ObservableObject {
89
89
timeout: TimeInterval ,
90
90
numRetries: Int
91
91
) {
92
+ print ( " [Downloader] Setting up download for \( url. lastPathComponent) " )
93
+ print ( " [Downloader] Destination: \( destination. path) " )
94
+ print ( " [Downloader] Temp file: \( tempFilePath? . path ?? " none " ) " )
95
+
92
96
// If we have an expected size and resumeSize, calculate initial progress
93
97
if let expectedSize = expectedSize, expectedSize > 0 && resumeSize > 0 {
94
98
let initialProgress = Double ( resumeSize) / Double( expectedSize)
95
99
downloadState. value = . downloading( initialProgress)
100
+ print ( " [Downloader] Resuming from \( resumeSize) / \( expectedSize) bytes ( \( Int ( initialProgress * 100 ) ) %) " )
96
101
} else {
97
102
downloadState. value = . downloading( 0 )
103
+ print ( " [Downloader] Starting new download " )
98
104
}
99
105
100
106
urlSession? . getAllTasks { tasks in
@@ -148,6 +154,9 @@ class Downloader: NSObject, ObservableObject {
148
154
// If the reported resumeSize doesn't match the file size, trust the file size
149
155
if existingSize != resumeSize {
150
156
self . downloadedSize = existingSize
157
+ print ( " [Downloader] Found existing temp file with \( existingSize) bytes (different from resumeSize: \( resumeSize) ) " )
158
+ } else {
159
+ print ( " [Downloader] Found existing temp file with \( existingSize) bytes " )
151
160
}
152
161
} else {
153
162
// Create new temp file with predictable path for future resume
@@ -160,6 +169,7 @@ class Downloader: NSObject, ObservableObject {
160
169
} )
161
170
let hashedName = " \( filename) - \( stableHash) "
162
171
tempURL = FileManager . default. temporaryDirectory. appendingPathComponent ( hashedName)
172
+ print ( " [Downloader] Creating new temp file at \( tempURL. path) " )
163
173
FileManager . default. createFile ( atPath: tempURL. path, contents: nil )
164
174
}
165
175
@@ -168,6 +178,7 @@ class Downloader: NSObject, ObservableObject {
168
178
169
179
// If we're resuming, seek to end of file first
170
180
if existingSize > 0 {
181
+ print ( " [Downloader] Seeking to end of existing file ( \( existingSize) bytes) " )
171
182
try tempFile. seekToEnd ( )
172
183
}
173
184
@@ -176,12 +187,16 @@ class Downloader: NSObject, ObservableObject {
176
187
177
188
// Clean up and move the completed download to its final destination
178
189
tempFile. closeFile ( )
190
+ print ( " [Downloader] Download completed with total size \( self . downloadedSize) bytes " )
191
+ print ( " [Downloader] Moving temp file to destination: \( self . destination. path) " )
179
192
try FileManager . default. moveDownloadedFile ( from: tempURL, to: self . destination)
180
193
181
194
// Clear temp file reference since it's been moved
182
195
self . tempFilePath = nil
196
+ print ( " [Downloader] Download successfully completed " )
183
197
self . downloadState. value = . completed( self . destination)
184
198
} catch {
199
+ print ( " [Downloader] Error: \( error) " )
185
200
self . downloadState. value = . failed( error)
186
201
}
187
202
}
@@ -214,16 +229,27 @@ class Downloader: NSObject, ObservableObject {
214
229
var newRequest = request
215
230
if resumeSize > 0 {
216
231
newRequest. setValue ( " bytes= \( resumeSize) - " , forHTTPHeaderField: " Range " )
232
+ print ( " [Downloader] Adding Range header: bytes= \( resumeSize) - " )
217
233
}
218
234
219
235
// Start the download and get the byte stream
220
236
let ( asyncBytes, response) = try await session. bytes ( for: newRequest)
221
237
222
- guard let response = response as? HTTPURLResponse else {
238
+ guard let httpResponse = response as? HTTPURLResponse else {
239
+ print ( " [Downloader] Error: Non-HTTP response received " )
223
240
throw DownloadError . unexpectedError
224
241
}
242
+
243
+ print ( " [Downloader] Received HTTP \( httpResponse. statusCode) response " )
244
+ if let contentRange = httpResponse. value ( forHTTPHeaderField: " Content-Range " ) {
245
+ print ( " [Downloader] Content-Range: \( contentRange) " )
246
+ }
247
+ if let contentLength = httpResponse. value ( forHTTPHeaderField: " Content-Length " ) {
248
+ print ( " [Downloader] Content-Length: \( contentLength) " )
249
+ }
225
250
226
- guard ( 200 ..< 300 ) . contains ( response. statusCode) else {
251
+ guard ( 200 ..< 300 ) . contains ( httpResponse. statusCode) else {
252
+ print ( " [Downloader] Error: HTTP status code \( httpResponse. statusCode) " )
227
253
throw DownloadError . unexpectedError
228
254
}
229
255
@@ -277,7 +303,10 @@ class Downloader: NSObject, ObservableObject {
277
303
// Verify the downloaded file size matches the expected size
278
304
let actualSize = try tempFile. seekToEnd ( )
279
305
if let expectedSize = expectedSize, expectedSize != actualSize {
306
+ print ( " [Downloader] Error: Size mismatch - expected \( expectedSize) bytes but got \( actualSize) bytes " )
280
307
throw DownloadError . unexpectedError
308
+ } else {
309
+ print ( " [Downloader] Final verification passed, size: \( actualSize) bytes " )
281
310
}
282
311
}
283
312
@@ -363,6 +392,7 @@ extension Downloader {
363
392
/// Persists the current download state to UserDefaults
364
393
func persistState( ) {
365
394
guard let tempFilePath = self . tempFilePath else {
395
+ print ( " [Downloader] Cannot persist state: No temp file path " )
366
396
return // Nothing to persist if no temp file
367
397
}
368
398
@@ -376,8 +406,9 @@ extension Downloader {
376
406
var states = Downloader . getPersistedStates ( )
377
407
states [ sourceURL. absoluteString] = data
378
408
UserDefaults . standard. set ( states, forKey: " SwiftTransformers.ActiveDownloads " )
409
+ print ( " [Downloader] Persisted download state for \( sourceURL. lastPathComponent) - \( downloadedSize) bytes downloaded " )
379
410
} catch {
380
- print ( " Error persisting download state: \( error) " )
411
+ print ( " [Downloader] Error persisting download state: \( error) " )
381
412
}
382
413
}
383
414
@@ -386,6 +417,7 @@ extension Downloader {
386
417
var states = Downloader . getPersistedStates ( )
387
418
states. removeValue ( forKey: sourceURL. absoluteString)
388
419
UserDefaults . standard. set ( states, forKey: " SwiftTransformers.ActiveDownloads " )
420
+ print ( " [Downloader] Removed persisted state for \( sourceURL. lastPathComponent) " )
389
421
}
390
422
391
423
/// Get all persisted download states
@@ -398,16 +430,19 @@ extension Downloader {
398
430
let states = getPersistedStates ( )
399
431
let decoder = JSONDecoder ( )
400
432
433
+ print ( " [Downloader] Found \( states. count) persisted download states " )
401
434
var resumedDownloaders : [ Downloader ] = [ ]
402
435
403
- for (_ , stateData) in states {
436
+ for (url , stateData) in states {
404
437
do {
405
438
let state = try decoder. decode ( PersistableDownloadState . self, from: stateData)
439
+ print ( " [Downloader] Trying to resume download for: \( state. sourceURL. lastPathComponent) " )
406
440
407
441
// Check if temp file still exists
408
442
if FileManager . default. fileExists ( atPath: state. tempFilePath. path) {
409
443
let attributes = try FileManager . default. attributesOfItem ( atPath: state. tempFilePath. path)
410
444
let fileSize = attributes [ . size] as? Int ?? 0
445
+ print ( " [Downloader] Found existing temp file with \( fileSize) bytes " )
411
446
412
447
// Create a new downloader that resumes from the temp file
413
448
let downloader = Downloader (
@@ -420,12 +455,16 @@ extension Downloader {
420
455
)
421
456
422
457
resumedDownloaders. append ( downloader)
458
+ print ( " [Downloader] Successfully resumed download for \( state. sourceURL. lastPathComponent) " )
459
+ } else {
460
+ print ( " [Downloader] Temp file not found at \( state. tempFilePath. path) " )
423
461
}
424
462
} catch {
425
- print ( " Error restoring download: \( error) " )
463
+ print ( " [Downloader] Error restoring download for \( url ) : \( error) " )
426
464
}
427
465
}
428
466
467
+ print ( " [Downloader] Successfully resumed \( resumedDownloaders. count) downloads " )
429
468
return resumedDownloaders
430
469
}
431
470
}
0 commit comments