Skip to content

Commit 25ebd5b

Browse files
committed
feat: Make python write thread socket indipendent
1 parent 22a22b8 commit 25ebd5b

File tree

1 file changed

+38
-43
lines changed

1 file changed

+38
-43
lines changed

src/main/resources/handler.py

Lines changed: 38 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,8 @@
1919
from pymobiledevice3.lockdown import create_using_usbmux
2020
import plistlib
2121

22-
active_debug_server: dict[int, tuple[LockdownTcpForwarder, Thread]] = {}
23-
active_usbmux_forwarder: dict[int, tuple[UsbmuxTcpForwarder, Thread]] = {}
24-
2522
class 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+
6263
def 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

7675
def 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

8784
def 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

9693
def 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

126123
def 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

133130
def 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

142139
def 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

177174
def 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

190187
def 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

214211
def 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

227224
def 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

300295
main()

0 commit comments

Comments
 (0)