Skip to content

feat: spawn stream support for Executor#1972

Open
RohitKushvaha01 wants to merge 15 commits intoAcode-Foundation:mainfrom
RohitKushvaha01:main
Open

feat: spawn stream support for Executor#1972
RohitKushvaha01 wants to merge 15 commits intoAcode-Foundation:mainfrom
RohitKushvaha01:main

Conversation

@RohitKushvaha01
Copy link
Member

@RohitKushvaha01 RohitKushvaha01 commented Mar 22, 2026

API example

Executor.spawnStream(["sh"], (ws)=>{

  //stdout + stderr
  ws.onmessage = (e)=>{
    const text = new TextDecoder().decode(e.data);
    console.log(text);
  };

  //stdin
  ws.send(new TextEncoder().encode("ls\n"));

});
  • the socket will close if the process exit
  • the process will exit if socket is closed

@RohitKushvaha01 RohitKushvaha01 self-assigned this Mar 22, 2026
@RohitKushvaha01 RohitKushvaha01 marked this pull request as draft March 22, 2026 12:02
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 22, 2026

Greptile Summary

This PR introduces spawn / spawnStream support for the Executor plugin, allowing callers to launch an arbitrary command and communicate with it over a local WebSocket connection. ProcessServer (a new Java-WebSocket–backed WebSocketServer) handles process lifecycle per connection, and startAndAwait() ensures the server is bound before the port is returned to JavaScript.

Key changes:

  • plugin.xml: adds the org.java-websocket:Java-WebSocket:1.6.0 Gradle dependency and registers ProcessServer.java.
  • ProcessServer.java: new file; binds to 127.0.0.1 only, merges stderr via redirectErrorStream(true), propagates startup failures through a CountDownLatch/AtomicReference pair, and avoids the onClose-deadlock via a detached stop() thread.
  • Executor.java: spawn action allocates a free port with ServerSocket(0), constructs a ProcessServer, calls startAndAwait(), then returns the port — correctly placed before the ensureServiceBound guard.
  • Executor.js: spawnStream adds JSDoc, an onError parameter, and a ws.onerror handler.

Remaining issues:

  • java.net.ServerSocket is imported twice on consecutive lines in Executor.java (lines 32–33); this produces a compiler warning and should be deduplicated.
  • e.printStackTrace() in the spawn catch block should be replaced with Log.e("Executor", ..., e) to integrate with Android's logcat.

Confidence Score: 4/5

  • PR is nearly ready to merge — a duplicate import causing a compiler warning is the only blocking fix needed.
  • The vast majority of previously raised concerns (deadlock in onClose, security via loopback-only binding, startup race, missing error propagation, stderr capture, JSDoc, onerror handler) have all been addressed correctly. The two remaining items are a duplicate import that will emit a compiler warning (potentially treated as an error by the build) and a minor logging anti-pattern. Architecture and correctness are sound.
  • src/plugins/terminal/src/android/Executor.java — duplicate import on lines 32–33 should be removed before merging.

Important Files Changed

Filename Overview
src/plugins/terminal/src/android/ProcessServer.java New file implementing WebSocket-based process server; addresses previous concerns (loopback-only binding, deadlock-free shutdown via detached thread, per-connection state, stderr merging, startup latch with error propagation). Minor: missing newline at EOF.
src/plugins/terminal/src/android/Executor.java Adds spawn action that allocates a free port via ServerSocket(0), constructs a ProcessServer, and uses startAndAwait() before returning the port. Duplicate java.net.ServerSocket import on lines 32-33 will generate a compiler warning; e.printStackTrace() should be Log.e.
src/plugins/terminal/www/Executor.js Adds spawnStream with JSDoc, onError parameter, and ws.onerror handler, addressing all previously raised JS-side concerns. "Executor" hardcode confirmed intentional.
src/plugins/terminal/plugin.xml Adds Java-WebSocket 1.6.0 framework dependency and registers ProcessServer.java as a new source file. No issues.

Sequence Diagram

sequenceDiagram
    participant JS as Executor.js
    participant CD as Cordova (execute())
    participant SS as ServerSocket(0)
    participant PS as ProcessServer
    participant WS as WebSocket Client (JS)
    participant PR as Process (cmd)

    JS->>CD: exec("spawn", [cmd])
    CD->>SS: new ServerSocket(0) → port
    SS-->>CD: port (socket closed)
    CD->>PS: new ProcessServer(port, cmd)
    CD->>PS: startAndAwait()
    PS->>PS: start() [background thread]
    PS-->>PS: onStart() → readyLatch.countDown()
    PS-->>CD: await() returns
    CD-->>JS: callbackContext.success(port)
    JS->>WS: new WebSocket("ws://127.0.0.1:port")
    WS->>PS: onOpen(conn)
    PS->>PR: ProcessBuilder(cmd).start()
    PR-->>PS: stdin / stdout streams
    PS->>PS: reader thread → conn.send(bytes)
    Note over WS,PS: stdin writes via ws.send() → onMessage → PR stdin
    Note over PS,PR: stdout bytes streamed back via WebSocket binary frames
    PR-->>PS: stdout EOF → conn.close(1000)
    PS->>PS: onClose → process.destroy()
    PS->>PS: new Thread → stop()
Loading

Reviews (7): Last reviewed commit: "Update src/plugins/terminal/src/android/..." | Re-trigger Greptile

@RohitKushvaha01

This comment was marked as outdated.

@RohitKushvaha01

This comment was marked as outdated.

RohitKushvaha01 and others added 3 commits March 23, 2026 12:36
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
RohitKushvaha01 and others added 2 commits March 23, 2026 13:24
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@RohitKushvaha01

This comment was marked as outdated.

RohitKushvaha01 and others added 3 commits March 23, 2026 13:39
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@RohitKushvaha01

This comment was marked as outdated.

@RohitKushvaha01

This comment was marked as outdated.

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@RohitKushvaha01 RohitKushvaha01 marked this pull request as ready for review March 23, 2026 08:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant