diff --git a/plugin.xml b/plugin.xml index 8dcb990..ee3cf72 100644 --- a/plugin.xml +++ b/plugin.xml @@ -16,7 +16,9 @@ - + + + @@ -25,54 +27,54 @@ - - + + - - + + - - - + + + - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - + + + + + + diff --git a/src/android/NanoHTTPDWebserver.java b/src/android/NanoHTTPDWebserver.java new file mode 100644 index 0000000..c3c0e97 --- /dev/null +++ b/src/android/NanoHTTPDWebserver.java @@ -0,0 +1,99 @@ +package org.apache.cordova.plugin; + + +import android.annotation.TargetApi; +import android.os.Build; + +import org.apache.cordova.PluginResult; +import org.json.JSONException; +import org.json.JSONObject; + +import fi.iki.elonen.NanoHTTPD; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.util.Iterator; +import java.util.UUID; + +public class NanoHTTPDWebserver extends NanoHTTPD{ + + Webserver webserver; + + public NanoHTTPDWebserver(int port, Webserver webserver) { + super("0.0.0.0", port); + this.webserver = webserver; + } + + /** + * Create a request object + * + * [ + * "requestId": requestUUID, + " body": request.jsonObject ?? "", + " headers": request.headers, + " method": request.method, + " path": request.url.path, + " query": request.url.query ?? "" + ] + * + * @param session + * @return + */ + private JSONObject createJSONRequest(String requestId, IHTTPSession session) throws JSONException { + JSONObject jsonRequest = new JSONObject(); + jsonRequest.put("requestId", requestId); + jsonRequest.put("body", session.getParameters()); + jsonRequest.put("headers", session.getHeaders()); + jsonRequest.put("method", session.getMethod()); + jsonRequest.put("path", session.getUri()); + jsonRequest.put("query", session.getQueryParameterString()); + return jsonRequest; + } + + @Override + public Response serve(IHTTPSession session) { + String requestUUID = UUID.randomUUID().toString(); + + PluginResult pluginResult = null; + try { + pluginResult = new PluginResult( + PluginResult.Status.OK, this.createJSONRequest(requestUUID, session)); + } catch (JSONException e) { + e.printStackTrace(); + } + pluginResult.setKeepCallback(true); + this.webserver.onRequestCallbackContext.sendPluginResult(pluginResult); + + while (!this.webserver.responses.containsKey(requestUUID)) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + JSONObject responseObject = (JSONObject) this.webserver.responses.get(requestUUID); + Response response = null; + try { + response = newFixedLengthResponse( + Response.Status.lookup(responseObject.getInt("status")), + "text/plain", + responseObject.getString("body") + ); + + Iterator keys = responseObject.getJSONObject("headers").keys(); + while (keys.hasNext()) { + String key = (String) keys.next(); + response.addHeader( + key, + responseObject.getJSONObject("headers").getString(key) + ); + } + + } catch (JSONException e) { + e.printStackTrace(); + } + return response; + } +} diff --git a/src/android/Webserver.java b/src/android/Webserver.java index d8d3982..9804f8f 100644 --- a/src/android/Webserver.java +++ b/src/android/Webserver.java @@ -1,21 +1,101 @@ package org.apache.cordova.plugin; -import org.apache.cordova.api.CordovaPlugin; -import org.apache.cordova.api.PluginResult; +import org.apache.cordova.*; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -/** - * This class echoes a string called from JavaScript. - */ +import java.io.IOException; +import java.util.HashMap; + + public class Webserver extends CordovaPlugin { - @Override - public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { - if ("start".equals(action)) { - callbackContext.success(); - return true; + + public HashMap responses; + public CallbackContext onRequestCallbackContext; + + private NanoHTTPDWebserver nanoHTTPDWebserver; + + @Override + public void initialize(CordovaInterface cordova, CordovaWebView webView) { + super.initialize(cordova, webView); + this.responses = new HashMap(); + } + + @Override + public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { + if ("start".equals(action)) { + try { + this.start(args, callbackContext); + } catch (IOException e) { + e.printStackTrace(); + } + return true; + } + else if ("stop".equals(action)) { + this.stop(args, callbackContext); + return true; + } + else if ("onRequest".equals(action)) { + this.onRequest(args, callbackContext); + return true; + } + else if ("onResponse".equals(action)) { + this.onResponse(args, callbackContext); + return true; + } + return false; // Returning false results in a "MethodNotFound" error. + } + + /** + * Starts the server + * @param args + * @param callbackContext + */ + private void start(JSONArray args, CallbackContext callbackContext) throws JSONException, IOException { + int port = 8080; + + if (args.length() == 1) { + port = args.getInt(0); + } + this.nanoHTTPDWebserver = new NanoHTTPDWebserver(port, this); + this.nanoHTTPDWebserver.start(); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK)); + } + + /** + * Stops the server + * @param args + * @param callbackContext + */ + private void stop(JSONArray args, CallbackContext callbackContext) throws JSONException { + if (this.nanoHTTPDWebserver != null) { + this.nanoHTTPDWebserver.stop(); + } + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK)); + } + + /** + * Will be called if the js context sends an response to the webserver + * @param args {UUID: {...}} + * @param callbackContext + * @throws JSONException + */ + private void onResponse(JSONArray args, CallbackContext callbackContext) throws JSONException { + this.responses.put(args.getString(0), args.get(1)); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK)); + } + + /** + * Just register the onRequest and send no result. This is needed to save the callbackContext to + * invoke it later + * @param args + * @param callbackContext + */ + private void onRequest(JSONArray args, CallbackContext callbackContext) { + this.onRequestCallbackContext = callbackContext; + PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT); + pluginResult.setKeepCallback(true); + this.onRequestCallbackContext.sendPluginResult(pluginResult); } - return false; // Returning false results in a "MethodNotFound" error. - } }