diff --git a/TcpSocket.js b/TcpSocket.js index 66f2b08..7728984 100644 --- a/TcpSocket.js +++ b/TcpSocket.js @@ -42,6 +42,8 @@ function TcpSocket(options: ?{ id: ?number }) { if (this._id <= instances) { throw new Error('Socket id ' + this._id + 'already in use'); } + + this._options = options; } else { // javascript generated sockets range from 1-1000 this._id = instances++; @@ -84,6 +86,8 @@ TcpSocket.prototype.connect = function(options, callback) : TcpSocket { return TcpSocket.prototype.connect.apply(this, args); } + this._options = options; + if (typeof callback === 'function') { this.once('connect', callback); } @@ -114,7 +118,11 @@ TcpSocket.prototype.connect = function(options, callback) : TcpSocket { } if (options.timeout) { - this.setTimeout(options.timeout); + this.setTimeout(options.timeout, () => { + if (this._state === STATE.CONNECTING) { + Sockets.cancel(this._id); + } + }); } else if (this._timeout) { this._activeTimer(this._timeout.msecs); } @@ -196,11 +204,7 @@ TcpSocket.prototype.setTimeout = function(msecs: number, callback: () => void) { this.removeListener('timeout', callback); } } else { - if (callback) { - this.once('timeout', callback); - } - - this._activeTimer(msecs); + this._activeTimer(msecs, callback); } return this; @@ -243,6 +247,10 @@ TcpSocket.prototype.destroy = function() { } }; +TcpSocket.prototype.retrieveLastData = function () { + Sockets.retrieveLastData(this._id); +}; + TcpSocket.prototype._registerEvents = function(): void { if (this._subs && this._subs.length > 0) { return; @@ -309,7 +317,13 @@ TcpSocket.prototype._onConnection = function(info: { id: number, address: { port TcpSocket.prototype._onData = function(data: string): void { this._debug('received', 'data'); - if (this._timeout) { + if (this._options && this._options.timeout) { + this._clearTimeout(); + + this.setTimeout(this._options.timeout, () => { + Sockets.destroy(this._id); + }); + } else if (this._timeout) { this._activeTimer(this._timeout.msecs); } diff --git a/android/build.gradle b/android/build.gradle index 6a4e026..0ca734a 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -41,5 +41,5 @@ repositories { dependencies { compile 'com.facebook.react:react-native:+' - compile 'com.koushikdutta.async:androidasync:2.1.6' + compile 'com.koushikdutta.async:androidasync:2.+' } diff --git a/android/src/main/java/com/peel/react/TcpSocketManager.java b/android/src/main/java/com/peel/react/TcpSocketManager.java index df2007f..41795e4 100644 --- a/android/src/main/java/com/peel/react/TcpSocketManager.java +++ b/android/src/main/java/com/peel/react/TcpSocketManager.java @@ -14,6 +14,7 @@ import com.koushikdutta.async.callback.ConnectCallback; import com.koushikdutta.async.callback.DataCallback; import com.koushikdutta.async.callback.ListenCallback; +import com.koushikdutta.async.future.Cancellable; import java.io.IOException; import java.lang.ref.WeakReference; @@ -26,6 +27,7 @@ */ public final class TcpSocketManager { private SparseArray mClients = new SparseArray(); + private SparseArray mConnectingClients = new SparseArray(); private WeakReference mListener; private AsyncServer mServer = AsyncServer.getDefault(); @@ -128,7 +130,7 @@ public void connect(final Integer cId, final @Nullable String host, final Intege socketAddress = new InetSocketAddress(port); } - mServer.connectSocket(socketAddress, new ConnectCallback() { + Cancellable cancel = mServer.connectSocket(socketAddress, new ConnectCallback() { @Override public void onConnectCompleted(Exception ex, AsyncSocket socket) { TcpSocketListener listener = mListener.get(); @@ -144,6 +146,8 @@ public void onConnectCompleted(Exception ex, AsyncSocket socket) { } } }); + + mConnectingClients.put(cId, cancel); } public void write(final Integer cId, final byte[] data) { @@ -169,6 +173,14 @@ public void close(final Integer cId) { } } + public void cancel(final Integer cId) { + Cancellable cancel = mConnectingClients.get(cId); + if (cancel != null) { + cancel.cancel(); + mConnectingClients.remove(cId); + } + } + public void closeAllSockets() { for (int i = 0; i < mClients.size(); i++) { close(mClients.keyAt(i)); diff --git a/android/src/main/java/com/peel/react/TcpSockets.java b/android/src/main/java/com/peel/react/TcpSockets.java index 1bc07d2..95ac096 100644 --- a/android/src/main/java/com/peel/react/TcpSockets.java +++ b/android/src/main/java/com/peel/react/TcpSockets.java @@ -34,6 +34,8 @@ public final class TcpSockets extends ReactContextBaseJavaModule implements TcpS private static final String TAG = "TcpSockets"; private boolean mShuttingDown = false; + private boolean dataReceiverMode = false; + private String lastData = ""; private TcpSocketManager socketManager; private ReactContext mReactContext; @@ -106,7 +108,10 @@ public void connect(final Integer cId, final @Nullable String host, final Intege new GuardedAsyncTask(getReactApplicationContext()) { @Override protected void doInBackgroundGuarded(Void... params) { - // NOTE : ignoring options for now, just use the available interface. + if (options.getBoolean("dataReceiverMode")) { + dataReceiverMode = true; + } + try { socketManager.connect(cId, host, port); } catch (UnknownHostException uhe) { @@ -120,6 +125,17 @@ protected void doInBackgroundGuarded(Void... params) { }.execute(); } + @ReactMethod + public void cancel(final Integer cId) { + new GuardedAsyncTask(getReactApplicationContext()) { + @Override + protected void doInBackgroundGuarded(Void... params) { + socketManager.cancel(cId); + onError(cId, "Connection timeout"); + } + }.execute(); + } + @ReactMethod public void write(final Integer cId, final String base64String, final Callback callback) { new GuardedAsyncTask(getReactApplicationContext()) { @@ -194,11 +210,26 @@ public void onConnect(Integer id, InetSocketAddress socketAddress) { sendEvent("connect", eventParams); } + @ReactMethod + public void retrieveLastData(Integer id) { + WritableMap eventParams = Arguments.createMap(); + eventParams.putInt("id", id); + eventParams.putString("data", lastData); + + sendEvent("data", eventParams); + } + @Override public void onData(Integer id, byte[] data) { if (mShuttingDown) { return; } + + if (dataReceiverMode) { + lastData = Base64.encodeToString(data, Base64.NO_WRAP); + return; + } + WritableMap eventParams = Arguments.createMap(); eventParams.putInt("id", id); eventParams.putString("data", Base64.encodeToString(data, Base64.NO_WRAP));