diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.js index cf46475344f..e4c4a0d746a 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/connection.js @@ -23,7 +23,6 @@ 'use strict'; const EventEmitter = require('events'); -const WebSocket = require('ws'); const util = require('util'); const utils = require('../utils'); const serializer = require('../structure/io/graph-serializer'); @@ -120,38 +119,33 @@ class Connection extends EventEmitter { this.emit('log', `ws open`); - this._ws = new WebSocket(this.url, { - headers: this.options.headers, - ca: this.options.ca, - cert: this.options.cert, - pfx: this.options.pfx, - rejectUnauthorized: this.options.rejectUnauthorized - }); + this._ws = new WebSocket(this.url); - this._ws.on('message', (data) => this._handleMessage(data)); - this._ws.on('close', (code, message) => this._handleClose(code, message)); + this._ws.onmessage = (data => this._handleMessage(data)); + this._ws.onerror = (err => this._handleError(err)); + this._ws.onclose = ((code, message) => this._handleClose(code, message)); - this._ws.on('pong', () => { + this._ws.pong = (() => { this.emit('log', 'ws pong received'); - if (this._pongTimeout) { - clearTimeout(this._pongTimeout); - this._pongTimeout = null; - } - }); - this._ws.on('ping', () => { + if (this._pongTimeout) { + clearTimeout(this._pongTimeout); + this._pongTimeout = null; + } + }); + this._ws.ping = (() => { this.emit('log', 'ws ping received'); - this._ws.pong(); - }); + this._ws.pong(); + }); return this._openPromise = new Promise((resolve, reject) => { - this._ws.on('open', () => { - this.isOpen = true; - if (this._pingEnabled) { - this._pingHeartbeat(); - } - resolve(); - }); - this._ws.on('error', (err) => { + this._ws.onopen = (() => { + this.isOpen = true; + if (this._pingEnabled) { + this._pingHeartbeat(); + } + resolve(); + }); + this._ws.on('error', (err) => { this._handleError(err); reject(err); }); @@ -163,14 +157,20 @@ class Connection extends EventEmitter { const rid = requestId || utils.getUuid(); return this.open().then(() => new Promise((resolve, reject) => { if (op !== 'authentication') { - this._responseHandlers[rid] = { - callback: (err, result) => err ? reject(err) : resolve(result), + this._responseHandlers[rid] = { + callback: (err, result) => err ? reject(err) : resolve(result), result: null - }; - } + }; + } - const message = Buffer.from(this._header + JSON.stringify(this._getRequest(rid, op, args, processor))); - this._ws.send(message); + const message = this._header + JSON.stringify(this._getRequest(requestId, bytecode, op, args, processor)); + var buf = new ArrayBuffer(message.length); // 2 bytes for each char + var bufView = new Uint8Array(buf); + for (var i=0, strLen=message.length; i < strLen; i++) { + bufView[i] = message.charCodeAt(i); + } + this._ws.binaryType = 'arraybuffer'; + this._ws.send(bufView); })); } @@ -197,6 +197,7 @@ class Connection extends EventEmitter { args['gremlin'] = this._writer.adaptObject(args['gremlin']); } + return ({ 'requestId': { '@type': 'g:UUID', '@value': id }, 'op': op || 'bytecode', @@ -215,20 +216,20 @@ class Connection extends EventEmitter { this._pingInterval = setInterval(() => { if (this.isOpen === false) { - // in case of if not open.. - if (this._pingInterval) { - clearInterval(this._pingInterval); - this._pingInterval = null; - } + // in case of if not open.. + if (this._pingInterval) { + clearInterval(this._pingInterval); + this._pingInterval = null; } + } - this._pongTimeout = setTimeout(() => { - this._ws.terminate(); - }, this._pongTimeoutDelay); + this._pongTimeout = setTimeout(() => { + this._ws.terminate(); + }, this._pongTimeoutDelay); - this._ws.ping(); + this._ws.ping(); - }, this._pingIntervalDelay); + }, this._pingIntervalDelay); } _handleError(err) { @@ -246,8 +247,14 @@ class Connection extends EventEmitter { this.emit('close', code, message); } - _handleMessage(data) { - const response = this._reader.read(JSON.parse(data.toString())); + _handleMessage(msg) { + if(msg.data instanceof ArrayBuffer ) { + //if in browser javascript, the data are sent as Uint8 + var data = String.fromCharCode.apply(null, new Uint8Array(msg.data)); + }else{ + data = msg; + } + const response = this._reader.read(JSON.parse(data)); if (response.requestId === null || response.requestId === undefined) { // There was a serialization issue on the server that prevented the parsing of the request id // We invoke any of the pending handlers with an error @@ -278,7 +285,7 @@ class Connection extends EventEmitter { if (response.status.code === responseStatusCode.authenticationChallenge && this._authenticator) { this._authenticator.evaluateChallenge(response.result.data).then(res => { return this.submit(undefined, 'authentication', res, response.requestId); - }).catch(handler.callback); + }).catch(handler.callback); return; } @@ -351,10 +358,10 @@ class Connection extends EventEmitter { // in another map for types like EnumValue. Could be a nicer way to do this but for now it's solving the // problem with script submission of non JSON native types if (protocolLevel && key === 'bindings') - newObj[key] = this._adaptArgs(args[key], false); - else - newObj[key] = this._writer.adaptObject(args[key]); - }); + newObj[key] = this._adaptArgs(args[key], false); + else + newObj[key] = this._writer.adaptObject(args[key]); + }); return newObj; } @@ -373,8 +380,8 @@ class Connection extends EventEmitter { if (!this._closePromise) { this._closePromise = new Promise(resolve => { this._closeCallback = resolve; - this._ws.close(); - }); + this._ws.close(); + }); } return this._closePromise; } diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/utils.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/utils.js index f996dba879f..a8c5d261feb 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/utils.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/utils.js @@ -23,7 +23,7 @@ */ 'use strict'; -const crypto = require('crypto'); +const uuidv4 = require('uuid/v4'); exports.toLong = function toLong(value) { return new Long(value); @@ -37,22 +37,7 @@ const Long = exports.Long = function Long(value) { }; exports.getUuid = function getUuid() { - const buffer = crypto.randomBytes(16); - //clear the version - buffer[6] &= 0x0f; - //set the version 4 - buffer[6] |= 0x40; - //clear the variant - buffer[8] &= 0x3f; - //set the IETF variant - buffer[8] |= 0x80; - const hex = buffer.toString('hex'); - return ( - hex.substr(0, 8) + '-' + - hex.substr(8, 4) + '-' + - hex.substr(12, 4) + '-' + - hex.substr(16, 4) + '-' + - hex.substr(20, 12)); + return uuidv4(); }; exports.emptyArray = Object.freeze([]); diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json b/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json index ce4a26743cd..59a1f45f943 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json @@ -14,15 +14,19 @@ ], "license": "Apache-2.0", "dependencies": { - "ws": "^6.2.2" + "ws": "^6.2.2", + "util": "^0.11.1", + "events": "^3.0.0", + "uuid": "^3.3.2" }, "devDependencies": { - "chai": "~4.1.2", - "cucumber": "~4.2.1", + "cucumber": "~5.1.0", + "chai": "~4.2.0", "grunt": "~1.2.0", "grunt-cli": "~1.3.2", "grunt-jsdoc": "~2.4.1", - "mocha": "~5.2.0" + "mocha": "~5.2.0", + "uuid": "^3.3.2" }, "repository": { "type": "git",