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