From eca3be059e57b950374d99bfc80838a1731890d9 Mon Sep 17 00:00:00 2001 From: Rapsssito Date: Tue, 16 Jun 2020 12:35:12 +0200 Subject: [PATCH 1/4] Add timers --- src/TcpSocket.js | 76 +++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/src/TcpSocket.js b/src/TcpSocket.js index 8f69033..0c906ad 100644 --- a/src/TcpSocket.js +++ b/src/TcpSocket.js @@ -15,7 +15,6 @@ const STATE = { * @typedef {{ * port: number; * host?: string; - * timeout?: number; * localAddress?: string, * localPort?: number, * interface?: 'wifi' | 'cellular' | 'ethernet', @@ -38,6 +37,9 @@ export default class TcpSocket extends EventEmitter { this._id = id; this._eventEmitter = eventEmitter; /** @type {number} */ + this._timeoutMsecs = 0; + this._timeout = undefined; + /** @type {number} */ this._state = STATE.DISCONNECTED; this._registerEvents(); if (address != undefined) this._setConnected(address); @@ -93,8 +95,7 @@ export default class TcpSocket extends EventEmitter { if (callback) callback(ev.address); }); // Timeout - if (customOptions.timeout) this.setTimeout(customOptions.timeout); - else if (this._timeout) this._activeTimer(this._timeout.msecs); + if (this._timeout) this._activateTimer(); // TLS Cert if (customOptions.tlsCert) { customOptions.tlsCert = Image.resolveAssetSource(customOptions.tlsCert).uri; @@ -107,53 +108,49 @@ export default class TcpSocket extends EventEmitter { } /** - * @private - * @param {number} msecs - * @param {() => void} [wrapper] + * Sets the socket to timeout after `timeout` milliseconds of inactivity on the socket. By default `TcpSocket` do not have a timeout. + * + * When an idle timeout is triggered the socket will receive a `'timeout'` event but the connection will not be severed. + * The user must manually call `socket.end()` or `socket.destroy()` to end the connection. + * + * If `timeout` is 0, then the existing idle timeout is disabled. + * + * The optional `callback` parameter will be added as a one-time listener for the `'timeout'` event. + * + * @param {number} timeout + * @param {() => void} [callback] */ - _activeTimer(msecs, wrapper) { - if (this._timeout && this._timeout.handle) clearTimeout(this._timeout.handle); - - if (!wrapper) { - const self = this; - wrapper = function() { - self._timeout = null; - self._eventEmitter.emit('timeout'); - }; + setTimeout(timeout, callback) { + if (timeout === 0) { + this._clearTimeout(); + } else { + this._activateTimer(timeout); } - - this._timeout = { - handle: setTimeout(wrapper, msecs), - wrapper: wrapper, - msecs: msecs, - }; + if (callback) this.once('timeout', callback); + return this; } /** * @private + * @param {number} [timeout] */ - _clearTimeout() { - if (this._timeout) { - clearTimeout(this._timeout.handle); - this._timeout = null; - } + _activateTimer(timeout) { + if (timeout !== undefined) this._timeoutMsecs = timeout; + this._clearTimeout(); + this._timeout = setTimeout(() => { + this._clearTimeout(); + this.emit('timeout'); + }, this._timeoutMsecs); } /** - * @deprecated - * @param {number} msecs - * @param {(...args: any[]) => void } [callback] + * @private */ - setTimeout(msecs, callback) { - if (msecs === 0) { - this._clearTimeout(); - if (callback) this._eventEmitter.removeListener('timeout', callback); - } else { - if (callback) this._eventEmitter.once('timeout', callback, this); - - this._activeTimer(msecs); + _clearTimeout() { + if (this._timeout !== undefined) { + clearTimeout(this._timeout); + this._timeout = undefined; } - return this; } /** @@ -186,6 +183,7 @@ export default class TcpSocket extends EventEmitter { }); } else { this._destroyed = true; + this._clearTimeout(); Sockets.end(this._id); } } @@ -242,7 +240,7 @@ export default class TcpSocket extends EventEmitter { * @param {string} err */ function(err) { - if (self._timeout) self._activeTimer(self._timeout.msecs); + if (self._timeout) self._activateTimer(); if (callback) { if (err) return callback(err); callback(null); From 1fad43b2d73cd307b5397eacd49919039195dab7 Mon Sep 17 00:00:00 2001 From: Rapsssito Date: Tue, 16 Jun 2020 12:50:22 +0200 Subject: [PATCH 2/4] Add timeout on createConnection --- README.md | 2 ++ src/TcpSocket.js | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f31e04..8054b24 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,7 @@ _Note: In order to use self-signed certificates make sure to [update your metro. * [`write(data[, encoding][, callback])`](#write) * [`destroy()`](#destroy) * [`setNoDelay([noDelay])`](https://nodejs.org/api/net.html#net_socket_setnodelay_nodelay) + * [`setTimeout(timeout[, callback])`](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) #### `createConnection()` `createConnection(options[, callback])` creates a TCP connection using the given [`options`](#createconnection-options). @@ -195,6 +196,7 @@ _Note: In order to use self-signed certificates make sure to [update your metro. | --------------------- | ------ | :--: | :-----: |-------------------------------------------------------------------------------------------------- | | **`port`** | `` | ✅ | ✅ | **Required**. Port the socket should connect to. | | `host` | `` | ✅ | ✅ | Host the socket should connect to. IP address in IPv4 format or `'localhost'`. **Default**: `'localhost'`. | +| `timeout` | `` | ✅ | ✅ | If set, will be used to call [`setTimeout(timeout)`](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the socket is created, but before it starts the connection. | | `localAddress` | `` | ✅ | ✅ | Local address the socket should connect from. If not specified, the OS will decide. It is **highly recommended** to specify a `localAddress` to prevent overload errors and improve performance. | | `localPort` | `` | ✅ | ✅ | Local port the socket should connect from. If not specified, the OS will decide. | | `interface`| `` | ❌ | ✅ | Interface the socket should connect from. If not specified, it will use the current active connection. The options are: `'wifi', 'ethernet', 'cellular'`. | diff --git a/src/TcpSocket.js b/src/TcpSocket.js index 0c906ad..11b6430 100644 --- a/src/TcpSocket.js +++ b/src/TcpSocket.js @@ -15,6 +15,7 @@ const STATE = { * @typedef {{ * port: number; * host?: string; + * timeout?: number, * localAddress?: string, * localPort?: number, * interface?: 'wifi' | 'cellular' | 'ethernet', @@ -95,7 +96,8 @@ export default class TcpSocket extends EventEmitter { if (callback) callback(ev.address); }); // Timeout - if (this._timeout) this._activateTimer(); + if (customOptions.timeout) this._activateTimer(customOptions.timeout); + else if (this._timeout) this._activateTimer(); // TLS Cert if (customOptions.tlsCert) { customOptions.tlsCert = Image.resolveAssetSource(customOptions.tlsCert).uri; From e7dd3253258a7945f83c6207e524c24929377e73 Mon Sep 17 00:00:00 2001 From: Rodrigo Martin Date: Wed, 17 Jun 2020 14:58:55 +0200 Subject: [PATCH 3/4] Change connect() timeout call to setTimeout() --- src/TcpSocket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TcpSocket.js b/src/TcpSocket.js index 11b6430..fb70202 100644 --- a/src/TcpSocket.js +++ b/src/TcpSocket.js @@ -96,7 +96,7 @@ export default class TcpSocket extends EventEmitter { if (callback) callback(ev.address); }); // Timeout - if (customOptions.timeout) this._activateTimer(customOptions.timeout); + if (customOptions.timeout) this.setTimeout(customOptions.timeout); else if (this._timeout) this._activateTimer(); // TLS Cert if (customOptions.tlsCert) { From 9cd7e617daaf850dd454233322970d1459f0f90b Mon Sep 17 00:00:00 2001 From: Rodrigo Martin Date: Wed, 17 Jun 2020 15:19:08 +0200 Subject: [PATCH 4/4] More clear README --- README.md | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 8054b24..7e4c3c7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![](https://github.com/Rapsssito/react-native-tcp-socket/workflows/tests/badge.svg) -React Native TCP socket API for Android & iOS with **client SSL/TLS support**. It allows you to create TCP clients and servers sockets, imitating some of node's [net](https://nodejs.org/api/net.html) API functionalities (check the available [API](#api) for more information). +React Native TCP socket API for Android & iOS with **client SSL/TLS support**. It allows you to create TCP clients and servers sockets, imitating some of Node's [net](https://nodejs.org/api/net.html) API functionalities (check the available [API](#api) for more information). ## Table of Contents @@ -11,8 +11,8 @@ React Native TCP socket API for Android & iOS with **client SSL/TLS support**. I - [Compatibility](#react-native-compatibility) - [Usage](#usage) - [API](#api) - - [Client](#client) - - [Server](#server) + - [TcpSocket](#tcpsocket) + - [TcpServer](#tcpserver) - [Maintainers](#maintainers) - [Acknowledgments](#acknowledgments) - [License](#license) @@ -113,7 +113,7 @@ To use this library you need to ensure you are using the correct version of Reac Import the library: ```javascript import TcpSocket from 'react-native-tcp-socket'; -// var net = require('react-native-tcp-socket'); +// const net = require('react-native-tcp-socket'); ``` ### Client ```javascript @@ -179,11 +179,13 @@ const client = TcpSocket.createConnection({ _Note: In order to use self-signed certificates make sure to [update your metro.config.js configuration](#self-signed-ssl-only-available-for-react-native--060)._ ## API -### Client +Here are listed all methods implemented in `react-native-tcp-socket`, their functionalities are equivalent to those provided by Node's [net](https://nodejs.org/api/net.html) (more info on [#41](https://github.com/Rapsssito/react-native-tcp-socket/issues/41)). However, the **methods whose interface differs from Node are shown in bold**. + +### TcpSocket * **Methods:** - * [`createConnection(options[, callback])`](#createconnection) - * [`write(data[, encoding][, callback])`](#write) - * [`destroy()`](#destroy) + * **[`TcpSocket.createConnection(options[, callback])`](#createconnection)** + * [`write(data[, encoding][, callback])`](https://nodejs.org/api/net.html#net_socket_write_data_encoding_callback) + * [`destroy([error])`](https://nodejs.org/api/net.html#net_socket_destroy_error) * [`setNoDelay([noDelay])`](https://nodejs.org/api/net.html#net_socket_setnodelay_nodelay) * [`setTimeout(timeout[, callback])`](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) @@ -207,18 +209,11 @@ _Note: In order to use self-signed certificates make sure to [update your metro. **Note**: The platforms marked as ❌ use the default value. -#### `write()` -* `data`: ` | | ` -* `encoding`: ``. Only used when `data` is `string`. Default: `utf8`. -* `callback `: `` - -`write(data[, encoding][, callback])` sends data on the socket. The second parameter specifies the encoding in the case of a string — it defaults to UTF8 encoding. - -### Server +### TcpServer * **Methods:** - * [`createServer(callback)`](#createserver) - * [`listen(options[, callback])`](#listen) - * [`close()`](#close) + * [`TcpSocket.createServer(connectionListener)`](https://nodejs.org/api/net.html#net_net_createserver_options_connectionlistener) + * **[`listen(options[, callback])`](#listen)** + * [`close([callback])`](https://nodejs.org/api/net.html#net_server_close_callback) #### `listen()` `listen(options[, callback])` creates a TCP server socket using the given [`options`](#listen-options).