diff --git a/src/android/Connection.java b/src/android/Connection.java index f834dd7..162756d 100644 --- a/src/android/Connection.java +++ b/src/android/Connection.java @@ -1,11 +1,18 @@ package com.tlantic.plugins.socket; +import android.util.Log; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; +import java.lang.Exception; +import java.lang.String; +import java.net.ConnectException; +import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; +import org.apache.cordova.CallbackContext; /** @@ -24,7 +31,24 @@ public class Connection extends Thread { private Boolean mustClose; private String host; private int port; + private CallbackContext callbackContext; //This is a bad practice. should be using handlers to send this to Socket Plugin + private String buildKey; + + public String getBuildKey() { + return buildKey; + } + + public void setBuildKey(String buildKey) { + this.buildKey = buildKey; + } + public CallbackContext getCallbackContext() { + return callbackContext; + } + + public void setCallbackContext(CallbackContext callbackContext) { + this.callbackContext = callbackContext; + } /** * Creates a TCP socket connection object. @@ -43,6 +67,20 @@ public Connection(SocketPlugin pool, String host, int port) { this.hook = pool; } + /** + * Creates a TCP socket connection object. + * + * @param pool Object containing "sendMessage" method to be called as a callback for data receive. + * @param host Target host for socket connection. + * @param port Target port for socket connection + * @param callbackContext for sending callbacks + */ + public Connection(SocketPlugin pool, String host, int port, CallbackContext callbackContext, String buildKey) { + this(pool, host, port); + this.callbackContext = callbackContext; + this.buildKey = buildKey; + } + /** * Returns socket connection state. @@ -95,8 +133,10 @@ public void close() { * * @param data information to be sent */ - public void write(String data) { + public boolean write(String data) { this.writer.println(data); + this.writer.flush(); + return !this.writer.checkError(); } @@ -109,8 +149,12 @@ public void run() { // creating connection try { - this.callbackSocket = new Socket(this.host, this.port); - this.writer = new PrintWriter(this.callbackSocket.getOutputStream(), true); + //This is a bad practice. should be using handlers to send this to SocketPlugin + this.callbackSocket = new Socket(); + this.callbackSocket.connect(new InetSocketAddress(this.host, this.port), 20000); + this.hook.sendConnectedEvent(this.buildKey, this.host, this.port, this); + this.callbackContext.success(this.buildKey); + this.writer = new PrintWriter(this.callbackSocket.getOutputStream(), true); this.reader = new BufferedReader(new InputStreamReader(callbackSocket.getInputStream())); // receiving data chunk @@ -128,17 +172,29 @@ public void run() { } } } catch (Exception e) { - e.printStackTrace(); + try { + this.callbackSocket.close(); + } catch (Exception closeException) { + closeException.printStackTrace(); + } + + hook.sendDisconnectedEvent(this.buildKey); + this.mustClose = true; } } } catch (UnknownHostException e1) { // TODO Auto-generated catch block + this.callbackContext.error(this.buildKey+" did not connect: unknown host"); e1.printStackTrace(); } catch (IOException e1) { // TODO Auto-generated catch block + this.callbackContext.error(this.buildKey+" did not connect: io host"); e1.printStackTrace(); - } + } catch (Exception el) { + this.callbackContext.error(this.buildKey+" did not connect: unknown error"); + el.printStackTrace(); + } } diff --git a/src/android/SocketPlugin.java b/src/android/SocketPlugin.java index 91f5e37..3d5ec52 100644 --- a/src/android/SocketPlugin.java +++ b/src/android/SocketPlugin.java @@ -95,13 +95,12 @@ private void connect (JSONArray args, CallbackContext callbackContext) { // creating connection if (this.pool.get(key) == null) { - socket = new Connection(this, host, port); + socket = new Connection(this, host, port, callbackContext, key); socket.start(); - this.pool.put(key, socket); } // adding to pool - callbackContext.success(key); +// callbackContext.success(key); } catch (JSONException e) { callbackContext.error("Invalid parameters for 'connect' action: " + e.getMessage()); @@ -180,10 +179,10 @@ private void send(JSONArray args, CallbackContext callbackContext) { } else { // write on output stream - socket.write(data); - - // ending send process - callbackContext.success(); + if(socket.write(data)) + callbackContext.success(); + else + callbackContext.error("Failed to send data"); } } catch (JSONException e) { @@ -224,6 +223,9 @@ private void disconnect (JSONArray args, CallbackContext callbackContext) { // removing from pool pool.remove(key); + + //Triggering event + this.sendDisconnectedEvent(key); } // ending with success @@ -257,11 +259,25 @@ private void disconnectAll (CallbackContext callbackContext) { // removing from pool this.pool.remove(pairs.getKey()); + + //Triggering event + this.sendDisconnectedEvent(pairs.getKey()); } callbackContext.success("All connections were closed."); } + private void sendEvent(final String eventTriggerCode) { + cordova.getActivity().runOnUiThread(new Runnable() { + + @Override + public void run() { + webView.loadUrl("javascript:" + eventTriggerCode); + } + + }); + } + /** * Callback for Connection object data receive. Relay information to javascript object method: window.tlantic.plugins.socket.receive(); @@ -273,14 +289,19 @@ private void disconnectAll (CallbackContext callbackContext) { public synchronized void sendMessage(String host, int port, String chunk) { final String receiveHook = "window.tlantic.plugins.socket.receive(\"" + host + "\"," + port + ",\"" + this.buildKey(host, port) + "\",\"" + chunk.replace("\"", "\\\"") + "\");"; - cordova.getActivity().runOnUiThread(new Runnable() { - - @Override - public void run() { - webView.loadUrl("javascript:" + receiveHook); - } - - }); + this.sendEvent(receiveHook); } - -} \ No newline at end of file + + public synchronized void sendDisconnectedEvent(String buildKey) { + final String receiveHook = "window.tlantic.plugins.socket.disconnectedEvent(\"" + buildKey + "\");"; + pool.remove(buildKey); + + this.sendEvent(receiveHook); + } + + public synchronized void sendConnectedEvent (String key, String ip, int port, Connection socket) { + this.pool.put(key, socket); + + //TODO trigger an event later when needed + } +} diff --git a/www/socket.js b/www/socket.js index 8add8da..b6a0dae 100644 --- a/www/socket.js +++ b/www/socket.js @@ -6,6 +6,7 @@ function Socket(){ 'use strict'; this.receiveHookName = 'SOCKET_RECEIVE_DATA_HOOK'; // *** Event name to act as "hook" for data receiving + this.disconnectedHookName = 'SOCKET_DISCONNECTED'; this.pluginRef = 'Socket'; // *** Plugin reference for Cordova.exec calls } @@ -57,4 +58,18 @@ Socket.prototype.receive = function (host, port, connectionId, chunk) { document.dispatchEvent(evReceive); }; + +Socket.prototype.disconnectedEvent = function(connectionId) { + var evReceive = document.createEvent('Events'); + + evReceive.initEvent(this.disconnectedHookName, true, true); + evReceive.metadata = { + connection: { + id: connectionId + } + }; + + document.dispatchEvent(evReceive); +}; + module.exports = new Socket();