1+ package com .foxdebug .acode .rk .exec .terminal ;
2+
3+ import org .apache .cordova .*;
4+ import org .json .*;
5+ import java .io .*;
6+ import java .util .*;
7+ import java .util .concurrent .*;
8+
9+ public class BackgroundExecutor extends CordovaPlugin {
10+
11+ private final Map <String , Process > processes = new ConcurrentHashMap <>();
12+ private final Map <String , OutputStream > processInputs = new ConcurrentHashMap <>();
13+ private final Map <String , CallbackContext > processCallbacks = new ConcurrentHashMap <>();
14+ private ProcessManager processManager ;
15+
16+ @ Override
17+ public void initialize (CordovaInterface cordova , CordovaWebView webView ) {
18+ super .initialize (cordova , webView );
19+ this .processManager = new ProcessManager (cordova .getContext ());
20+ }
21+
22+ @ Override
23+ public boolean execute (String action , JSONArray args , CallbackContext callbackContext ) throws JSONException {
24+ switch (action ) {
25+ case "start" :
26+ String pid = UUID .randomUUID ().toString ();
27+ startProcess (pid , args .getString (0 ), args .getString (1 ).equals ("true" ), callbackContext );
28+ return true ;
29+ case "write" :
30+ writeToProcess (args .getString (0 ), args .getString (1 ), callbackContext );
31+ return true ;
32+ case "stop" :
33+ stopProcess (args .getString (0 ), callbackContext );
34+ return true ;
35+ case "exec" :
36+ exec (args .getString (0 ), args .getString (1 ).equals ("true" ), callbackContext );
37+ return true ;
38+ case "isRunning" :
39+ isProcessRunning (args .getString (0 ), callbackContext );
40+ return true ;
41+ case "loadLibrary" :
42+ loadLibrary (args .getString (0 ), callbackContext );
43+ return true ;
44+ default :
45+ callbackContext .error ("Unknown action: " + action );
46+ return false ;
47+ }
48+ }
49+
50+ private void exec (String cmd , boolean useAlpine , CallbackContext callbackContext ) {
51+ cordova .getThreadPool ().execute (() -> {
52+ try {
53+ ProcessManager .ExecResult result = processManager .executeCommand (cmd , useAlpine );
54+
55+ if (result .isSuccess ()) {
56+ callbackContext .success (result .stdout );
57+ } else {
58+ callbackContext .error (result .getErrorMessage ());
59+ }
60+ } catch (Exception e ) {
61+ callbackContext .error ("Exception: " + e .getMessage ());
62+ }
63+ });
64+ }
65+
66+ private void startProcess (String pid , String cmd , boolean useAlpine , CallbackContext callbackContext ) {
67+ cordova .getThreadPool ().execute (() -> {
68+ try {
69+ ProcessBuilder builder = processManager .createProcessBuilder (cmd , useAlpine );
70+ Process process = builder .start ();
71+
72+ processes .put (pid , process );
73+ processInputs .put (pid , process .getOutputStream ());
74+ processCallbacks .put (pid , callbackContext );
75+
76+ sendPluginResult (callbackContext , pid , true );
77+
78+ // Stream stdout
79+ new Thread (() -> StreamHandler .streamOutput (
80+ process .getInputStream (),
81+ line -> sendPluginMessage (pid , "stdout:" + line )
82+ )).start ();
83+
84+ // Stream stderr
85+ new Thread (() -> StreamHandler .streamOutput (
86+ process .getErrorStream (),
87+ line -> sendPluginMessage (pid , "stderr:" + line )
88+ )).start ();
89+
90+ int exitCode = process .waitFor ();
91+ sendPluginMessage (pid , "exit:" + exitCode );
92+ cleanup (pid );
93+ } catch (Exception e ) {
94+ callbackContext .error ("Failed to start process: " + e .getMessage ());
95+ }
96+ });
97+ }
98+
99+ private void writeToProcess (String pid , String input , CallbackContext callbackContext ) {
100+ try {
101+ OutputStream os = processInputs .get (pid );
102+ if (os != null ) {
103+ StreamHandler .writeToStream (os , input );
104+ callbackContext .success ("Written to process" );
105+ } else {
106+ callbackContext .error ("Process not found or closed" );
107+ }
108+ } catch (IOException e ) {
109+ callbackContext .error ("Write error: " + e .getMessage ());
110+ }
111+ }
112+
113+ private void stopProcess (String pid , CallbackContext callbackContext ) {
114+ Process process = processes .get (pid );
115+ if (process != null ) {
116+ ProcessUtils .killProcessTree (process );
117+ cleanup (pid );
118+ callbackContext .success ("Process terminated" );
119+ } else {
120+ callbackContext .error ("No such process" );
121+ }
122+ }
123+
124+ private void isProcessRunning (String pid , CallbackContext callbackContext ) {
125+ Process process = processes .get (pid );
126+
127+ if (process != null ) {
128+ String status = ProcessUtils .isAlive (process ) ? "running" : "exited" ;
129+ if (status .equals ("exited" )) cleanup (pid );
130+ callbackContext .success (status );
131+ } else {
132+ callbackContext .success ("not_found" );
133+ }
134+ }
135+
136+ private void loadLibrary (String path , CallbackContext callbackContext ) {
137+ try {
138+ System .load (path );
139+ callbackContext .success ("Library loaded successfully." );
140+ } catch (Exception e ) {
141+ callbackContext .error ("Failed to load library: " + e .getMessage ());
142+ }
143+ }
144+
145+ private void sendPluginResult (CallbackContext ctx , String message , boolean keepCallback ) {
146+ PluginResult result = new PluginResult (PluginResult .Status .OK , message );
147+ result .setKeepCallback (keepCallback );
148+ ctx .sendPluginResult (result );
149+ }
150+
151+ private void sendPluginMessage (String pid , String message ) {
152+ CallbackContext ctx = processCallbacks .get (pid );
153+ if (ctx != null ) {
154+ sendPluginResult (ctx , message , true );
155+ }
156+ }
157+
158+ private void cleanup (String pid ) {
159+ processes .remove (pid );
160+ processInputs .remove (pid );
161+ processCallbacks .remove (pid );
162+ }
163+ }
0 commit comments