From d8bd096d6855bc66b613d67802e1251d17bd2f69 Mon Sep 17 00:00:00 2001 From: Patrick Neschkudla Date: Fri, 13 May 2016 19:09:18 +0200 Subject: [PATCH 1/4] replace current websocket implementation with engine.io, made tests work in node without mocking window --- client/package.json | 5 ++- client/src/auth.js | 3 +- client/src/socket.js | 72 ++++++++++++++++++-------------- client/src/util/glob.js | 9 ++++ client/test/above.js | 2 +- client/test/aboveSub.js | 2 +- client/test/auth.js | 2 +- client/test/below.js | 2 +- client/test/belowSub.js | 2 +- client/test/chaining.js | 2 +- client/test/collection.js | 2 +- client/test/find.js | 2 +- client/test/findAll.js | 2 +- client/test/findAllSub.js | 2 +- client/test/findSub.js | 2 +- client/test/horizonObject.js | 4 +- client/test/insert.js | 2 +- client/test/limit.js | 2 +- client/test/order.js | 2 +- client/test/orderLimitSub.js | 2 +- client/test/remove.js | 2 +- client/test/removeAll.js | 2 +- client/test/replace.js | 2 +- client/test/store.js | 2 +- client/test/test.js | 49 +++++++--------------- client/test/times.js | 2 +- client/test/update.js | 2 +- client/test/upsert.js | 2 +- client/test/utilsTest.js | 2 +- client/webpack.horizon.config.js | 19 +++++---- server/package.json | 3 +- server/src/client.js | 9 ++-- server/src/server.js | 22 ++++++---- 33 files changed, 127 insertions(+), 114 deletions(-) create mode 100644 client/src/util/glob.js diff --git a/client/package.json b/client/package.json index 4c7399156..c69f2aab3 100644 --- a/client/package.json +++ b/client/package.json @@ -16,9 +16,12 @@ "dependencies": { "babel-runtime": "^6.6.1", "core-js": "^2.1.0", + "engine.io-client": "^1.6.9", + "engine.io-parser": "socketio/engine.io-parser#748144b50a1d10e8c7c9b8100f2e21f8ac424c7a", "isomorphic-fetch": "^2.2.1", "rxjs": "^5.0.0-beta.6", - "snake-case": "^1.1.2" + "snake-case": "^1.1.2", + "ws": "^1.0.1" }, "engines": { "node": ">=4.0.0" diff --git a/client/src/auth.js b/client/src/auth.js index a3184eb5d..aa9670bd9 100644 --- a/client/src/auth.js +++ b/client/src/auth.js @@ -91,7 +91,8 @@ export class TokenStorage { } setAuthFromQueryParams() { - const parsed = queryParse(window.location.search) + const parsed = typeof window !== 'undefined' ? queryParse(window.location.search) : {} + if (parsed.horizon_auth != null) { this.set(parsed.horizon_auth) } diff --git a/client/src/socket.js b/client/src/socket.js index 3550eda38..5377879b4 100644 --- a/client/src/socket.js +++ b/client/src/socket.js @@ -6,16 +6,20 @@ import { merge } from 'rxjs/observable/merge' import { filter } from 'rxjs/operator/filter' import { share } from 'rxjs/operator/share' -import { WebSocket } from './shim.js' import { serialize, deserialize } from './serialization.js' import { log } from './logging.js' +import socket from 'engine.io-client' + +let transports + +if (typeof window === 'undefined') { + transports = [ 'websocket' ] +} const PROTOCOL_VERSION = 'rethinkdb-horizon-v0' // Before connecting the first time const STATUS_UNCONNECTED = { type: 'unconnected' } -// After the websocket is opened, but before handshake -const STATUS_CONNECTED = { type: 'connected' } // After the websocket is opened and handshake is completed const STATUS_READY = { type: 'ready' } // After unconnected, maybe before or after connected. Any socket level error @@ -42,7 +46,7 @@ class ProtocolError extends Error { // observable is closed. class HorizonSocket extends Subject { constructor(host, secure, path, handshaker) { - const hostString = `ws${secure ? 's' : ''}://${host}/${path}` + const hostString = `ws${secure ? 's' : ''}://${host}` const msgBuffer = [] let ws, handshakeDisp // Handshake is an asyncsubject because we want it to always cache @@ -50,19 +54,25 @@ class HorizonSocket extends Subject { const handshake = new AsyncSubject() const statusSubject = new BehaviorSubject(STATUS_UNCONNECTED) - const isOpen = () => Boolean(ws) && ws.readyState === WebSocket.OPEN + const isOpen = () => Boolean(ws) && ws.readyState === 'open' // Serializes to a string before sending function wsSend(msg) { const stringMsg = JSON.stringify(serialize(msg)) + ws.send(stringMsg) } // This is the observable part of the Subject. It forwards events // from the underlying websocket const socketObservable = Observable.create(subscriber => { - ws = new WebSocket(hostString, PROTOCOL_VERSION) - ws.onerror = () => { + ws = socket(hostString, { + protocol: PROTOCOL_VERSION, + path: `/${path}`, + transports + }) + + ws.on('error', () => { // If the websocket experiences the error, we forward it through // to the observable. Unfortunately, the event we receive in // this callback doesn't tell us much of anything, so there's no @@ -70,15 +80,33 @@ class HorizonSocket extends Subject { statusSubject.next(STATUS_ERROR) const errMsg = `Websocket ${hostString} experienced an error` subscriber.error(new Error(errMsg)) - } - ws.onopen = () => { + }) + + ws.on('open', () => { + ws.on('message', data => { + const deserialized = deserialize(JSON.parse(data)) + log('Received', deserialized) + subscriber.next(deserialized) + }) + + ws.on('close', e => { + // This will happen if the socket is closed by the server If + // .close is called from the client (see closeSocket), this + // listener will be removed + statusSubject.next(STATUS_DISCONNECTED) + if (e.code !== 1000 || !e.wasClean) { + subscriber.error( + new Error(`Socket closed unexpectedly with code: ${e.code}`), e) + } else { + subscriber.complete() + } + }) + // Send the handshake - statusSubject.next(STATUS_CONNECTED) handshakeDisp = this.makeRequest(handshaker()).subscribe( x => { handshake.next(x) handshake.complete() - statusSubject.next(STATUS_READY) }, err => handshake.error(err), @@ -90,24 +118,7 @@ class HorizonSocket extends Subject { log('Sending buffered:', msg) wsSend(msg) } - } - ws.onmessage = event => { - const deserialized = deserialize(JSON.parse(event.data)) - log('Received', deserialized) - subscriber.next(deserialized) - } - ws.onclose = e => { - // This will happen if the socket is closed by the server If - // .close is called from the client (see closeSocket), this - // listener will be removed - statusSubject.next(STATUS_DISCONNECTED) - if (e.code !== 1000 || !e.wasClean) { - subscriber.error( - new Error(`Socket closed unexpectedly with code: ${e.code}`)) - } else { - subscriber.complete() - } - } + }) return () => { if (handshakeDisp) { handshakeDisp.unsubscribe() @@ -157,9 +168,6 @@ class HorizonSocket extends Subject { } else { ws.close(code, reason) } - ws.onopen = undefined - ws.onclose = undefined - ws.onmessage = undefined } super(socketSubscriber, socketObservable) diff --git a/client/src/util/glob.js b/client/src/util/glob.js new file mode 100644 index 000000000..96a867519 --- /dev/null +++ b/client/src/util/glob.js @@ -0,0 +1,9 @@ +module.exports = function glob() { + return typeof self !== 'undefined' ? + self : + typeof window !== 'undefined' ? + window : + typeof global !== 'undefined' ? + global : + {} +} diff --git a/client/test/above.js b/client/test/above.js index e311fa643..910f691bb 100644 --- a/client/test/above.js +++ b/client/test/above.js @@ -3,7 +3,7 @@ import { toArray } from 'rxjs/operator/toArray' import { assertCompletes, assertThrows, assertErrors } from './utils' -const aboveSuite = window.aboveSuite = (getData) => () => { +const aboveSuite = global.aboveSuite = (getData) => () => { let data before(() => { diff --git a/client/test/aboveSub.js b/client/test/aboveSub.js index 2dafa216e..5e09aa9c7 100644 --- a/client/test/aboveSub.js +++ b/client/test/aboveSub.js @@ -2,7 +2,7 @@ import { concat } from 'rxjs/operator/concat' import { assertCompletes, observableInterleave } from './utils' -const aboveSubscriptionSuite = window.aboveSubscriptionSuite = getData => () => { +const aboveSubscriptionSuite = global.aboveSubscriptionSuite = getData => () => { let data before(() => { diff --git a/client/test/auth.js b/client/test/auth.js index d082c0d93..0cd465960 100644 --- a/client/test/auth.js +++ b/client/test/auth.js @@ -1,6 +1,6 @@ import { TokenStorage, FakeStorage } from '../src/auth' -const authSuite = window.authSuite = () => { +const authSuite = global.authSuite = () => { describe('TokenStorage', () => { let fakeStorage let tokenStore diff --git a/client/test/below.js b/client/test/below.js index 9d2c8dd3f..125ad77f8 100644 --- a/client/test/below.js +++ b/client/test/below.js @@ -3,7 +3,7 @@ import { toArray } from 'rxjs/operator/toArray' import { assertCompletes, assertThrows, assertErrors } from './utils' -const belowSuite = window.belowSuite = (getData) => () => { +const belowSuite = global.belowSuite = (getData) => () => { let data before(() => { diff --git a/client/test/belowSub.js b/client/test/belowSub.js index 894946fc3..2679b2eca 100644 --- a/client/test/belowSub.js +++ b/client/test/belowSub.js @@ -2,7 +2,7 @@ import { concat } from 'rxjs/operator/concat' import { assertCompletes, observableInterleave } from './utils' -const belowSubscriptionSuite = window.belowSubscriptionSuite = getData => () => { +const belowSubscriptionSuite = global.belowSubscriptionSuite = getData => () => { let data before(() => { diff --git a/client/test/chaining.js b/client/test/chaining.js index c465b967a..41160c87b 100644 --- a/client/test/chaining.js +++ b/client/test/chaining.js @@ -3,7 +3,7 @@ import { toArray } from 'rxjs/operator/toArray' import { assertCompletes, assertThrows } from './utils' -const chainingSuite = window.chainingSuite = getData => () => { +const chainingSuite = global.chainingSuite = getData => () => { let data before(() => { diff --git a/client/test/collection.js b/client/test/collection.js index e14e93a69..7ada6e5f1 100644 --- a/client/test/collection.js +++ b/client/test/collection.js @@ -3,7 +3,7 @@ import { toArray } from 'rxjs/operator/toArray' import { assertCompletes, removeAllData } from './utils' -const collectionSuite = window.collectionSuite = (getHorizon, getData, getTestData) => () => { +const collectionSuite = global.collectionSuite = (getHorizon, getData, getTestData) => () => { let horizon, data, testData, empty_collection before(() => { diff --git a/client/test/find.js b/client/test/find.js index e27051b6f..1e8507342 100644 --- a/client/test/find.js +++ b/client/test/find.js @@ -3,7 +3,7 @@ import { toArray } from 'rxjs/operator/toArray' import { assertCompletes, assertThrows, assertErrors } from './utils' -const findSuite = window.findSuite = getData => () => { +const findSuite = global.findSuite = getData => () => { let data before(() => { diff --git a/client/test/findAll.js b/client/test/findAll.js index f913d7b14..6eb6b4b1e 100644 --- a/client/test/findAll.js +++ b/client/test/findAll.js @@ -3,7 +3,7 @@ import { toArray } from 'rxjs/operator/toArray' import { assertCompletes, assertThrows, assertErrors } from './utils' -const findAllSuite = window.findAllSuite = getData => () => { +const findAllSuite = global.findAllSuite = getData => () => { let data before(() => { diff --git a/client/test/findAllSub.js b/client/test/findAllSub.js index ee4399276..26ce36c8b 100644 --- a/client/test/findAllSub.js +++ b/client/test/findAllSub.js @@ -2,7 +2,7 @@ import { concat } from 'rxjs/operator/concat' import { assertCompletes, observableInterleave } from './utils' -const findAllSubscriptionSuite = window.findAllSubscriptionSuite = getData => () => { +const findAllSubscriptionSuite = global.findAllSubscriptionSuite = getData => () => { let data before(() => { diff --git a/client/test/findSub.js b/client/test/findSub.js index ca18f1b93..626ee7f94 100644 --- a/client/test/findSub.js +++ b/client/test/findSub.js @@ -2,7 +2,7 @@ import { concat } from 'rxjs/operator/concat' import { assertCompletes, observableInterleave } from './utils' -const findSubscriptionSuite = window.findSubscriptionSuite = getData => () => { +const findSubscriptionSuite = global.findSubscriptionSuite = getData => () => { let data before(() => { diff --git a/client/test/horizonObject.js b/client/test/horizonObject.js index abd0ef0db..b832b1664 100644 --- a/client/test/horizonObject.js +++ b/client/test/horizonObject.js @@ -3,7 +3,7 @@ // Test object creation, the `disconnect` method, and `connected/disconnected` // events. -var horizonObjectSuite = window.horizonObjectSuite = () => { +var horizonObjectSuite = global.horizonObjectSuite = () => { describe('Horizon', () => { it('connects and can track its status', done => { Horizon.clearAuthTokens() @@ -14,7 +14,7 @@ var horizonObjectSuite = window.horizonObjectSuite = () => { switch (stat.type) { case 'unconnected': break - case 'connected': + case 'ready': horizon.disconnect() break case 'error': diff --git a/client/test/insert.js b/client/test/insert.js index 34f0ddc71..ee6167059 100644 --- a/client/test/insert.js +++ b/client/test/insert.js @@ -4,7 +4,7 @@ import { mergeMap } from 'rxjs/operator/mergeMap' import { toArray } from 'rxjs/operator/toArray' import { assertCompletes, assertThrows, assertErrors } from './utils' -const insertSuite = window.insertSuite = getData => () => { +const insertSuite = global.insertSuite = getData => () => { let data before(() => { diff --git a/client/test/limit.js b/client/test/limit.js index e033c0635..dc1dcfb72 100644 --- a/client/test/limit.js +++ b/client/test/limit.js @@ -3,7 +3,7 @@ import { toArray } from 'rxjs/operator/toArray' import { assertCompletes, assertThrows, assertErrors } from './utils' -const limitSuite = window.limitSuite = getData => () => { +const limitSuite = global.limitSuite = getData => () => { let data before(() => { diff --git a/client/test/order.js b/client/test/order.js index 4e2c5ef91..5b63a428d 100644 --- a/client/test/order.js +++ b/client/test/order.js @@ -3,7 +3,7 @@ import { toArray } from 'rxjs/operator/toArray' import { assertCompletes, assertThrows, assertErrors } from './utils' -const orderSuite = window.orderSuite = (getData, getTestData) => () => { +const orderSuite = global.orderSuite = (getData, getTestData) => () => { let data, testData before(() => { diff --git a/client/test/orderLimitSub.js b/client/test/orderLimitSub.js index e97d4122d..cef78e029 100644 --- a/client/test/orderLimitSub.js +++ b/client/test/orderLimitSub.js @@ -2,7 +2,7 @@ import { concat } from 'rxjs/operator/concat' import { assertCompletes, observableInterleave } from './utils' -const orderLimitSubSuite = window.orderLimitSubSuite = getData => () => { +const orderLimitSubSuite = global.orderLimitSubSuite = getData => () => { let data before(() => { diff --git a/client/test/remove.js b/client/test/remove.js index 1428a3e4c..95924ca9f 100644 --- a/client/test/remove.js +++ b/client/test/remove.js @@ -7,7 +7,7 @@ import { ignoreElements } from 'rxjs/operator/ignoreElements' import { assertCompletes, assertThrows, removeAllData } from './utils' -const removeSuite = window.removeSuite = getData => () => { +const removeSuite = global.removeSuite = getData => () => { let data const testData = [ { id: 1, a: 1 }, diff --git a/client/test/removeAll.js b/client/test/removeAll.js index 25584a44a..03ad91613 100644 --- a/client/test/removeAll.js +++ b/client/test/removeAll.js @@ -7,7 +7,7 @@ import { ignoreElements } from 'rxjs/operator/ignoreElements' import { assertCompletes, assertThrows, assertErrors, removeAllData } from './utils' -const removeAllSuite = window.removeAllSuite = getData => () => { +const removeAllSuite = global.removeAllSuite = getData => () => { let data const testData = [ { id: 1, a: 1 }, diff --git a/client/test/replace.js b/client/test/replace.js index f907f43ed..5f2080cb4 100644 --- a/client/test/replace.js +++ b/client/test/replace.js @@ -4,7 +4,7 @@ import { toArray } from 'rxjs/operator/toArray' import { assertCompletes, assertThrows, assertErrors } from './utils' -const replaceSuite = window.replaceSuite = getData => () => { +const replaceSuite = global.replaceSuite = getData => () => { let data before(() => { diff --git a/client/test/store.js b/client/test/store.js index 5d1fa6617..dc0428ea5 100644 --- a/client/test/store.js +++ b/client/test/store.js @@ -4,7 +4,7 @@ import { mergeMap } from 'rxjs/operator/mergeMap' import { toArray } from 'rxjs/operator/toArray' import { assertCompletes, assertThrows, assertErrors } from './utils' -const storeSuite = window.storeSuite = getData => () => { +const storeSuite = global.storeSuite = getData => () => { let data before(() => { diff --git a/client/test/test.js b/client/test/test.js index 92444cd35..5512b288d 100644 --- a/client/test/test.js +++ b/client/test/test.js @@ -1,11 +1,14 @@ const BROWSER = (typeof window !== 'undefined') const path = require('path') +const glob = require('../src/util/glob') + +const global = glob() if (BROWSER) { // Use source maps in mocha errors (ordinarily source maps // only work inside Developer Tools) require('source-map-support/browser-source-map-support.js') - window.sourceMapSupport.install() + global.sourceMapSupport.install() } else { // In node, require source-map-support directly. It is listed // as an external dependency in webpack config, so that it is @@ -14,46 +17,26 @@ if (BROWSER) { } if (BROWSER) { - // Expose window.mocha and window.Mocha + // Expose global.mocha and global.Mocha require('mocha/mocha.js') // Expose globals such as describe() - window.mocha.setup('bdd') - window.mocha.timeout(10000) + global.mocha.setup('bdd') + global.mocha.timeout(10000) } else { - // Emulate window globals in node for now - global.window = global - - // In node, polyfill WebSocket. It is listed as an external dependency - // in webpack config, so that it is not bundled here. - window.WebSocket = require('ws') - - // Polyfill window.location - window.location = { - host: 'localhost:8181', - protocol: 'http:', - hostname: 'localhost', - port: 8181, - } - - // In node, require 'dist/horizon.js' at runtime, so that - // we test the actual packaged module. It is listed as an external - // in webpack config, so that it is not bundled here to avoid - // race conditions when packaging. - if (__dirname.split(path.sep).pop(-1) === 'test') { - window.Horizon = require('../lib/index.js') + global.Horizon = require('../lib/index.js') } else { - window.Horizon = require("./horizon.js") + global.Horizon = require('./horizon.js') } } -window.chai = require('chai/chai.js') -window.chai.config.showDiff = true -window.chai.config.truncateThreshold = 0 -window.expect = window.chai.expect -window.assert = window.chai.assert +global.chai = require('chai/chai.js') +global.chai.config.showDiff = true +global.chai.config.truncateThreshold = 0 +global.expect = global.chai.expect +global.assert = global.chai.assert -window._ = require('lodash/lodash.js') +global._ = require('lodash/lodash.js') // Wait until server is ready before proceeding to tests describe('Waiting until server ready...', function() { @@ -70,7 +53,7 @@ describe('Waiting until server ready...', function() { // Clients dispose by themselves on failure }) } - const connectInterval = setInterval(tryConnecting, 1000) + const connectInterval = setInterval(tryConnecting, 5000) tryConnecting() }) }) diff --git a/client/test/times.js b/client/test/times.js index ebead4ddb..cf6ced9ee 100644 --- a/client/test/times.js +++ b/client/test/times.js @@ -3,7 +3,7 @@ import { toArray } from 'rxjs/operator/toArray' import { assertCompletes } from './utils' -const timesSuite = window.timesSuite = getData => () => { +const timesSuite = global.timesSuite = getData => () => { let data before(() => { diff --git a/client/test/update.js b/client/test/update.js index c0e697009..06dde14a1 100644 --- a/client/test/update.js +++ b/client/test/update.js @@ -5,7 +5,7 @@ import { toArray } from 'rxjs/operator/toArray' import { assertCompletes, assertThrows, assertErrors } from './utils' -const updateSuite = window.updateSuite = getData => () => { +const updateSuite = global.updateSuite = getData => () => { let data before(() => { diff --git a/client/test/upsert.js b/client/test/upsert.js index 6905887db..71b48f9fb 100644 --- a/client/test/upsert.js +++ b/client/test/upsert.js @@ -5,7 +5,7 @@ import { toArray } from 'rxjs/operator/toArray' import { assertCompletes, assertThrows, assertErrors } from './utils' -const upsertSuite = window.upsertSuite = getData => () => { +const upsertSuite = global.upsertSuite = getData => () => { let data before(() => { diff --git a/client/test/utilsTest.js b/client/test/utilsTest.js index 05f253758..4b792a1a2 100644 --- a/client/test/utilsTest.js +++ b/client/test/utilsTest.js @@ -1,6 +1,6 @@ import validIndexValue from '../src/util/valid-index-value' -const utilsSuite = window.utilsSuite = () => { +const utilsSuite = global.utilsSuite = () => { describe('validIndexValue', () => { function assertValid(value) { assert.isTrue(validIndexValue(value), diff --git a/client/webpack.horizon.config.js b/client/webpack.horizon.config.js index 39aa135e6..e6cf9c052 100644 --- a/client/webpack.horizon.config.js +++ b/client/webpack.horizon.config.js @@ -38,24 +38,27 @@ module.exports = function(buildTarget) { } : null, }, - externals: function(context, request, callback) { + externals: [ + function(context, request, callback) { // Selected modules are not packaged into horizon.js. Webpack // allows them to be required natively at runtime, either from // filesystem (node) or window global. - if (!POLYFILL && /^rxjs\/?/.test(request)) { - callback(null, { + if (!POLYFILL && /^rxjs\/?/.test(request)) { + callback(null, { // If loaded via script tag, has to be at window.Rx when // library loads root: 'Rx', // Otherwise imported via `require('rx')` commonjs: 'rxjs', commonjs2: 'rxjs', - amd: 'rxjs', + amd: 'rxjs' }) - } else { - callback() - } - }, + } else { + callback() + } + }, + { ws: 'commonjs ws' } + ], debug: DEV_BUILD, devtool: SOURCEMAPS ? (DEV_BUILD ? 'source-map' : 'source-map') : false, module: { diff --git a/server/package.json b/server/package.json index 813269bc8..afaa94395 100644 --- a/server/package.json +++ b/server/package.json @@ -22,9 +22,10 @@ "node": ">=4.0.0" }, "dependencies": { - "joi": "^8.0.4", "@horizon/client": "0.1.1-0", "cookie": "^0.2.3", + "engine.io": "^1.6.9", + "joi": "^8.0.4", "jsonwebtoken": "^5.5.4", "oauth": "^0.9.14", "pem": "^1.8.1", diff --git a/server/src/client.js b/server/src/client.js index f0679353d..cf68b597f 100644 --- a/server/src/client.js +++ b/server/src/client.js @@ -6,7 +6,6 @@ const schemas = require('./schema/horizon_protocol'); const Joi = require('joi'); const r = require('rethinkdb'); -const websocket = require('ws'); class Request { constructor(client, raw_request) { @@ -61,7 +60,7 @@ class Request { logger.debug(`Error on request ${this.id}: ${err}`); // Ignore responses for disconnected clients - if (this.client.socket.readyState !== websocket.OPEN) { + if (this.client.socket.readyState !== 'open') { return logger.debug(`Disconnected client got an error: ${JSON.stringify(err)}.`); } @@ -130,7 +129,7 @@ class Client { } close_socket(msg, err_info) { - if (this.socket.readyState === websocket.OPEN) { + if (this.socket.readyState === 'open') { if (err_info) { logger.error(`Horizon client request resulted in error: ${err_info}`); } @@ -193,7 +192,7 @@ class Client { metadata.get_user_info(decoded.user, (rdb_err, res) => { if (rdb_err) { this.send_response(request.request_id, { error: 'User does not exist.', error_code: 0 }); - this.socket.close(1002, `Invalid user.`); + this.socket.close(1002, 'Invalid user.'); } else { // TODO: listen on feed success(res, token); @@ -243,7 +242,7 @@ class Client { send_response(request_id, data) { // Ignore responses for disconnected clients - if (this.socket.readyState !== websocket.OPEN) { + if (this.socket.readyState !== 'open') { logger.debug(`Attempted to send a response to a disconnected client: ${JSON.stringify(data)}.`); } else { data.request_id = request_id; diff --git a/server/src/server.js b/server/src/server.js index b9d044a95..4eead6c24 100644 --- a/server/src/server.js +++ b/server/src/server.js @@ -27,7 +27,7 @@ const assert = require('assert'); const fs = require('fs'); const Joi = require('joi'); const url = require('url'); -const websocket = require('ws'); +const websocket = require('engine.io'); const protocol_name = 'rethinkdb-horizon-v0'; @@ -83,19 +83,25 @@ class Server { const verify_client = (info, cb) => { // Reject connections if we aren't synced with the database if (!this._reql_conn.is_ready()) { - cb(false, 503, 'Connection to the database is down.'); + cb(503, false); } else { - cb(true); + cb(false, true); } }; - const ws_options = { handleProtocols: accept_protocol, path: this._path, - verifyClient: verify_client }; + const ws_options = { handleProtocols: accept_protocol, + allowRequest: verify_client }; const add_websocket = (server) => { - this._ws_servers.add(new websocket.Server(Object.assign({}, { server }, ws_options)) - .on('error', (error) => logger.error(`Websocket server error: ${error}`)) - .on('connection', (socket) => new Client(socket, this))); + const ws_server = websocket(Object.assign({}, ws_options)) + .on('error', (error) => logger.error(`Websocket server error: ${error}`)) + .on('connection', (socket) => new Client(socket, this)); + + ws_server.attach(server, { + path: this._path, + }); + + this._ws_servers.add(ws_server); }; const path_replace = new RegExp('^' + this._path + '/'); From 15b2f50cee866a42434e68e0e4b32fc05eaa04b4 Mon Sep 17 00:00:00 2001 From: Josh Kuhn Date: Fri, 13 May 2016 10:30:31 -0700 Subject: [PATCH 2/4] Add utensils object (#351) --- client/src/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/src/index.js b/client/src/index.js index 829851eb7..6b55f4e5f 100644 --- a/client/src/index.js +++ b/client/src/index.js @@ -81,6 +81,12 @@ function Horizon({ horizon.onSocketError = subscribeOrObservable( socket.status::filter(x => x.type === 'error')) + horizon.utensils = { + sendRequest, + tokenStorage, + } + Object.freeze(horizon.utensils) + horizon._authMethods = null horizon._horizonPath = path horizon.authEndpoint = authEndpoint From 33e1ec0ee9627cde9378ba54b71b41ae0bd0e6e7 Mon Sep 17 00:00:00 2001 From: Patrick Neschkudla Date: Fri, 13 May 2016 21:16:01 +0200 Subject: [PATCH 3/4] fix error condition --- client/src/socket.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/src/socket.js b/client/src/socket.js index 5377879b4..f5c970bb0 100644 --- a/client/src/socket.js +++ b/client/src/socket.js @@ -94,9 +94,10 @@ class HorizonSocket extends Subject { // .close is called from the client (see closeSocket), this // listener will be removed statusSubject.next(STATUS_DISCONNECTED) - if (e.code !== 1000 || !e.wasClean) { + if (e !== 'forced close') { subscriber.error( - new Error(`Socket closed unexpectedly with code: ${e.code}`), e) + new Error(`Socket closed unexpectedly with code: ${e}`) + ) } else { subscriber.complete() } From 335c8cb8463c6188bccb3a875d73218471d424a0 Mon Sep 17 00:00:00 2001 From: Patrick Neschkudla Date: Fri, 13 May 2016 21:40:50 +0200 Subject: [PATCH 4/4] set fixed version 1.0.1 of ws package --- client/package.json | 5 ++--- server/package.json | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/client/package.json b/client/package.json index c69f2aab3..8ff6dfff1 100644 --- a/client/package.json +++ b/client/package.json @@ -21,7 +21,7 @@ "isomorphic-fetch": "^2.2.1", "rxjs": "^5.0.0-beta.6", "snake-case": "^1.1.2", - "ws": "^1.0.1" + "ws": "1.0.1" }, "engines": { "node": ">=4.0.0" @@ -46,8 +46,7 @@ "mocha": "2.3.4", "nodemon": "^1.9.1", "source-map-support": "^0.4.0", - "webpack": "^1.12.14", - "ws": "^1.0.1" + "webpack": "^1.12.14" }, "main": "lib/index.js", "repository": { diff --git a/server/package.json b/server/package.json index afaa94395..d9c615866 100644 --- a/server/package.json +++ b/server/package.json @@ -31,7 +31,7 @@ "pem": "^1.8.1", "rethinkdb": "^2.1.1", "winston": "^2.1.0", - "ws": "^1.0.1" + "ws": "1.0.1" }, "devDependencies": { "eslint": "^2.3.0",