1919from pymobiledevice3 .lockdown import create_using_usbmux
2020import plistlib
2121
22- active_debug_server : dict [int , tuple [LockdownTcpForwarder , Thread ]] = {}
23- active_usbmux_forwarder : dict [int , tuple [UsbmuxTcpForwarder , Thread ]] = {}
24-
2522class WriteDispatcher :
26- def __init__ (self , writer ):
27- self .writer = writer
23+ def __init__ (self ):
2824 self .write_queue = queue .Queue ()
2925 self .shutdown_event = threading .Event ()
3026 self .write_thread = threading .Thread (target = self ._write_worker , daemon = True )
@@ -34,31 +30,36 @@ def _write_worker(self):
3430 try :
3531 while True :
3632 try :
37- message = self .write_queue .get ()
33+ writer , message = self .write_queue .get ()
3834 if message is None :
3935 break
4036
41- self . writer .write (str (message ))
42- self . writer .write ("\n " )
43- self . writer .flush ()
37+ writer .write (str (message ))
38+ writer .write ("\n " )
39+ writer .flush ()
4440
4541 except Exception as e :
4642 print (f"Write thread error: { e } " )
47- break
43+ continue
4844 finally :
4945 self .shutdown_event .set ()
5046
51- def write_reply (self , reply : dict ):
47+ def write_reply (self , writer , reply : dict ):
5248 if self .shutdown_event .is_set ():
5349 return
54- print ("Sending packet: " + str (reply ))
55- self .write_queue .put (reply )
50+ print ("Sending packet: " + str (reply ) + " to " + str ( writer . fileno ()) )
51+ self .write_queue .put (( writer , reply ) )
5652
5753 def shutdown (self ):
5854 self .write_queue .put (None )
5955 self .write_thread .join ()
6056
6157
58+ active_debug_server : dict [int , tuple [LockdownTcpForwarder , Thread ]] = {}
59+ active_usbmux_forwarder : dict [int , tuple [UsbmuxTcpForwarder , Thread ]] = {}
60+ write_dispatcher = WriteDispatcher ()
61+
62+
6263def list_devices (id , writer ):
6364 devices = []
6465 for device in usbmux .list_devices ():
@@ -69,9 +70,7 @@ def list_devices(id, writer):
6970
7071 reply = {"id" : id , "state" : "completed" , "result" : devices }
7172
72- print ("Collected results: " + str (reply ))
73-
74- writer .write_reply (reply )
73+ write_dispatcher .write_reply (writer , reply )
7574
7675def list_devices_udid (id , writer ):
7776 devices = []
@@ -80,26 +79,24 @@ def list_devices_udid(id, writer):
8079
8180 reply = {"id" : id , "state" : "completed" , "result" : devices }
8281
83- print ("Collected results: " + str (reply ))
84-
85- writer .write_reply (reply )
82+ write_dispatcher .write_reply (writer , reply )
8683
8784def get_device (id , device_id , writer ):
8885 try :
8986 with create_using_usbmux (device_id , autopair = False ) as lockdown :
9087 reply = {"id" : id , "state" : "completed" , "result" : lockdown .short_info }
91- writer .write_reply (reply )
88+ write_dispatcher .write_reply (writer , reply )
9289 except NoDeviceConnectedError | DeviceNotFoundError :
9390 reply = {"id" : id , "state" : "failed_expected" }
94- writer .write_reply (reply )
91+ write_dispatcher .write_reply (writer , reply )
9592
9693def install_app (id , lockdown_client , path , mode , writer ):
9794 with InstallationProxyService (lockdown = lockdown_client ) as installer :
9895 options = {"PackageType" : "Developer" }
9996
10097 def progress_handler (progress , * args ):
10198 reply = {"id" : id , "state" : "progress" , "progress" : progress }
102- writer .write_reply (reply )
99+ write_dispatcher .write_reply (writer , reply )
103100 return
104101
105102 if mode == "INSTALL" :
@@ -119,15 +116,15 @@ def progress_handler(progress, *args):
119116 res = installer .lookup (options = {"BundleIDs" : [bundle_identifier ]})
120117
121118 reply = {"id" : id , "state" : "completed" , "result" : res [bundle_identifier ]["Path" ]}
122- writer .write_reply (reply )
119+ write_dispatcher .write_reply (writer , reply )
123120
124121 print ("Installed bundle: " + str (bundle_identifier ))
125122
126123def decode_plist (id , path , writer ):
127124 with open (path , 'rb' ) as f :
128125 plist_data = plistlib .load (f )
129126 reply = {"id" : id , "state" : "completed" , "result" : plist_data }
130- writer .write_reply (reply )
127+ write_dispatcher .write_reply (writer , reply )
131128 return
132129
133130def auto_mount_image (id , lockdown , writer ):
@@ -136,7 +133,7 @@ def auto_mount_image(id, lockdown, writer):
136133 except AlreadyMountedError :
137134 pass
138135 reply = {"id" : id , "state" : "completed" }
139- writer .write_reply (reply )
136+ write_dispatcher .write_reply (writer , reply )
140137
141138
142139def debugserver_connect (id , lockdown , port , writer ):
@@ -146,7 +143,7 @@ def debugserver_connect(id, lockdown, port, writer):
146143 raise TunneldConnectionError ()
147144 except TunneldConnectionError :
148145 reply = {"id" :id , "state" : "failed_tunneld" }
149- writer .write_reply (reply )
146+ write_dispatcher .write_reply (writer , reply )
150147 return
151148
152149 if Version (discovery_service .product_version ) < Version ('17.0' ):
@@ -171,7 +168,7 @@ def forwarder_thread():
171168 "host" : "127.0.0.1" ,
172169 "port" : selected_port
173170 }}
174- writer .write_reply (reply )
171+ write_dispatcher .write_reply (writer , reply )
175172
176173
177174def debugserver_close (id , port , writer ):
@@ -184,7 +181,7 @@ def debugserver_close(id, port, writer):
184181 print (f"Joining debugserver thread { port } timed out" )
185182
186183 reply = {"id" : id , "state" : "completed" }
187- writer .write_reply (reply )
184+ write_dispatcher .write_reply (writer , reply )
188185
189186
190187def usbmux_forward_open (id , udid , remote_port , local_port , writer ):
@@ -208,7 +205,7 @@ def forwarder_thread():
208205 "local_port" : selected_port ,
209206 "remote_port" : remote_port
210207 }}
211- writer .write_reply (reply )
208+ write_dispatcher .write_reply (writer , reply )
212209
213210
214211def usbmux_forward_close (id , local_port , writer ):
@@ -221,7 +218,7 @@ def usbmux_forward_close(id, local_port, writer):
221218 print (f"Joining usbmux thread { local_port } timed out" )
222219
223220 reply = {"id" : id , "state" : "completed" }
224- writer .write_reply (reply )
221+ write_dispatcher .write_reply (writer , reply )
225222
226223
227224def main ():
@@ -237,8 +234,6 @@ def main():
237234 reader = sock .makefile ('r' )
238235 writer = sock .makefile ('w' )
239236
240- write_dispatcher = WriteDispatcher (writer )
241-
242237 while True :
243238 command = reader .readline ().strip ()
244239 if not command :
@@ -257,44 +252,44 @@ def main():
257252 sock .close ()
258253 sys .exit (0 )
259254 elif command_type == "list_devices" :
260- list_devices (id , write_dispatcher )
255+ list_devices (id , writer )
261256 continue
262257 elif command_type == "list_devices_udid" :
263- list_devices_udid (id , write_dispatcher )
258+ list_devices_udid (id , writer )
264259 continue
265260 elif command_type == "get_device" :
266261 device_id = res ['device_id' ] if 'device_id' in res else None
267- get_device (id , device_id , write_dispatcher )
262+ get_device (id , device_id , writer )
268263 continue
269264 elif command_type == "decode_plist" :
270- decode_plist (id , res ['plist_path' ], write_dispatcher )
265+ decode_plist (id , res ['plist_path' ], writer )
271266 continue
272267 elif command_type == "debugserver_close" :
273- debugserver_close (id , res ['port' ], write_dispatcher )
268+ debugserver_close (id , res ['port' ], writer )
274269 continue
275270 elif command_type == "usbmux_forwarder_open" :
276- usbmux_forward_open (id , res ['device_id' ], res ['remote_port' ], res ['local_port' ], write_dispatcher )
271+ usbmux_forward_open (id , res ['device_id' ], res ['remote_port' ], res ['local_port' ], writer )
277272 continue
278273 elif command_type == "usbmux_forwarder_close" :
279- usbmux_forward_close (id , res ['local_port' ], write_dispatcher )
274+ usbmux_forward_close (id , res ['local_port' ], writer )
280275 continue
281276
282277 # Now come the device targetted functions
283278 device_id = res ['device_id' ]
284279 with create_using_usbmux (device_id ) as lockdown :
285280 if command_type == "install_app" :
286- install_app (id , lockdown , res ['app_path' ], res ['install_mode' ], write_dispatcher )
281+ install_app (id , lockdown , res ['app_path' ], res ['install_mode' ], writer )
287282 continue
288283 elif command_type == "auto_mount_image" :
289- auto_mount_image (id , lockdown , write_dispatcher )
284+ auto_mount_image (id , lockdown , writer )
290285 continue
291286 elif command_type == "debugserver_connect" :
292287 port = res ['port' ] if 'port' in res else 0
293- debugserver_connect (id , lockdown , port , write_dispatcher )
288+ debugserver_connect (id , lockdown , port , writer )
294289 continue
295290
296291 except Exception as e :
297292 reply = {"request" : command , "state" : "failed" , "error" : repr (e ), "backtrace" : traceback .format_exc ()}
298- write_dispatcher .write_reply (reply )
293+ write_dispatcher .write_reply (writer , reply )
299294
300295main ()
0 commit comments