1- import aiohttp
21import lvgl as lv
32import json
43import requests
76
87from mpos .apps import Activity , Intent
98from mpos .app import App
10- from mpos import TaskManager
9+ from mpos import TaskManager , DownloadManager
1110import mpos .ui
1211from mpos .content .package_manager import PackageManager
1312
@@ -28,7 +27,6 @@ class AppStore(Activity):
2827 app_index_url_badgehub = _BADGEHUB_API_BASE_URL + "/" + _BADGEHUB_LIST
2928 app_detail_url_badgehub = _BADGEHUB_API_BASE_URL + "/" + _BADGEHUB_DETAILS
3029 can_check_network = True
31- aiohttp_session = None # one session for the whole app is more performant
3230
3331 # Widgets:
3432 main_screen = None
@@ -39,7 +37,6 @@ class AppStore(Activity):
3937 progress_bar = None
4038
4139 def onCreate (self ):
42- self .aiohttp_session = aiohttp .ClientSession ()
4340 self .main_screen = lv .obj ()
4441 self .please_wait_label = lv .label (self .main_screen )
4542 self .please_wait_label .set_text ("Downloading app index..." )
@@ -62,11 +59,8 @@ def onResume(self, screen):
6259 else :
6360 TaskManager .create_task (self .download_app_index (self .app_index_url_github ))
6461
65- def onDestroy (self , screen ):
66- await self .aiohttp_session .close ()
67-
6862 async def download_app_index (self , json_url ):
69- response = await self .download_url (json_url )
63+ response = await DownloadManager .download_url (json_url )
7064 if not response :
7165 self .please_wait_label .set_text (f"Could not download app index from\n { json_url } " )
7266 return
@@ -152,7 +146,7 @@ async def download_icons(self):
152146 break
153147 if not app .icon_data :
154148 try :
155- app .icon_data = await TaskManager .wait_for (self .download_url (app .icon_url ), 5 ) # max 5 seconds per icon
149+ app .icon_data = await TaskManager .wait_for (DownloadManager .download_url (app .icon_url ), 5 ) # max 5 seconds per icon
156150 except Exception as e :
157151 print (f"Download of { app .icon_url } got exception: { e } " )
158152 continue
@@ -177,96 +171,6 @@ def show_app_detail(self, app):
177171 intent .putExtra ("appstore" , self )
178172 self .startActivity (intent )
179173
180- '''
181- This async download function can be used in 3 ways:
182- - with just a url => returns the content
183- - with a url and an outfile => writes the content to the outfile
184- - with a url and a chunk_callback => calls the chunk_callback(chunk_data) for each chunk
185-
186- Optionally:
187- - progress_callback is called with the % (0-100) progress
188- - if total_size is not provided, it will be taken from the response headers (if present) or default to 100KB
189- - a dict of headers can be passed, for example: headers['Range'] = f'bytes={self.bytes_written_so_far}-'
190-
191- Can return either:
192- - the actual content
193- - None: if the content failed to download
194- - True: if the URL was successfully downloaded (and written to outfile, if provided)
195- - False: if the URL was not successfully download and written to outfile
196- '''
197- async def download_url (self , url , outfile = None , total_size = None , progress_callback = None , chunk_callback = None , headers = None ):
198- print (f"Downloading { url } " )
199- #await TaskManager.sleep(4) # test slowness
200- try :
201- async with self .aiohttp_session .get (url , headers = headers ) as response :
202- if response .status < 200 or response .status >= 400 :
203- return False if outfile else None
204-
205- # Figure out total size
206- print ("headers:" ) ; print (response .headers )
207- if total_size is None :
208- total_size = response .headers .get ('Content-Length' ) # some servers don't send this in the headers
209- if total_size is None :
210- print ("WARNING: Unable to determine total_size from server's reply and function arguments, assuming 100KB" )
211- total_size = 100 * 1024
212-
213- fd = None
214- if outfile :
215- fd = open (outfile , 'wb' )
216- if not fd :
217- print ("WARNING: could not open {outfile} for writing!" )
218- return False
219- chunks = []
220- partial_size = 0
221- chunk_size = 1024
222-
223- print (f"download_url { 'writing to ' + outfile if outfile else 'downloading' } { total_size } bytes in chunks of size { chunk_size } " )
224-
225- while True :
226- tries_left = 3
227- chunk_data = None
228- while tries_left > 0 :
229- try :
230- chunk_data = await TaskManager .wait_for (response .content .read (chunk_size ), 10 )
231- break
232- except Exception as e :
233- print (f"Waiting for response.content.read of next chunk_data got error: { e } " )
234- tries_left -= 1
235-
236- if tries_left == 0 :
237- print ("ERROR: failed to download chunk_data, even with retries!" )
238- if fd :
239- fd .close ()
240- return False if outfile else None
241-
242- if chunk_data :
243- # Output
244- if fd :
245- fd .write (chunk_data )
246- elif chunk_callback :
247- await chunk_callback (chunk_data )
248- else :
249- chunks .append (chunk_data )
250- # Report progress
251- partial_size += len (chunk_data )
252- progress_pct = round ((partial_size * 100 ) / int (total_size ))
253- print (f"progress: { partial_size } / { total_size } bytes = { progress_pct } %" )
254- if progress_callback :
255- await progress_callback (progress_pct )
256- #await TaskManager.sleep(1) # test slowness
257- else :
258- print ("chunk_data is None while there was no error so this was the last one.\n Finished downloading {url}" )
259- if fd :
260- fd .close ()
261- return True
262- elif chunk_callback :
263- return True
264- else :
265- return b'' .join (chunks )
266- except Exception as e :
267- print (f"download_url got exception { e } " )
268- return False if outfile else None
269-
270174 @staticmethod
271175 def badgehub_app_to_mpos_app (bhapp ):
272176 #print(f"Converting {bhapp} to MPOS app object...")
@@ -293,7 +197,7 @@ def badgehub_app_to_mpos_app(bhapp):
293197
294198 async def fetch_badgehub_app_details (self , app_obj ):
295199 details_url = self .app_detail_url_badgehub + "/" + app_obj .fullname
296- response = await self .download_url (details_url )
200+ response = await DownloadManager .download_url (details_url )
297201 if not response :
298202 print (f"Could not download app details from from\n { details_url } " )
299203 return
@@ -578,7 +482,7 @@ async def download_and_install(self, app_obj, dest_folder):
578482 pass
579483 temp_zip_path = "tmp/temp.mpk"
580484 print (f"Downloading .mpk file from: { zip_url } to { temp_zip_path } " )
581- result = await self . appstore .download_url (zip_url , outfile = temp_zip_path , total_size = download_url_size , progress_callback = self .pcb )
485+ result = await DownloadManager .download_url (zip_url , outfile = temp_zip_path , total_size = download_url_size , progress_callback = self .pcb )
582486 if result is not True :
583487 print ("Download failed..." ) # Would be good to show an error to the user if this failed...
584488 else :
0 commit comments