Skip to content

Commit 51a5248

Browse files
OSUpdate app: work towards fixing auto-resume
1 parent 4756571 commit 51a5248

File tree

4 files changed

+59
-44
lines changed

4 files changed

+59
-44
lines changed

internal_filesystem/builtin/apps/com.micropythonos.appstore/assets/appstore.py

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,11 @@ def onResume(self, screen):
6060
TaskManager.create_task(self.download_app_index(self.app_index_url_github))
6161

6262
async def download_app_index(self, json_url):
63-
response = await DownloadManager.download_url(json_url)
64-
if not response:
65-
self.please_wait_label.set_text(f"Could not download app index from\n{json_url}")
63+
try:
64+
response = await DownloadManager.download_url(json_url)
65+
except Exception as e:
66+
print(f"Failed to download app index: {e}")
67+
self.please_wait_label.set_text(f"Could not download app index from\n{json_url}\nError: {e}")
6668
return
6769
print(f"Got response text: {response[0:20]}")
6870
try:
@@ -197,9 +199,10 @@ def badgehub_app_to_mpos_app(bhapp):
197199

198200
async def fetch_badgehub_app_details(self, app_obj):
199201
details_url = self.app_detail_url_badgehub + "/" + app_obj.fullname
200-
response = await DownloadManager.download_url(details_url)
201-
if not response:
202-
print(f"Could not download app details from from\n{details_url}")
202+
try:
203+
response = await DownloadManager.download_url(details_url)
204+
except Exception as e:
205+
print(f"Could not download app details from {details_url}: {e}")
203206
return
204207
print(f"Got response text: {response[0:20]}")
205208
try:
@@ -480,14 +483,27 @@ async def download_and_install(self, app_obj, dest_folder):
480483
pass
481484
temp_zip_path = "tmp/temp.mpk"
482485
print(f"Downloading .mpk file from: {zip_url} to {temp_zip_path}")
483-
result = await DownloadManager.download_url(zip_url, outfile=temp_zip_path, total_size=download_url_size, progress_callback=self.pcb)
484-
if result is not True:
485-
print("Download failed...") # Would be good to show an error to the user if this failed...
486-
else:
487-
print("Downloaded .mpk file, size:", os.stat(temp_zip_path)[6], "bytes")
488-
# Install it:
489-
PackageManager.install_mpk(temp_zip_path, dest_folder) # 60 until 90 percent is the unzip but no progress there...
490-
self.progress_bar.set_value(90, True)
486+
try:
487+
result = await DownloadManager.download_url(zip_url, outfile=temp_zip_path, total_size=download_url_size, progress_callback=self.pcb)
488+
if result is not True:
489+
print("Download failed...") # Would be good to show an error to the user if this failed...
490+
else:
491+
print("Downloaded .mpk file, size:", os.stat(temp_zip_path)[6], "bytes")
492+
# Install it:
493+
PackageManager.install_mpk(temp_zip_path, dest_folder) # 60 until 90 percent is the unzip but no progress there...
494+
self.progress_bar.set_value(90, True)
495+
except Exception as e:
496+
print(f"Download failed with exception: {e}")
497+
self.install_label.set_text(f"Download failed")
498+
self.install_button.remove_state(lv.STATE.DISABLED)
499+
self.progress_bar.add_flag(lv.obj.FLAG.HIDDEN)
500+
self.progress_bar.set_value(0, False)
501+
# Make sure there's no leftover file filling the storage:
502+
try:
503+
os.remove(temp_zip_path)
504+
except Exception:
505+
pass
506+
return
491507
# Make sure there's no leftover file filling the storage:
492508
try:
493509
os.remove(temp_zip_path)

internal_filesystem/builtin/apps/com.micropythonos.osupdate/assets/osupdate.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,8 @@ def _is_network_error(self, exception):
482482
'-113', '-104', '-110', '-118', # Error codes
483483
'econnaborted', 'econnreset', 'etimedout', 'ehostunreach', # Error names
484484
'connection reset', 'connection aborted', # Error messages
485-
'broken pipe', 'network unreachable', 'host unreachable'
485+
'broken pipe', 'network unreachable', 'host unreachable',
486+
'failed to download chunk' # From download_manager OSError(-110)
486487
]
487488

488489
return any(indicator in error_str or indicator in error_repr

internal_filesystem/lib/mpos/net/download_manager.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,14 @@ async def download_url(url, outfile=None, total_size=None,
200200
201201
Returns:
202202
bytes: Downloaded content (if outfile and chunk_callback are None)
203-
bool: True if successful, False if failed (when using outfile or chunk_callback)
203+
bool: True if successful (when using outfile or chunk_callback)
204204
205205
Raises:
206+
ImportError: If aiohttp module is not available
207+
RuntimeError: If HTTP request fails (status code < 200 or >= 400)
208+
OSError: If chunk download times out after retries or network connection is lost
206209
ValueError: If both outfile and chunk_callback are provided
210+
Exception: Other download errors (propagated from aiohttp or chunk processing)
207211
208212
Example:
209213
# Download to memory
@@ -247,7 +251,7 @@ async def on_chunk(chunk):
247251
session = _get_session()
248252
if session is None:
249253
print("DownloadManager: Cannot download, aiohttp not available")
250-
return False if (outfile or chunk_callback) else None
254+
raise ImportError("aiohttp module not available")
251255

252256
# Increment refcount
253257
global _session_refcount
@@ -268,7 +272,7 @@ async def on_chunk(chunk):
268272
async with session.get(url, headers=headers) as response:
269273
if response.status < 200 or response.status >= 400:
270274
print(f"DownloadManager: HTTP error {response.status}")
271-
return False if (outfile or chunk_callback) else None
275+
raise RuntimeError(f"HTTP {response.status}")
272276

273277
# Figure out total size
274278
print("DownloadManager: Response headers:", response.headers)
@@ -332,7 +336,7 @@ async def on_chunk(chunk):
332336
print("DownloadManager: ERROR: failed to download chunk after retries!")
333337
if fd:
334338
fd.close()
335-
return False if (outfile or chunk_callback) else None
339+
raise OSError(-110, "Failed to download chunk after retries")
336340

337341
if chunk_data:
338342
# Output chunk
@@ -384,7 +388,7 @@ async def on_chunk(chunk):
384388
print(f"DownloadManager: Exception during download: {e}")
385389
if fd:
386390
fd.close()
387-
return False if (outfile or chunk_callback) else None
391+
raise # Re-raise the exception instead of suppressing it
388392
finally:
389393
# Decrement refcount
390394
if _session_lock:

tests/test_download_manager.py

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -249,28 +249,31 @@ def test_http_error_status(self):
249249
import asyncio
250250

251251
async def run_test():
252-
# Request 404 error from httpbin
253-
data = await DownloadManager.download_url("https://httpbin.org/status/404")
252+
# Request 404 error from httpbin - should raise RuntimeError
253+
with self.assertRaises(RuntimeError) as context:
254+
data = await DownloadManager.download_url("https://httpbin.org/status/404")
254255

255-
# Should return None for memory download
256-
self.assertIsNone(data)
256+
# Should raise RuntimeError with status code
257+
self.assertIn("404", str(context.exception))
257258

258259
asyncio.run(run_test())
259260

260261
def test_http_error_with_file_output(self):
261-
"""Test that file download returns False on HTTP error."""
262+
"""Test that file download raises exception on HTTP error."""
262263
import asyncio
263264

264265
async def run_test():
265266
outfile = f"{self.temp_dir}/error_test.bin"
266267

267-
success = await DownloadManager.download_url(
268-
"https://httpbin.org/status/500",
269-
outfile=outfile
270-
)
268+
# Should raise RuntimeError for HTTP 500
269+
with self.assertRaises(RuntimeError) as context:
270+
success = await DownloadManager.download_url(
271+
"https://httpbin.org/status/500",
272+
outfile=outfile
273+
)
271274

272-
# Should return False for file download
273-
self.assertFalse(success)
275+
# Should raise RuntimeError with status code
276+
self.assertIn("500", str(context.exception))
274277

275278
# File should not be created
276279
try:
@@ -286,14 +289,9 @@ def test_invalid_url(self):
286289
import asyncio
287290

288291
async def run_test():
289-
# Invalid URL should raise exception or return None
290-
try:
292+
# Invalid URL should raise an exception
293+
with self.assertRaises(Exception):
291294
data = await DownloadManager.download_url("http://invalid-url-that-does-not-exist.local/")
292-
# If it doesn't raise, it should return None
293-
self.assertIsNone(data)
294-
except Exception:
295-
# Exception is acceptable
296-
pass
297295

298296
asyncio.run(run_test())
299297

@@ -372,16 +370,12 @@ async def run_test():
372370
# Try to download to non-existent directory
373371
outfile = "/tmp/nonexistent_dir_12345/test.bin"
374372

375-
try:
373+
# Should raise exception because directory doesn't exist
374+
with self.assertRaises(Exception):
376375
success = await DownloadManager.download_url(
377376
"https://httpbin.org/bytes/100",
378377
outfile=outfile
379378
)
380-
# Should fail because directory doesn't exist
381-
self.assertFalse(success)
382-
except Exception:
383-
# Exception is acceptable
384-
pass
385379

386380
asyncio.run(run_test())
387381

0 commit comments

Comments
 (0)