@@ -164,7 +164,70 @@ success = await DownloadManager.download_url(
164164)
165165```
166166
167- ### Helper Functions
167+ ### Utility Functions
168+
169+ #### ` DownloadManager.is_network_error(exception) `
170+
171+ Check if an exception is a recoverable network error.
172+
173+ Recognizes common network error codes and messages that indicate temporary connectivity issues that can be retried.
174+
175+ ** Parameters:**
176+ - ` exception ` - Exception to check
177+
178+ ** Returns:**
179+ - ` bool ` - True if this is a network error that can be retried
180+
181+ ** Example:**
182+ ``` python
183+ try :
184+ await DownloadManager.download_url(url)
185+ except Exception as e:
186+ if DownloadManager.is_network_error(e):
187+ # Network error - wait and retry
188+ await TaskManager.sleep(2 )
189+ # Retry with resume...
190+ else :
191+ # Fatal error - show error to user
192+ raise
193+ ```
194+
195+ ** Detected error codes:**
196+ - ` -110 ` - ETIMEDOUT (connection timed out)
197+ - ` -113 ` - ECONNABORTED (connection aborted)
198+ - ` -104 ` - ECONNRESET (connection reset by peer)
199+ - ` -118 ` - EHOSTUNREACH (no route to host)
200+ - ` -202 ` - DNS/connection error (network not ready)
201+
202+ ** Detected error messages:**
203+ - "connection reset", "connection aborted"
204+ - "broken pipe", "network unreachable", "host unreachable"
205+ - "failed to download chunk"
206+
207+ #### ` DownloadManager.get_resume_position(outfile) `
208+
209+ Get the current size of a partially downloaded file.
210+
211+ Useful for implementing resume functionality with Range headers.
212+
213+ ** Parameters:**
214+ - ` outfile ` - Path to file
215+
216+ ** Returns:**
217+ - ` int ` - File size in bytes, or 0 if file doesn't exist
218+
219+ ** Example:**
220+ ``` python
221+ resume_from = DownloadManager.get_resume_position(" /sdcard/file.bin" )
222+ if resume_from > 0 :
223+ headers = {' Range' : f ' bytes= { resume_from} - ' }
224+ await DownloadManager.download_url(url, outfile = outfile, headers = headers)
225+ else :
226+ # Start new download
227+ await DownloadManager.download_url(url, outfile = outfile)
228+ ```
229+
230+ ### Session Management Functions
168231
169232#### ` DownloadManager.is_session_active() `
170233
@@ -254,56 +317,74 @@ async def download_mpk(self, app):
254317### Resume Partial Download
255318
256319``` python
257- import os
258-
259320async def resume_download (self , url , outfile ):
260321 """ Resume a partial download using Range headers"""
261- bytes_written = 0
262-
263- # Check if partial file exists
264- try :
265- bytes_written = os.stat(outfile)[6 ] # File size
322+ # Use DownloadManager utility to get resume position
323+ bytes_written = DownloadManager.get_resume_position(outfile)
324+
325+ if bytes_written > 0 :
266326 print (f " Resuming from { bytes_written} bytes " )
267- except OSError :
327+ headers = {' Range' : f ' bytes= { bytes_written} - ' }
328+ else :
268329 print (" Starting new download" )
330+ headers = None
269331
270332 # Download remaining bytes
271333 success = await DownloadManager.download_url(
272334 url,
273335 outfile = outfile,
274- headers = { ' Range ' : f ' bytes= { bytes_written } - ' }
336+ headers = headers
275337 )
276338
277339 return success
278340```
279341
280342** Note:** Server must support HTTP Range requests.
281343
282- ### Error Handling
344+ ### Error Handling with Network Detection
283345
284346``` python
285- async def robust_download (self , url ):
286- """ Download with comprehensive error handling"""
287- try :
288- data = await DownloadManager.download_url(url)
289-
290- if data is None :
291- print (" Download failed (network error or HTTP error)" )
292- return None
293-
294- if len (data) == 0 :
295- print (" Warning: Downloaded empty file" )
296-
297- return data
298-
299- except ValueError as e:
300- print (f " Invalid parameters: { e} " )
301- return None
302- except Exception as e:
303- print (f " Unexpected error: { e} " )
304- return None
347+ async def robust_download (self , url , outfile ):
348+ """ Download with comprehensive error handling and retry"""
349+ max_retries = 3
350+ retry_delay = 2
351+
352+ for attempt in range (max_retries):
353+ try :
354+ success = await DownloadManager.download_url(url, outfile = outfile)
355+
356+ if success:
357+ return True
358+ else :
359+ print (" Download failed" )
360+ return False
361+
362+ except Exception as e:
363+ if DownloadManager.is_network_error(e):
364+ # Network error - retry with resume
365+ print (f " Network error (attempt { attempt + 1 } / { max_retries} ): { e} " )
366+
367+ if attempt < max_retries - 1 :
368+ await TaskManager.sleep(retry_delay)
369+ # Resume from last position
370+ continue
371+ else :
372+ print (" Max retries reached" )
373+ return False
374+ else :
375+ # Non-network error - don't retry
376+ print (f " Fatal error: { e} " )
377+ return False
378+
379+ return False
305380```
306381
382+ ** Benefits:**
383+ - Automatic retry on network errors
384+ - Resume from last position
385+ - No retry on fatal errors (404, invalid URL, etc.)
386+ - User-friendly error messages
387+
307388## Session Management
308389
309390### Automatic Lifecycle
0 commit comments