diff --git a/app.js b/app.js index fae46c651d8919013322b7ed0fca3c99220bf903..9e012fbe957cc75c79020683c12474069b49cf6b 100644 --- a/app.js +++ b/app.js @@ -26,6 +26,8 @@ const runner = require('./lib/runner.js')(config.runner); const loader = require('./lib/loader.js')('./client'); const controllerFactory = require('./lib/controller.js'); +const proxy = require('./lib/proxy.js')(config.proxy); + console.log('starting hublot...'); loader.loadAll('controller', 'lib', 'robot') @@ -40,6 +42,8 @@ loader.loadAll('controller', 'lib', 'robot') app.listen(config.api, () => { console.log('App listening on port 3000'); }); + + proxy.create(); }) .catch(err => { console.error(err); diff --git a/client/lib/live-reco.js b/client/lib/live-reco.js index 6640e9d32a531e05b647b5ac207e9c858650a090..9b0fb7cc135298757feba2711300934f04381dd2 100644 --- a/client/lib/live-reco.js +++ b/client/lib/live-reco.js @@ -20,51 +20,154 @@ 'use strict'; -/* global robotLib:true Stomp SockJS XMLHttpRequest */ +/* global robotLib:true Stomp SockJS XMLHttpRequest WebSocket */ robotLib.reco = function (config) { let recoStompClient; let connected = false; - function tryConnect() { - recoStompClient = Stomp.over(new SockJS('http://' + config.reco.host + ':' + config.reco.port + '/chat')); - recoStompClient.connect( - {}, - () => { - connected = true; + function connectionHandler() { + const connection = { + getReco: (confId, resolve, reject) => { + const xmlHttp = new XMLHttpRequest(); + + xmlHttp.onreadystatechange = () => { + if (xmlHttp.readyState === 4) { + if (xmlHttp.status === 200) { + resolve(xmlHttp.responseText); + } else { + console.error('Online reco: error trying to reach http://%s:%s/resources', config.reco.host, config.reco.port); + reject(xmlHttp.statusText); + } + } + }; + + const url = 'http://' + config.reco.host + ':' + config.reco.port + '/resources?id=' + confId + '&resources=keywords;wiki'; + xmlHttp.open('GET', url, true); + xmlHttp.setRequestHeader('Content-type', 'application/json'); + xmlHttp.send(null); }, - err => { - connected = false; - console.error('Online reco: STOMP failed to connect to %s:%s (trying again in %d ms)', - config.reco.host, config.reco.port, config.reco.reconnectInterval); - console.error('Online reco: ' + err); - setTimeout(tryConnect, config.reco.reconnectInterval); - }); + send: data => { + recoStompClient.send('/app/chat', {}, data); + }, + + start: confId => { + const xhttp = new XMLHttpRequest(); + xhttp.open('GET', 'http://' + config.reco.host + ':' + config.reco.port + '/stream?action=START&id=' + confId, false); + xhttp.send(); + }, + + stop: confId => { + const xhttp = new XMLHttpRequest(); + xhttp.open('GET', 'http://' + config.reco.host + ':' + config.reco.port + '/stream?action=STOP&id=' + confId, false); + xhttp.send(); + }, + + tryConnect: () => { + recoStompClient = Stomp.over(new SockJS('http://' + config.reco.host + ':' + config.reco.port + '/chat')); + recoStompClient.connect( + {}, + () => { + connected = true; + }, + err => { + connected = false; + + console.error('Online reco: STOMP failed to connect to', + config.reco.host, ':', config.reco.port, + '(trying again in', config.reco.reconnectInterval, 'ms)'); + console.error('Online reco: ' + err); + setTimeout(connection.tryConnect, config.reco.reconnectInterval); + }); + } + }; + + return connection; } - tryConnect(); + function proxifiedConnectionHandler() { + const connection = { + getReco: (confId, resolve, reject) => { + const ws = new WebSocket('ws://' + config.reco.host + ':' + config.reco.port + '/reco'); + ws.onopen = function () { + ws.send('/resources?id=' + confId + '&resources=keywords;wiki'); + }; + ws.onerror = function (event) { + reject(event); + }; + ws.onmessage = function (event) { + ws.close(); + resolve(event.data); + }; + }, + + send: data => { + recoStompClient.send(data); + }, + + start: confId => { + const ws = new WebSocket('ws://' + config.reco.host + ':' + config.reco.port + '/startstop'); + ws.onopen = function () { + ws.send('/stream?action=START&id=' + confId); + ws.close(); + }; + }, + + stop: confId => { + const ws = new WebSocket('ws://' + config.reco.host + ':' + config.reco.port + '/startstop'); + ws.onopen = function () { + ws.send('/stream?action=STOP&id=' + confId); + ws.close(); + }; + }, + + tryConnect: () => { + const ws = new WebSocket('ws://' + config.reco.host + ':' + config.reco.port + '/chat'); + + ws.onopen = function () { + connected = true; + }; + ws.onclose = function () { + connected = false; + }; + ws.onerror = function () { + setTimeout(connection.tryConnect, config.reco.reconnectInterval); + }; + recoStompClient = ws; + } + }; + + return connection; + } + + function createConnection() { + if (config.proxified) { + return proxifiedConnectionHandler(); + } + return connectionHandler(); + } + + const connection = createConnection(); + + connection.tryConnect(); return { - start: confid => { + start: confId => { if (!connected) { - console.error('Online reco: not connected but trying to send start to conf %s', confid); + console.error('Online reco: not connected but trying to send start to conf %s', confId); return false; } - const xhttp = new XMLHttpRequest(); - xhttp.open('GET', 'http://' + config.reco.host + ':' + config.reco.port + '/stream?action=START&id=' + confid, false); - xhttp.send(); + connection.start(confId); return true; }, - stop: confid => { + stop: confId => { if (!connected) { - console.error('Online reco: not connected but trying to send stop to conf %s', confid); + console.error('Online reco: not connected but trying to send stop to conf %s', confId); return false; } - const xhttp = new XMLHttpRequest(); - xhttp.open('GET', 'http://' + config.reco.host + ':' + config.reco.port + '/stream?action=STOP&id=' + confid, false); - xhttp.send(); + connection.stop(confId); return true; }, @@ -73,29 +176,13 @@ robotLib.reco = function (config) { console.error('Online reco: not connected but trying to send %j', content); return false; } - recoStompClient.send('/app/chat', {}, JSON.stringify(content)); + connection.send(JSON.stringify(content)); return true; }, getOnlineReco: confId => { return new Promise((resolve, reject) => { - const xmlHttp = new XMLHttpRequest(); - - xmlHttp.onreadystatechange = () => { - if (xmlHttp.readyState === 4) { - if (xmlHttp.status === 200) { - resolve(xmlHttp.responseText); - } else { - console.error('Online reco: error trying to reach http://%s:%s/resources', config.reco.host, config.reco.port); - reject(xmlHttp.statusText); - } - } - }; - - const url = 'http://' + config.reco.host + ':' + config.reco.port + '/resources?id=' + confId + '&resources=keywords;wiki'; - xmlHttp.open('GET', url, true); - xmlHttp.setRequestHeader('Content-type', 'application/json'); - xmlHttp.send(null); + connection.getReco(confId, resolve, reject); }); } }; diff --git a/client/lib/speech-to-text.js b/client/lib/speech-to-text.js index c1705152241f552e6d652b899c305dc8a8977ffe..3265dee56b119221950150ded0fe3e6b205183d2 100644 --- a/client/lib/speech-to-text.js +++ b/client/lib/speech-to-text.js @@ -26,7 +26,7 @@ robotLib.stt = function (config) { return { getTranscriptSocket: onSegment => { try { - const ws = new WebSocket(config.gstreamerURL + '/client/ws/speech?content-type=audio/x-matroska,,+rate=(int)48000,+channels=(int)1'); + const ws = new WebSocket(config.gstreamerURL); ws.onopen = function () { console.info('ws to stt module open'); }; diff --git a/config.json b/config.json index 70efd365687aa8f861832dcfccae9f51bd15fe56..3dbabad97a93c401c7efe737e1482fa4536c22a9 100644 --- a/config.json +++ b/config.json @@ -7,9 +7,12 @@ "puppeteer": { "headless": true, "args" : [ - "--disable-web-security", + "--remote-debugging-address=0.0.0.0", + "--remote-debugging-port=9999", + "--disable-gpu", + "--allow-insecure-localhost", + "--no-sandbox", "--user-data-dir=./tmp/chromium", - "--allow-running-insecure-content", "--use-fake-device-for-media-stream", "--use-file-for-fake-audio-capture=/opt/media/silence.wav", "--use-file-for-fake-video-capture=/opt/media/logo.y4m", @@ -20,17 +23,29 @@ "client": { "name": "hublot", "avatar": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEoAAABECAYAAAAm2qMBAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4QYNDTU7dwT3OwAABUtJREFUeNrtnF1oHFUUx38zjUlabWKtELU3WLQPFrSOgopaRawmIZdqLVTtQ1R8sVqsH9SvQptKBaWF6oMiLYhUKiLYtMVOGqu0Kgnq260txQejEIZU0BRrqsaQZH2YO3Hczu7Ofszs1/xhyWaZPXvnN+fOPffcc8cgBlm2g5LCe38xcBtgAdcAi4HLgUuAi4BG/bVJ4BxwBhgFfgZ+ABQwpKQYT7cdpYyY4KwCHgDuB1pL9BNjwEFgv5LiUNTQogTVCTwF3Ec86gPeVlIciwKaEQGgp4HtQDPl0TiwUUmxu5TAjBJ2r2eAt6gcpYAnlRS7LNsBKAqYUSwky3Y6gAPAXCpTfwArlRRfF+NdRhGA5gH7gC6qQ33AWj2a5g3MKBDSzcB32r2NKgGV0q8blBTf5/tlswBImzQkqgiS11YTOG7ZznrvnErqUT5I+4DV1IY+UFI8Gva+ZeQBaUhH1LWkz5UUHWFgGSEhfQPcUmVdLayOKilW5IJlhIA0AHTUKCRPnygp1hTjUTuB56gPbVZSvFaIR3UCA9SXblVSfBsKlB4ym4AJ6lNGUEB6XhylD/iiTiGlgMNBN3UzwKPWAsvr2Ju6LNvpDhOZf0iij7KCsmxna42HAWHVYtnO89k8qjdhNKsdgaAs23k2YfP/3mbZzmNBHrUxYXOeXpi9y+u46VrgRMIlUO1KCsfUMUNPwiOj1vm7XgIqs1Z7N6xm3JXaRMFa6nmUTFhkl2U7KxqAZTHMn8aBaWA+0FAiu1Pa7hxtN8pA+c4GPeJFpd+Aq7yCCn11jgD3Fmm3X0khfTYXAMPAgojO40rDsh0FXB+B8UklRVMGV94DPFKg3V1KinUZ7E5pDyu1Bk2gLaKrsCnLctAThRrNAgnglYjO5QozQnc9l+VkJ+L+zSLVauJmM6NQm16cCLr69xQxAt0U5E06cF4U0bk0GZbtpCK8mS9RUgynV5NYtvMnMK9Am2eUFAt93c1bLVoKnIrKUw3LdiYi9CqA94CX9XC+BthdIruPA/txSxl3FDE4hNGYYdnOaeCyJKzMqmET+CXhkFOnTeCnhENO/WgCJxMOOTViAscTDjn1lQn0JxxyzgaOmjpKHk1wZNQp+C/DubcMDZjBrdgNM52Z0MfOlKGdfeBmOAHeL0MDmpUUrbhbPtpwc9N9+p55AvgU2ICbfW3Rx15Yhna+C75kl2U7I0B7TD++RUmxLWCuFmau1wtsjamdJ5UU1/m7HsCbMV6lKf9kOQ9IoOvEY9JO742R1pBUXC1QUhSUuo2xjTNKitkkYHr+uhd4NY5WWLbzNzAIbMbdgzeppJhJO8bQk95lwOvEW470ov+foIq7GeKvaJkGfgf+0l0rpQHNxU0sNsTcnnElRYv/g6AG9JQhXJgDLNSvStDD6R8YGbrFIHB7nQaYh5UU3TlB6ZGlEfinTkGZQCp9JM5WPi2BQ3UGabmSYigTvUzDt01a1VmNqzcTJAi3aegA7u7yWtZeJUVPrv6YNRJWUqwCvqxhSP1Kip5ce/fy2YZ2DLirxiAdUVJ0Fr0NLQDWx8CDtUJJSWGEnZCbIQ16sB4CttQIp3fymZCbedD3/m4D7sBd0KxmjeUbXBXisoO4D535rIpBLY4clG/i2AV04z6Rp9qU1xJ8SbIElu2YuGnbN4i2jqHUeklJsT02UD5gjbhFYr0VlAnIpUXAaEnCgwKhdQHrgU7gggoG9SvuAsZ0NlhmhA0YUFKsBFpwH7K1R480lTZaXgqMkOMhPLFkMtMen9QO3AhcjVuRvAR39Wc+7nJUObwvBZwF7s703JZ/AccI0dMbvIyTAAAAAElFTkSuQmCC", - "gstreamerURL": "ws://kaldi-gstreamer:80", + "proxified": true, + "gstreamerURL": "ws://localhost:3001/kaldi", "externalLibs": [ "https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.1.4/sockjs.min.js", "https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js" ], "archive": "http://localhost:8080/api/summary", "reco": { - "host": "recommender", - "port": 8080, + "host": "localhost", + "port": 3001, "reconnectInterval": 5000 } }, - "api": 3000 + "api": 3000, + "proxy": { + "port": 3001, + "services": { + "reco": { + "host": "hublot_recommender_1", + "port": 8080, + "reconnectInterval": 5000 + }, + "kaldi": "ws://hublot_kaldi-gstreamer_1:80/client/ws/speech?content-type=audio/x-matroska,+rate=(int)48000,+channels=(int)" + } + } } diff --git a/lib/proxy.js b/lib/proxy.js new file mode 100644 index 0000000000000000000000000000000000000000..dbd355894e60515fe15f83f8bbeabe8b49c199ca --- /dev/null +++ b/lib/proxy.js @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2017 Linagora. + * + * This file is part of Hublot + * (see https://ci.linagora.com/linagora/lgs/labs/hublot). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +const http = require('http'); +const SockJS = require('sockjs-client'); +const stomp = require('webstomp-client'); +const WebSocket = require('ws'); +const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; + +module.exports = config => { + function createStompClient() { + const stompCapsule = { + get: null + }; + + function tryConnect() { + console.log('proxy: connecting to STOMP...'); + + const sock = new SockJS('http://' + config.services.reco.host + ':' + config.services.reco.port + '/chat'); + stompCapsule.get = stomp.over(sock, { + debug: false + }); + + stompCapsule.get.connect( + {}, + () => console.log('proxy: STOMP connected'), + err => { + console.error( + 'proxy: STOMP failed to connect to %s:%s (trying again in %d ms)', + config.services.reco.host, config.services.reco.port, config.services.reco.reconnectInterval); + console.error(err); + setTimeout(tryConnect, config.services.reco.reconnectInterval); + }); + } + tryConnect(); + + return stompCapsule; + } + + function kaldiWS(connectionToClient) { + const connectionToKaldi = new WebSocket(config.services.kaldi); + connectionToKaldi.on('open', () => { + connectionToClient.on('message', message => { + connectionToKaldi.send(message, { + binary: true + }); + }); + connectionToKaldi.on('message', message => { + try { + connectionToClient.send(message); + } catch (err) { + // Sometimes, the client will close the connection unexpectedly + // (e.g. when stopping). This is expected + } + }); + + connectionToClient.on('close', () => connectionToKaldi.close()); + connectionToKaldi.on('close', () => connectionToClient.close()); + }); + } + + function recoChatWS(connectionToClient, stompClient) { + connectionToClient.on('message', message => { + try { + stompClient.get.send('/app/chat', message); + } catch (err) { + console.error('proxy: chatWS', err); + } + }); + + connectionToClient.on('error', error => { + console.error('proxy: WS chat error', error); + }); + } + + function recoStartStopWS(connectionToClient) { + connectionToClient.on('message', message => { + const xmlHttp = new XMLHttpRequest(); + const url = 'http://' + config.services.reco.host + ':' + config.services.reco.port + message; + xmlHttp.open('GET', url, true); + xmlHttp.setRequestHeader('Content-type', 'application/json'); + xmlHttp.send(null); + + connectionToClient.close(); + }); + + connectionToClient.on('error', error => { + console.error('proxy: WS reco error', error); + }); + } + + function recoRecoWS(connectionToClient) { + connectionToClient.on('message', message => { + const xmlHttp = new XMLHttpRequest(); + + xmlHttp.onreadystatechange = () => { + if (xmlHttp.readyState === 4) { + if (xmlHttp.status === 200) { + try { + connectionToClient.send(xmlHttp.responseText); + } catch (err) { + console.error('proxy: recoRecoWS error', err); + } + } else { + console.error('Online reco: error trying to reach http://%s:%s/resources', + config.services.reco.host, config.services.reco.port); + } + connectionToClient.close(); + } + }; + + const url = 'http://' + config.services.reco.host + ':' + config.services.reco.port + message; + xmlHttp.open('GET', url, true); + xmlHttp.setRequestHeader('Content-type', 'application/json'); + xmlHttp.send(null); + }); + + connectionToClient.on('error', error => { + console.error('proxy: WS reco error', error); + }); + } + + return { + create: () => { + const server = http.createServer(); + + const stompClient = createStompClient(); + + const wssServer = new WebSocket.Server({ + server, + autoAcceptConnections: true + }); + + wssServer.on('connection', (connectionToClient, req) => { + if (req.url === '/kaldi') { + kaldiWS(connectionToClient); + return; + } + if (req.url === '/chat') { + recoChatWS(connectionToClient, stompClient); + return; + } + if (req.url === '/startstop') { + recoStartStopWS(connectionToClient); + return; + } + if (req.url === '/reco') { + recoRecoWS(connectionToClient); + return; + } + console.error('proxy: unknown path for ws connection', req.url); + }); + + server.listen(config.port); + + console.log('Proxy listening on port', config.port); + } + }; +}; diff --git a/package.json b/package.json index d91024aa807b82f39b4d8aeca31b00eec9c3083f..a3e7db712a5d227ba5ee19b87667b2b0eb173a07 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,11 @@ "body-parser": "^1.18.2", "express": "^4.16.2", "mz": "2.6.0", - "puppeteer": "0.12.0" + "puppeteer": "0.12.0", + "sockjs-client": "1.1.4", + "webstomp-client": "1.2.0", + "ws": "3.3.1", + "xmlhttprequest": "1.8.0 " }, "devDependencies": { "jest": "20.0.0", diff --git a/yarn.lock b/yarn.lock index b2123d870d46e84ddeb8e6406c808386325c5f7c..395a8d577a24a0331ae38a0db18bcdac31c5aa86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -699,7 +699,7 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.4.1, debug@^2.6.8: +debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.4.1, debug@^2.6.6, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -1097,6 +1097,12 @@ event-emitter@~0.3.5: d "1" es5-ext "~0.10.14" +eventsource@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-0.1.6.tgz#0acede849ed7dd1ccc32c811bb11b944d4f29232" + dependencies: + original ">=0.0.5" + exec-sh@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" @@ -1213,6 +1219,12 @@ fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" +faye-websocket@~0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" + dependencies: + websocket-driver ">=0.5.1" + fb-watchman@^1.8.0: version "1.9.2" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383" @@ -1546,6 +1558,10 @@ http-errors@1.6.2, http-errors@~1.6.2: setprototypeof "1.0.3" statuses ">= 1.3.1 < 2" +http-parser-js@>=0.4.0: + version "0.4.9" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.9.tgz#ea1a04fb64adff0242e9974f297dd4c3cad271e1" + http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -1598,7 +1614,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.3, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -1823,7 +1839,7 @@ is-stream@^1.0.0, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" -is-typedarray@^1.0.0, is-typedarray@~1.0.0: +is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -2192,6 +2208,10 @@ json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" +json3@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" @@ -2490,10 +2510,6 @@ mz@2.6.0: object-assign "^4.0.1" thenify-all "^1.0.0" -nan@^2.3.3: - version "2.7.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46" - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -2607,6 +2623,12 @@ optionator@^0.8.1, optionator@^0.8.2: type-check "~0.3.2" wordwrap "~1.0.0" +original@>=0.0.5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.0.tgz#9147f93fa1696d04be61e01bd50baeaca656bd3b" + dependencies: + url-parse "1.0.x" + os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" @@ -2855,6 +2877,14 @@ qs@6.5.1, qs@~6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" +querystringify@0.0.x: + version "0.0.4" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-0.0.4.tgz#0cf7f84f9463ff0ae51c4c4b142d95be37724d9c" + +querystringify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" + randomatic@^1.1.3: version "1.1.7" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" @@ -3030,6 +3060,10 @@ require-uncached@^1.0.2: caller-path "^0.1.0" resolve-from "^1.0.0" +requires-port@1.0.x, requires-port@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + resolve-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-1.0.0.tgz#4eaeea41ed040d1702457df64a42b2b07d246f9f" @@ -3208,6 +3242,17 @@ sntp@2.x.x: dependencies: hoek "4.x.x" +sockjs-client@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.4.tgz#5babe386b775e4cf14e7520911452654016c8b12" + dependencies: + debug "^2.6.6" + eventsource "0.1.6" + faye-websocket "~0.11.0" + inherits "^2.0.1" + json3 "^3.3.2" + url-parse "^1.1.8" + sort-keys@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" @@ -3483,12 +3528,6 @@ type-is@~1.6.15: media-typer "0.3.0" mime-types "~2.1.15" -typedarray-to-buffer@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.2.tgz#1017b32d984ff556eba100f501589aba1ace2e04" - dependencies: - is-typedarray "^1.0.0" - typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -3544,6 +3583,20 @@ url-parse-lax@^1.0.0: dependencies: prepend-http "^1.0.1" +url-parse@1.0.x: + version "1.0.5" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b" + dependencies: + querystringify "0.0.x" + requires-port "1.0.x" + +url-parse@^1.1.8: + version "1.2.0" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.2.0.tgz#3a19e8aaa6d023ddd27dcc44cb4fc8f7fec23986" + dependencies: + querystringify "~1.0.0" + requires-port "~1.0.0" + user-home@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" @@ -3599,14 +3652,20 @@ webidl-conversions@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" -websocket@1.0.25: - version "1.0.25" - resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.25.tgz#998ec790f0a3eacb8b08b50a4350026692a11958" +websocket-driver@>=0.5.1: + version "0.7.0" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" dependencies: - debug "^2.2.0" - nan "^2.3.3" - typedarray-to-buffer "^3.1.2" - yaeti "^0.0.6" + http-parser-js ">=0.4.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.2.tgz#0e18781de629a18308ce1481650f67ffa2693a5d" + +webstomp-client@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/webstomp-client/-/webstomp-client-1.2.0.tgz#454da66c2ff86c4a876f04218b6d9de8946e596b" whatwg-encoding@^1.0.1: version "1.0.2" @@ -3703,6 +3762,14 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" +ws@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.1.tgz#d97e34dee06a1190c61ac1e95f43cb60b78cf939" + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + ws@^3.0.0: version "3.3.0" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.0.tgz#f8b948a1378af7efa702f5513da08dd516897c31" @@ -3719,6 +3786,10 @@ xml-name-validator@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" +"xmlhttprequest@1.8.0 ": + version "1.8.0" + resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" + xo-init@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/xo-init/-/xo-init-0.5.0.tgz#8e28dec79676cc5e042fde5fd8f710e2646b0e36" @@ -3769,10 +3840,6 @@ y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" -yaeti@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" - yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"