11package io .github .berstanio .pymobiledevice3 .ipc ;
22
3+ import io .github .berstanio .pymobiledevice3 .daemon .DaemonHandler ;
34import io .github .berstanio .pymobiledevice3 .data .DebugServerConnection ;
4- import io .github .berstanio .pymobiledevice3 .data .PyMobileDevice3Error ;
55import io .github .berstanio .pymobiledevice3 .data .DeviceInfo ;
66import io .github .berstanio .pymobiledevice3 .data .InstallMode ;
7+ import io .github .berstanio .pymobiledevice3 .data .PyMobileDevice3Error ;
78import io .github .berstanio .pymobiledevice3 .data .USBMuxForwarder ;
89import io .github .berstanio .pymobiledevice3 .venv .PyInstallation ;
910import io .github .berstanio .pymobiledevice3 .venv .PyInstallationHandler ;
1617import java .io .IOException ;
1718import java .io .InputStreamReader ;
1819import java .io .PrintWriter ;
19- import java .net .InetAddress ;
20- import java .net .ServerSocket ;
2120import java .net .Socket ;
22- import java .nio .charset .StandardCharsets ;
2321import java .util .concurrent .ArrayBlockingQueue ;
2422import java .util .concurrent .CompletableFuture ;
2523import java .util .concurrent .ConcurrentHashMap ;
@@ -32,9 +30,6 @@ public class PyMobileDevice3IPC implements Closeable {
3230
3331 private static final boolean DEBUG = System .getProperty ("java.pymobiledevice3.debug" ) != null ;
3432
35- private final PyInstallation installation ;
36- private final Process process ;
37- private final ServerSocket serverSocket ;
3833 private final Socket socket ;
3934 private final BufferedReader reader ;
4035 private final PrintWriter writer ;
@@ -48,21 +43,12 @@ public class PyMobileDevice3IPC implements Closeable {
4843
4944 private boolean destroyed = false ;
5045
51- public PyMobileDevice3IPC (PyInstallation installation ) throws IOException {
52- this .installation = installation ;
53- serverSocket = new ServerSocket (0 , 50 , InetAddress .getByName ("localhost" ));
54- int port = serverSocket .getLocalPort ();
55- ProcessBuilder pb = new ProcessBuilder ()
56- .command (installation .getPythonExecutable ().getAbsolutePath () , "-u" , installation .getHandler ().getAbsolutePath (), String .valueOf (port ));
57-
58- if (DEBUG )
59- pb .inheritIO ();
60- else
61- pb .redirectErrorStream (true );
62-
63- process = pb .start ();
46+ public PyMobileDevice3IPC () throws IOException {
47+ Socket daemonSocket = DaemonHandler .getDaemonSocket ();
48+ if (daemonSocket == null )
49+ throw new IllegalStateException ("Daemon is not running" );
6450
65- socket = serverSocket . accept () ;
51+ socket = daemonSocket ;
6652 reader = new BufferedReader (new InputStreamReader (socket .getInputStream ()));
6753 writer = new PrintWriter (socket .getOutputStream (), true );
6854
@@ -84,9 +70,8 @@ public PyMobileDevice3IPC(PyInstallation installation) throws IOException {
8470 try {
8571 String line = reader .readLine ();
8672 if (line == null ) {
87- String log = new String (process .getInputStream ().readAllBytes (), StandardCharsets .UTF_8 );
8873 for (CompletableFuture <?> future : futures .values ()) {
89- future .completeExceptionally (new PyMobileDevice3Error ("Python process died: " + log ));
74+ future .completeExceptionally (new PyMobileDevice3Error ("Python process died" ));
9075 }
9176
9277 close ();
@@ -257,7 +242,7 @@ public CompletableFuture<DebugServerConnection> debugServerConnect(DeviceInfo in
257242 object .put ("port" , port );
258243 return createRequest (object , (future , jsonObject ) -> {
259244 if (jsonObject .getString ("state" ).equals ("failed_tunneld" )) {
260- future .completeExceptionally (new PyMobileDevice3Error ("No tunneld instance for device " + info .getUniqueDeviceId () + " found. Have you started the service with `sudo " + installation . getPythonExecutable (). getAbsolutePath () + " -m pymobiledevice3 remote tunneld`? " ));
245+ future .completeExceptionally (new PyMobileDevice3Error ("No tunneld instance for device " + info .getUniqueDeviceId () + " found." ));
261246 return ;
262247 }
263248 JSONObject result = jsonObject .getJSONObject ("result" );
@@ -296,9 +281,19 @@ public CompletableFuture<Void> usbMuxForwarderClose(USBMuxForwarder connection)
296281 });
297282 }
298283
284+ public CompletableFuture <Void > forceKillDaemon () {
285+ JSONObject object = new JSONObject ();
286+ object .put ("id" , commandId .getAndIncrement ());
287+ object .put ("command" , "exit" );
288+ if (!writeQueue .offer (object .toString ()))
289+ return CompletableFuture .failedFuture (new PyMobileDevice3Error ("Write queue overflow" ));
290+ return CompletableFuture .completedFuture (null );
291+ }
292+
299293 public static void main (String [] args ) throws IOException {
300294 PyInstallation installation = PyInstallationHandler .install (new File ("build/pyenv/" ));
301- try (PyMobileDevice3IPC ipc = new PyMobileDevice3IPC (installation )) {
295+ DaemonHandler .startDaemon (installation );
296+ try (PyMobileDevice3IPC ipc = new PyMobileDevice3IPC ()) {
302297 //JSONObject object = ipc.decodePList(new File("/Volumes/ExternalSSD/IdeaProjects/MOE-Upstream/moe/samples-java/Calculator/ios/build/moe/xcodebuild/Release-iphoneos/ios.app/Info.plist")).join();
303298 //System.out.println(object.getString("CFBundleExecutable"));
304299 //for (DeviceInfo info : ipc.listDevices().join())
@@ -308,6 +303,8 @@ public static void main(String[] args) throws IOException {
308303 DebugServerConnection connection = ipc .debugServerConnect (info , 0 ).join ();
309304
310305 ipc .debugServerClose (connection ).join ();
306+
307+ ipc .forceKillDaemon ().join ();
311308 }
312309 }
313310
@@ -322,9 +319,6 @@ public void close() {
322319 writeThread .join ();
323320
324321 socket .close ();
325- serverSocket .close ();
326- process .destroyForcibly ();
327- process .onExit ().join ();
328322 commandResults .clear ();
329323 writeQueue .clear ();
330324
0 commit comments