1414from rich .progress import (
1515 DownloadColumn ,
1616 Progress ,
17+ TaskID ,
1718 TransferSpeedColumn ,
1819)
1920from rich .status import Status
@@ -83,6 +84,10 @@ def __init__(self, args):
8384 self ._app_id = app_meta ["id" ]
8485 self ._new_ver = app_meta ["version" ]
8586 self ._board_crc = crc16_ccitt (app_meta ["board" ].encode ("utf-8" ))
87+ self ._state_connecting : set [int ] = set ()
88+ self ._state_copying : set [int ] = set ()
89+ self ._state_uploading : set [int ] = set ()
90+ self ._tasks : dict [LocalClient , TaskID ] = {}
8691 self ._handled : list [int ] = []
8792 self ._pending : dict [int , float ] = {}
8893 self ._missing_diffs : set [str ] = set ()
@@ -97,7 +102,6 @@ def __init__(self, args):
97102 DownloadColumn (),
98103 TransferSpeedColumn (),
99104 )
100- self .task = None
101105 if args .log is None :
102106 self ._log = None
103107 else :
@@ -127,6 +131,10 @@ def add_parser(cls, parser):
127131
128132 add_server_port_parser (parser )
129133
134+ @property
135+ def _actioning (self ) -> set [int ]:
136+ return self ._state_connecting | self ._state_copying | self ._state_uploading
137+
130138 def progress_table (self ):
131139 table = Table ()
132140 table .add_column (f"{ self ._app_name } \n { self ._new_ver } " )
@@ -144,7 +152,15 @@ def progress_table(self):
144152 meta = Table (box = None )
145153 meta .add_column ()
146154 meta .add_row (table )
147- meta .add_row (Status (self .state ))
155+ if self ._state_connecting :
156+ meta .add_row (Status (f"Connecting to: { ', ' .join (f'{ i :016X} ' for i in self ._state_connecting )} " ))
157+ if self ._state_copying or self ._state_uploading :
158+ meta .add_row (Status (f"Writing patch file: { ', ' .join (
159+ f'{ i :016X} ' for i in self ._state_copying | self ._state_uploading )} " )
160+ )
161+
162+ if not (self ._state_connecting or self ._state_copying or self ._state_uploading ):
163+ meta .add_row (Status (self .state ))
148164 meta .add_row (self .progress )
149165
150166 return meta
@@ -153,11 +169,12 @@ def state_update(self, live: Live, state: str):
153169 self .state = state
154170 live .update (self .progress_table ())
155171
156- def data_progress_cb (self , offset ):
157- if self .task is None :
158- self .state = "Writing patch file"
159- self .task = self .progress .add_task ("" , total = len (self .patch_file ))
160- self .progress .update (self .task , completed = offset )
172+ def data_progress_cb (self , offset , client : LocalClient ):
173+ task = self ._tasks .get (client )
174+ if task is None :
175+ task = self .progress .add_task ("" , total = len (self .patch_file ))
176+ self ._tasks [client ] = task
177+ self .progress .update (task , completed = offset )
161178
162179 def gateway_diff_load (self , client : LocalClient ):
163180 assert self ._single_diff is not None
@@ -183,57 +200,68 @@ def gateway_diff_load(self, client: LocalClient):
183200 print (f"'{ self ._single_diff } ' written to gateway" )
184201
185202 def run_file_upload (self , live : Live , mtu : int , source : HopReceived , client : LocalClient ):
186- self .state_update (live , f"Uploading patch file to { source .infuse_id :016X} " )
187- rpc_client = RpcClient (client , mtu , source .infuse_id )
188-
189- params = file_write_basic .request (rpc_enum_file_action .APP_CPATCH , binascii .crc32 (self .patch_file ))
190-
191- hdr , _rsp = rpc_client .run_data_send_cmd (
192- file_write_basic .COMMAND_ID ,
193- Auth .DEVICE ,
194- bytes (params ),
195- self .patch_file ,
196- self .data_progress_cb ,
197- file_write_basic .response .from_buffer_copy ,
198- )
203+ try :
204+ self ._state_uploading .add (source .infuse_id )
205+ live .update (self .progress_table ())
206+ # self.state_update(live, f"Uploading patch file to {source.infuse_id:016X}")
207+ rpc_client = RpcClient (client , mtu , source .infuse_id )
208+
209+ params = file_write_basic .request (rpc_enum_file_action .APP_CPATCH , binascii .crc32 (self .patch_file ))
199210
200- if hdr is None :
201- self ._failed += 1
202- elif hdr .return_code == 0 :
203- self ._pending [source .infuse_id ] = time .time () + 60
211+ hdr , _rsp = rpc_client .run_data_send_cmd (
212+ file_write_basic .COMMAND_ID ,
213+ Auth .DEVICE ,
214+ bytes (params ),
215+ self .patch_file ,
216+ lambda offset : self .data_progress_cb (offset , client ),
217+ file_write_basic .response .from_buffer_copy ,
218+ )
219+
220+ if hdr is None :
221+ self ._failed += 1
222+ elif hdr .return_code == 0 :
223+ self ._pending [source .infuse_id ] = time .time () + 60
224+ finally :
225+ self ._state_uploading .remove (source .infuse_id )
226+ live .update (self .progress_table ())
204227
205228 def run_file_copy (self , live : Live , mtu : int , source : HopReceived , client : LocalClient ):
206- self .state_update (live , f"Copying patch file to { source .infuse_id :016X} " )
207- rpc_client = RpcClient (client , mtu , InfuseID .GATEWAY )
208-
209- params = bt_file_copy_basic .request (
210- source .interface_address .val .to_rpc_struct (),
211- rpc_enum_file_action .APP_CPATCH ,
212- 0 ,
213- len (self .patch_file ),
214- binascii .crc32 (self .patch_file ),
215- 1 ,
216- 3 ,
217- )
229+ try :
230+ self ._state_uploading .add (source .infuse_id )
231+ live .update (self .progress_table ())
232+ rpc_client = RpcClient (client , mtu , InfuseID .GATEWAY )
233+
234+ params = bt_file_copy_basic .request (
235+ source .interface_address .val .to_rpc_struct (),
236+ rpc_enum_file_action .APP_CPATCH ,
237+ 0 ,
238+ len (self .patch_file ),
239+ binascii .crc32 (self .patch_file ),
240+ 1 ,
241+ 3 ,
242+ )
218243
219- hdr , _rsp = rpc_client .run_standard_cmd (
220- bt_file_copy_basic .COMMAND_ID ,
221- Auth .DEVICE ,
222- bytes (params ),
223- bt_file_copy_basic .response .from_buffer_copy ,
224- )
225- if hdr is None :
226- self ._failed += 1
227- elif hdr .return_code == 0 :
228- self ._pending [source .infuse_id ] = time .time () + 60
229- elif hdr .return_code < 0 :
230- sock_name = client ._input_sock .getsockname ()
231- err = errno .strerror (- hdr .return_code )
232- print (f"{ sock_name } Failed to copy patch file to { source .infuse_id :016X} ({ err } )" )
244+ hdr , _rsp = rpc_client .run_standard_cmd (
245+ bt_file_copy_basic .COMMAND_ID ,
246+ Auth .DEVICE ,
247+ bytes (params ),
248+ bt_file_copy_basic .response .from_buffer_copy ,
249+ )
250+ if hdr is None :
251+ self ._failed += 1
252+ elif hdr .return_code == 0 :
253+ self ._pending [source .infuse_id ] = time .time () + 60
254+ elif hdr .return_code < 0 :
255+ sock_name = client ._input_sock .getsockname ()
256+ err = errno .strerror (- hdr .return_code )
257+ print (f"{ sock_name } Failed to copy patch file to { source .infuse_id :016X} ({ err } )" )
258+ finally :
259+ self ._state_uploading .remove (source .infuse_id )
260+ live .update (self .progress_table ())
233261
234262 def run_thread (self , live : Live , client : LocalClient ):
235263 for source , announce in client .observe_announce ():
236- self .state_update ( live , "Scanning" )
264+ live . update ( self .progress_table () )
237265 if len (self ._explicit_ids ):
238266 if source .infuse_id not in self ._explicit_ids :
239267 continue
@@ -275,7 +303,7 @@ def run_thread(self, live: Live, client: LocalClient):
275303 if v_str == self ._new_ver and announce .application == self ._app_id :
276304 self ._handled .append (source .infuse_id )
277305 self ._already += 1
278- self .state_update ( live , "Scanning" )
306+ live . update ( self .progress_table () )
279307 if self ._log :
280308 self ._log .write (
281309 f"{ time .time ()} ,0x{ source .infuse_id :016x} ,0x{ self ._app_id :08x} ,{ v_str } ,already\n "
@@ -293,15 +321,15 @@ def run_thread(self, live: Live, client: LocalClient):
293321 self ._missing_diffs .add (v_str )
294322 self ._handled .append (source .infuse_id )
295323 self ._no_diff += 1
296- self .state_update ( live , "Scanning" )
324+ live . update ( self .progress_table () )
297325 continue
298326
299327 if self ._single_diff and self ._single_diff != diff_file :
300328 # Not the file we've copied to the gateway flash
301329 self ._missing_diffs .add (v_str )
302330 self ._handled .append (source .infuse_id )
303331 self ._no_diff += 1
304- self .state_update ( live , "Scanning" )
332+ live . update ( self .progress_table () )
305333 continue
306334
307335 # Is signal strong enough to connect?
@@ -312,27 +340,32 @@ def run_thread(self, live: Live, client: LocalClient):
312340 with open (diff_file , "rb" ) as f :
313341 self .patch_file = f .read ()
314342
343+ if source .infuse_id in self ._actioning :
344+ continue
345+
315346 # Attempt to upload
316- self .state_update (live , f"Connecting to { source .infuse_id :016X} " )
347+ self ._state_connecting .add (source .infuse_id )
348+ live .update (self .progress_table ())
317349 try :
318350 with client .connection (
319351 source .infuse_id , GatewayRequestConnectionRequest .DataType .COMMAND , self ._conn_timeout
320352 ) as mtu :
353+ self ._state_connecting .remove (source .infuse_id )
321354 if self ._single_diff :
322355 self .run_file_copy (live , mtu , source , client )
323356 else :
324357 self .run_file_upload (live , mtu , source , client )
325358
326359 except ConnectionRefusedError :
327- self .state_update ( live , "Scanning" )
360+ self ._state_connecting . remove ( source . infuse_id )
328361 except ConnectionAbortedError :
329- self .state_update (live , "Scanning" )
330-
331- if self .task is not None :
332- self .progress .remove_task (self .task )
333- self .task = None
362+ if source .infuse_id in self ._state_connecting :
363+ self ._state_connecting .remove (source .infuse_id )
334364
335- self .state_update (live , "Scanning" )
365+ if client in self ._tasks :
366+ self .progress .remove_task (self ._tasks [client ])
367+ del self ._tasks [client ]
368+ live .update (self .progress_table ())
336369
337370 def run (self ):
338371 if not self ._client .comms_check ():
0 commit comments