UNPKG

react-native-tcp-socket

Version:

React Native TCP socket API for Android & iOS

198 lines (171 loc) 5.92 kB
'use strict'; import { NativeModules } from 'react-native'; const Buffer = (global.Buffer = global.Buffer || require('buffer').Buffer); const Sockets = NativeModules.TcpSockets; const STATE = { DISCONNECTED: 0, CONNECTING: 1, CONNECTED: 2, }; export default class TcpSocket { constructor(id, eventEmitter) { this._id = id; this._eventEmitter = eventEmitter; this._state = STATE.DISCONNECTED; } on(event, callback) { switch (event) { case 'data': this._eventEmitter.addListener('data', (evt) => { if (evt.id !== this._id) return; const bufferTest = Buffer.from(evt.data, 'base64'); callback(bufferTest); }); break; case 'error': this._eventEmitter.addListener('error', (evt) => { if (evt.id !== this._id) return; callback(evt.error); }); break; default: this._eventEmitter.addListener(event, (evt) => { if (evt.id !== this._id) return; callback(); }); break; } } off(event, callback) { this._eventEmitter.removeListener(event, callback); } connect(options, callback) { this._registerEvents(); // Normalize args options.host = options.host || 'localhost'; options.port = Number(options.port) || 0; options.localPort = Number(options.localPort) || 0; options.localAddress = options.localAddress || '0.0.0.0'; options.interface = options.interface || ''; const connectListener = this._eventEmitter.addListener('connect', (ev) => { if (this._id !== ev.id) return; connectListener.remove(); if (callback) callback(ev.address); }); if (options.timeout) this.setTimeout(options.timeout); else if (this._timeout) this._activeTimer(this._timeout.msecs); this._state = STATE.CONNECTING; this._destroyed = false; Sockets.connect(this._id, options.host, options.port, options); return this; } _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'); }; } this._timeout = { handle: setTimeout(wrapper, msecs), wrapper: wrapper, msecs: msecs, }; } _clearTimeout() { if (this._timeout) { clearTimeout(this._timeout.handle); this._timeout = null; } } setTimeout(msecs, callback) { if (msecs === 0) { this._clearTimeout(); if (callback) this._eventEmitter.removeListener('timeout', callback); } else { if (callback) this._eventEmitter.once('timeout', callback); this._activeTimer(msecs); } return this; } address() { return this._address; } end(data, encoding) { if (this._destroyed) return; if (data) this.write(data, encoding); this._destroyed = true; Sockets.end(this._id); } close() { this.destroy(); } destroy() { if (!this._destroyed) { this._destroyed = true; this._clearTimeout(); Sockets.destroy(this._id); } } _registerEvents() { this._eventEmitter.addListener('connect', (ev) => { if (this._id !== ev.id) return; this._onConnect(ev.address); }); this._eventEmitter.addListener('close', (ev) => { if (this._id !== ev.id) return; this._onClose(ev.hadError); }); this._eventEmitter.addListener('error', (ev) => { if (this._id !== ev.id) return; this._onError(ev.error); }); } _unregisterEvents() { this._eventEmitter.listeners().forEach((listener) => listener.remove()); } _onConnect(address) { this.setConnected(address); } _onClose() { this.setDisconnected(); } _onError() { this.destroy(); } /** * * @param {string | Buffer | Uint8Array} buffer * @param {string} encoding * @param {Function} callback */ write(buffer, encoding, callback) { const self = this; if (this._state === STATE.DISCONNECTED) throw new Error('Socket is not connected.'); callback = callback || (() => {}); let str; if (typeof buffer === 'string') str = Buffer.from(buffer, encoding).toString('base64'); else if (Buffer.isBuffer(buffer)) str = buffer.toString('base64'); else if (buffer instanceof Uint8Array || Array.isArray(buffer)) str = Buffer.from(buffer); else throw new TypeError( `Invalid data, chunk must be a string or buffer, not ${typeof buffer}` ); Sockets.write(this._id, str, function(err) { if (self._timeout) self._activeTimer(self._timeout.msecs); if (err) return callback(err); callback(); }); } setConnected(address) { this._state = STATE.CONNECTED; this._address = address; } setDisconnected() { if (this._state === STATE.DISCONNECTED) return; this._unregisterEvents(); this._state = STATE.DISCONNECTED; } }