THRIFT-5003: Websocket Connection in Browsers with nodejs code
* changed this to self in forEach callback
* updated minimum node version to 8.16.2 (Maintenance LTS until December 2019)
changed ws_connection.js to work in the browser, with isomorphic-ws
added exports for `wsConnection`, `createWSConnection`, `createWSClient`
* added exports for WSConnection to browser.js
* extended the sample of nodejs code in the browser with webpack
* tested and updated node version to LTS 10.18.0 Dubnium
discussion based: https://github.com/apache/thrift/pull/1927#discussion_r358140463
diff --git a/lib/nodejs/README.md b/lib/nodejs/README.md
index ed306c1..c087440 100644
--- a/lib/nodejs/README.md
+++ b/lib/nodejs/README.md
@@ -75,8 +75,8 @@
thrift --gen js:node,ts,es6,with_ns
-```
-import * as thrift from 'thrift/browser';
+```javascript
+import * as thrift from 'thrift';
import { MyServiceClient } from '../gen-nodejs/MyService';
let host = window.location.hostname;
@@ -108,4 +108,35 @@
});
```
-Note that thrift/index.js must be renamed or skipped for browsers.
+Bundlers, like webpack, will use thrift/browser.js by default because of the
+`"browser": "./lib/nodejs/lib/thrift/browser.js"` field in package.json.
+
+### Browser example with WebSocket, BufferedTransport and BinaryProtocol
+```javascript
+import thrift from 'thrift';
+import { MyServiceClient } from '../gen-nodejs/MyService';
+
+const host = window.location.hostname;
+const port = 9090;
+const opts = {
+ transport: thrift.TBufferedTransport,
+ protocol: thrift.TBinaryProtocol
+}
+const connection = thrift.createWSConnection(host, port, opts);
+connection.open();
+const thriftClient = thrift.createWSClient(MyServiceClient, connection);
+
+connection.on('error', (err) => {
+ console.error(err);
+});
+
+thriftClient.myService(param)
+ .then((result) => {
+ console.log(result);
+ })
+ .catch((err) => {
+ ....
+ });
+```
+
+
diff --git a/lib/nodejs/lib/thrift/browser.js b/lib/nodejs/lib/thrift/browser.js
index 67ce853..82e5469 100644
--- a/lib/nodejs/lib/thrift/browser.js
+++ b/lib/nodejs/lib/thrift/browser.js
@@ -23,6 +23,11 @@
exports.createXHRConnection = xhrConnection.createXHRConnection;
exports.createXHRClient = xhrConnection.createXHRClient;
+var wsConnection = require('./ws_connection');
+exports.WSConnection = wsConnection.WSConnection;
+exports.createWSConnection = wsConnection.createWSConnection;
+exports.createWSClient = wsConnection.createWSClient;
+
exports.Multiplexer = require('./multiplexed_protocol').Multiplexer;
exports.TWebSocketTransport = require('./ws_transport');
diff --git a/lib/nodejs/lib/thrift/ws_connection.js b/lib/nodejs/lib/thrift/ws_connection.js
index 052cbd4..8ee8f6e 100644
--- a/lib/nodejs/lib/thrift/ws_connection.js
+++ b/lib/nodejs/lib/thrift/ws_connection.js
@@ -17,18 +17,16 @@
* under the License.
*/
var util = require('util');
-var WebSocket = require('ws');
+var WebSocket = require('isomorphic-ws');
var EventEmitter = require("events").EventEmitter;
var thrift = require('./thrift');
-var ttransport = require('./transport');
-var tprotocol = require('./protocol');
var TBufferedTransport = require('./buffered_transport');
var TJSONProtocol = require('./json_protocol');
var InputBufferUnderrunError = require('./input_buffer_underrun_error');
var createClient = require('./create_client');
-
+var jsEnv = require('browser-or-node');
exports.WSConnection = WSConnection;
/**
@@ -69,7 +67,7 @@
* @throws {error} Exceptions other than ttransport.InputBufferUnderrunError are rethrown
* @event {error} The "error" event is fired when a Node.js error event occurs during
* request or response processing, in which case the node error is passed on. An "error"
- * event may also be fired when the connectison can not map a response back to the
+ * event may also be fired when the connection can not map a response back to the
* appropriate client (an internal error), generating a TApplicationException.
* @classdesc WSConnection objects provide Thrift end point transport
* semantics implemented using Websockets.
@@ -80,7 +78,6 @@
EventEmitter.call(this);
//Set configuration
- var self = this;
this.options = options || {};
this.host = host;
this.port = port;
@@ -113,14 +110,13 @@
};
WSConnection.prototype.__onOpen = function() {
- var self = this;
this.emit("open");
if (this.send_pending.length > 0) {
//If the user made calls before the connection was fully
//open, send them now
this.send_pending.forEach(function(data) {
- self.socket.send(data);
- });
+ this.socket.send(data);
+ }, this);
this.send_pending = [];
}
};
@@ -184,7 +180,7 @@
};
WSConnection.prototype.__onData = function(data) {
- if (Object.prototype.toString.call(data) == "[object ArrayBuffer]") {
+ if (Object.prototype.toString.call(data) === "[object ArrayBuffer]") {
data = new Uint8Array(data);
}
var buf = new Buffer(data);
@@ -207,7 +203,7 @@
* @returns {boolean}
*/
WSConnection.prototype.isOpen = function() {
- return this.socket && this.socket.readyState == this.socket.OPEN;
+ return this.socket && this.socket.readyState === this.socket.OPEN;
};
/**
@@ -215,11 +211,15 @@
*/
WSConnection.prototype.open = function() {
//If OPEN/CONNECTING/CLOSING ignore additional opens
- if (this.socket && this.socket.readyState != this.socket.CLOSED) {
+ if (this.socket && this.socket.readyState !== this.socket.CLOSED) {
return;
}
//If there is no socket or the socket is closed:
- this.socket = new WebSocket(this.uri(), "", this.wsOptions);
+ if (jsEnv.isBrowser) {
+ this.socket = new WebSocket(this.uri());
+ } else {
+ this.socket = new WebSocket(this.uri(), "", this.wsOptions);
+ }
this.socket.binaryType = 'arraybuffer';
this.socket.onopen = this.__onOpen.bind(this);
this.socket.onmessage = this.__onMessage.bind(this);
@@ -245,8 +245,8 @@
var host = this.host;
// avoid port if default for schema
- if (this.port && (('wss' == schema && this.port != 443) ||
- ('ws' == schema && this.port != 80))) {
+ if (this.port && (('wss' === schema && this.port !== 443) ||
+ ('ws' === schema && this.port !== 80))) {
port = ':' + this.port;
}