From b6ce1c65fb6b566c3cba25676402f534e98aca59 Mon Sep 17 00:00:00 2001 From: Justin Bertram Date: Wed, 20 Sep 2017 11:01:14 -0500 Subject: [PATCH] ARTEMIS-1426 update stomp.js for chat example Our copy of the stomp.js library hasn't been updated since the end of 2012. Lots of nice changes have been made since then. Pulled from https://github.com/jmesnil/stomp-websocket/blob/master/lib/stomp.js. --- .../stomp/stomp-websockets/chat/stomp.js | 374 ++++++++++++------ 1 file changed, 248 insertions(+), 126 deletions(-) diff --git a/examples/protocols/stomp/stomp-websockets/chat/stomp.js b/examples/protocols/stomp/stomp-websockets/chat/stomp.js index 2d68945566..a998d191ff 100644 --- a/examples/protocols/stomp/stomp-websockets/chat/stomp.js +++ b/examples/protocols/stomp/stomp-websockets/chat/stomp.js @@ -17,10 +17,10 @@ * under the License. */ -// Generated by CoffeeScript 1.3.3 (function() { var Byte, Client, Frame, Stomp, - __hasProp = {}.hasOwnProperty; + __hasProp = {}.hasOwnProperty, + __slice = [].slice; Byte = { LF: '\x0A', @@ -28,6 +28,7 @@ }; Frame = (function() { + var unmarshallSingle; function Frame(command, headers, body) { this.command = command; @@ -36,23 +37,35 @@ } Frame.prototype.toString = function() { - var lines, name, value, _ref; + var lines, name, skipContentLength, value, _ref; lines = [this.command]; + skipContentLength = this.headers['content-length'] === false ? true : false; + if (skipContentLength) { + delete this.headers['content-length']; + } _ref = this.headers; for (name in _ref) { if (!__hasProp.call(_ref, name)) continue; value = _ref[name]; lines.push("" + name + ":" + value); } - if (this.body) { - lines.push("content-length:" + ('' + this.body).length); + if (this.body && !skipContentLength) { + lines.push("content-length:" + (Frame.sizeOfUTF8(this.body))); } lines.push(Byte.LF + this.body); return lines.join(Byte.LF); }; - Frame._unmarshallSingle = function(data) { - var body, chr, command, divider, headerLines, headers, i, idx, len, line, start, trim, _i, _j, _ref, _ref1; + Frame.sizeOfUTF8 = function(s) { + if (s) { + return encodeURI(s).match(/%..|./g).length; + } else { + return 0; + } + }; + + unmarshallSingle = function(data) { + var body, chr, command, divider, headerLines, headers, i, idx, len, line, start, trim, _i, _j, _len, _ref, _ref1; divider = data.search(RegExp("" + Byte.LF + Byte.LF)); headerLines = data.substring(0, divider).split(Byte.LF); command = headerLines.shift(); @@ -60,9 +73,9 @@ trim = function(str) { return str.replace(/^\s+|\s+$/g, ''); }; - line = idx = null; - for (i = _i = 0, _ref = headerLines.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { - line = headerLines[i]; + _ref = headerLines.reverse(); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + line = _ref[_i]; idx = line.indexOf(':'); headers[trim(line.substring(0, idx))] = trim(line.substring(idx + 1)); } @@ -85,19 +98,29 @@ }; Frame.unmarshall = function(datas) { - var data; - return (function() { + var frame, frames, last_frame, r; + frames = datas.split(RegExp("" + Byte.NULL + Byte.LF + "*")); + r = { + frames: [], + partial: '' + }; + r.frames = (function() { var _i, _len, _ref, _results; - _ref = datas.split(RegExp("" + Byte.NULL + Byte.LF + "*")); + _ref = frames.slice(0, -1); _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { - data = _ref[_i]; - if ((data != null ? data.length : void 0) > 0) { - _results.push(Frame._unmarshallSingle(data)); - } + frame = _ref[_i]; + _results.push(unmarshallSingle(frame)); } return _results; })(); + last_frame = frames.slice(-1)[0]; + if (last_frame === Byte.LF || (last_frame.search(RegExp("" + Byte.NULL + Byte.LF + "*$"))) !== -1) { + r.frames.push(unmarshallSingle(last_frame)); + } else { + r.partial = last_frame; + } + return r; }; Frame.marshall = function(command, headers, body) { @@ -111,6 +134,7 @@ })(); Client = (function() { + var now; function Client(ws) { this.ws = ws; @@ -121,21 +145,45 @@ outgoing: 10000, incoming: 10000 }; + this.maxWebSocketFrameSize = 16 * 1024; this.subscriptions = {}; + this.partialData = ''; } + Client.prototype.debug = function(message) { + var _ref; + return typeof window !== "undefined" && window !== null ? (_ref = window.console) != null ? _ref.log(message) : void 0 : void 0; + }; + + now = function() { + if (Date.now) { + return Date.now(); + } else { + return new Date().valueOf; + } + }; + Client.prototype._transmit = function(command, headers, body) { var out; out = Frame.marshall(command, headers, body); if (typeof this.debug === "function") { this.debug(">>> " + out); } - return this.ws.send(out); + while (true) { + if (out.length > this.maxWebSocketFrameSize) { + this.ws.send(out.substring(0, this.maxWebSocketFrameSize)); + out = out.substring(this.maxWebSocketFrameSize); + if (typeof this.debug === "function") { + this.debug("remaining = " + out.length); + } + } else { + return this.ws.send(out); + } + } }; Client.prototype._setupHeartbeat = function(headers) { - var serverIncoming, serverOutgoing, ttl, v, _ref, _ref1, - _this = this; + var serverIncoming, serverOutgoing, ttl, v, _ref, _ref1; if ((_ref = headers.version) !== Stomp.VERSIONS.V1_1 && _ref !== Stomp.VERSIONS.V1_2) { return; } @@ -154,132 +202,179 @@ if (typeof this.debug === "function") { this.debug("send PING every " + ttl + "ms"); } - this.pinger = typeof window !== "undefined" && window !== null ? window.setInterval(function() { - _this.ws.send(Byte.LF); - return typeof _this.debug === "function" ? _this.debug(">>> PING") : void 0; - }, ttl) : void 0; + this.pinger = Stomp.setInterval(ttl, (function(_this) { + return function() { + _this.ws.send(Byte.LF); + return typeof _this.debug === "function" ? _this.debug(">>> PING") : void 0; + }; + })(this)); } if (!(this.heartbeat.incoming === 0 || serverOutgoing === 0)) { ttl = Math.max(this.heartbeat.incoming, serverOutgoing); if (typeof this.debug === "function") { this.debug("check PONG every " + ttl + "ms"); } - return this.ponger = typeof window !== "undefined" && window !== null ? window.setInterval(function() { - var delta; - delta = Date.now() - _this.serverActivity; - if (delta > ttl * 2) { - if (typeof _this.debug === "function") { - _this.debug("did not receive server activity for the last " + delta + "ms"); + return this.ponger = Stomp.setInterval(ttl, (function(_this) { + return function() { + var delta; + delta = now() - _this.serverActivity; + if (delta > ttl * 2) { + if (typeof _this.debug === "function") { + _this.debug("did not receive server activity for the last " + delta + "ms"); + } + return _this.ws.close(); } - return _this._cleanUp(); - } - }, ttl) : void 0; + }; + })(this)); } }; - Client.prototype.connect = function(login, passcode, connectCallback, errorCallback, vhost) { - var _this = this; - this.connectCallback = connectCallback; + Client.prototype._parseConnect = function() { + var args, connectCallback, errorCallback, headers; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + headers = {}; + switch (args.length) { + case 2: + headers = args[0], connectCallback = args[1]; + break; + case 3: + if (args[1] instanceof Function) { + headers = args[0], connectCallback = args[1], errorCallback = args[2]; + } else { + headers.login = args[0], headers.passcode = args[1], connectCallback = args[2]; + } + break; + case 4: + headers.login = args[0], headers.passcode = args[1], connectCallback = args[2], errorCallback = args[3]; + break; + default: + headers.login = args[0], headers.passcode = args[1], connectCallback = args[2], errorCallback = args[3], headers.host = args[4]; + } + return [headers, connectCallback, errorCallback]; + }; + + Client.prototype.connect = function() { + var args, errorCallback, headers, out; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + out = this._parseConnect.apply(this, args); + headers = out[0], this.connectCallback = out[1], errorCallback = out[2]; if (typeof this.debug === "function") { this.debug("Opening Web Socket..."); } - this.ws.onmessage = function(evt) { - var arr, c, data, frame, onreceive, _i, _len, _ref, _results; - data = typeof ArrayBuffer !== 'undefined' && evt.data instanceof ArrayBuffer ? (arr = new Uint8Array(evt.data), typeof _this.debug === "function" ? _this.debug("--- got data length: " + arr.length) : void 0, ((function() { - var _i, _len, _results; + this.ws.onmessage = (function(_this) { + return function(evt) { + var arr, c, client, data, frame, messageID, onreceive, subscription, unmarshalledData, _i, _len, _ref, _results; + data = typeof ArrayBuffer !== 'undefined' && evt.data instanceof ArrayBuffer ? (arr = new Uint8Array(evt.data), typeof _this.debug === "function" ? _this.debug("--- got data length: " + arr.length) : void 0, ((function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = arr.length; _i < _len; _i++) { + c = arr[_i]; + _results.push(String.fromCharCode(c)); + } + return _results; + })()).join('')) : evt.data; + _this.serverActivity = now(); + if (data === Byte.LF) { + if (typeof _this.debug === "function") { + _this.debug("<<< PONG"); + } + return; + } + if (typeof _this.debug === "function") { + _this.debug("<<< " + data); + } + unmarshalledData = Frame.unmarshall(_this.partialData + data); + _this.partialData = unmarshalledData.partial; + _ref = unmarshalledData.frames; _results = []; - for (_i = 0, _len = arr.length; _i < _len; _i++) { - c = arr[_i]; - _results.push(String.fromCharCode(c)); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + frame = _ref[_i]; + switch (frame.command) { + case "CONNECTED": + if (typeof _this.debug === "function") { + _this.debug("connected to server " + frame.headers.server); + } + _this.connected = true; + _this._setupHeartbeat(frame.headers); + _results.push(typeof _this.connectCallback === "function" ? _this.connectCallback(frame) : void 0); + break; + case "MESSAGE": + subscription = frame.headers.subscription; + onreceive = _this.subscriptions[subscription] || _this.onreceive; + if (onreceive) { + client = _this; + messageID = frame.headers["message-id"]; + frame.ack = function(headers) { + if (headers == null) { + headers = {}; + } + return client.ack(messageID, subscription, headers); + }; + frame.nack = function(headers) { + if (headers == null) { + headers = {}; + } + return client.nack(messageID, subscription, headers); + }; + _results.push(onreceive(frame)); + } else { + _results.push(typeof _this.debug === "function" ? _this.debug("Unhandled received MESSAGE: " + frame) : void 0); + } + break; + case "RECEIPT": + _results.push(typeof _this.onreceipt === "function" ? _this.onreceipt(frame) : void 0); + break; + case "ERROR": + _results.push(typeof errorCallback === "function" ? errorCallback(frame) : void 0); + break; + default: + _results.push(typeof _this.debug === "function" ? _this.debug("Unhandled frame: " + frame) : void 0); + } } return _results; - })()).join('')) : evt.data; - _this.serverActivity = Date.now(); - if (data === Byte.LF) { - if (typeof _this.debug === "function") { - _this.debug("<<< PONG"); - } - return; - } - if (typeof _this.debug === "function") { - _this.debug("<<< " + data); - } - _ref = Frame.unmarshall(data); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - frame = _ref[_i]; - switch (frame.command) { - case "CONNECTED": - if (typeof _this.debug === "function") { - _this.debug("connected to server " + frame.headers.server); - } - _this.connected = true; - _this._setupHeartbeat(frame.headers); - _results.push(typeof _this.connectCallback === "function" ? _this.connectCallback(frame) : void 0); - break; - case "MESSAGE": - onreceive = _this.subscriptions[frame.headers.subscription]; - _results.push(typeof onreceive === "function" ? onreceive(frame) : void 0); - break; - case "RECEIPT": - _results.push(typeof _this.onreceipt === "function" ? _this.onreceipt(frame) : void 0); - break; - case "ERROR": - _results.push(typeof errorCallback === "function" ? errorCallback(frame) : void 0); - break; - default: - _results.push(typeof _this.debug === "function" ? _this.debug("Unhandled frame: " + frame) : void 0); - } - } - return _results; - }; - this.ws.onclose = function() { - var msg; - msg = "Whoops! Lost connection to " + _this.ws.url; - if (typeof _this.debug === "function") { - _this.debug(msg); - } - return typeof errorCallback === "function" ? errorCallback(msg) : void 0; - }; - return this.ws.onopen = function() { - var headers; - if (typeof _this.debug === "function") { - _this.debug('Web Socket Opened...'); - } - headers = { - "accept-version": Stomp.VERSIONS.supportedVersions(), - "heart-beat": [_this.heartbeat.outgoing, _this.heartbeat.incoming].join(',') }; - if (vhost) { - headers.host = vhost; - } - if (login) { - headers.login = login; - } - if (passcode) { - headers.passcode = passcode; - } - return _this._transmit("CONNECT", headers); - }; + })(this); + this.ws.onclose = (function(_this) { + return function() { + var msg; + msg = "Whoops! Lost connection to " + _this.ws.url; + if (typeof _this.debug === "function") { + _this.debug(msg); + } + _this._cleanUp(); + return typeof errorCallback === "function" ? errorCallback(msg) : void 0; + }; + })(this); + return this.ws.onopen = (function(_this) { + return function() { + if (typeof _this.debug === "function") { + _this.debug('Web Socket Opened...'); + } + headers["accept-version"] = Stomp.VERSIONS.supportedVersions(); + headers["heart-beat"] = [_this.heartbeat.outgoing, _this.heartbeat.incoming].join(','); + return _this._transmit("CONNECT", headers); + }; + })(this); }; - Client.prototype.disconnect = function(disconnectCallback) { - this._transmit("DISCONNECT"); + Client.prototype.disconnect = function(disconnectCallback, headers) { + if (headers == null) { + headers = {}; + } + this._transmit("DISCONNECT", headers); this.ws.onclose = null; + this.ws.close(); this._cleanUp(); return typeof disconnectCallback === "function" ? disconnectCallback() : void 0; }; Client.prototype._cleanUp = function() { - this.ws.close(); this.connected = false; if (this.pinger) { - if (typeof window !== "undefined" && window !== null) { - window.clearInterval(this.pinger); - } + Stomp.clearInterval(this.pinger); } if (this.ponger) { - return typeof window !== "undefined" && window !== null ? window.clearInterval(this.ponger) : void 0; + return Stomp.clearInterval(this.ponger); } }; @@ -295,6 +390,7 @@ }; Client.prototype.subscribe = function(destination, callback, headers) { + var client; if (headers == null) { headers = {}; } @@ -304,7 +400,13 @@ headers.destination = destination; this.subscriptions[headers.id] = callback; this._transmit("SUBSCRIBE", headers); - return headers.id; + client = this; + return { + id: headers.id, + unsubscribe: function() { + return client.unsubscribe(headers.id); + } + }; }; Client.prototype.unsubscribe = function(id) { @@ -315,9 +417,21 @@ }; Client.prototype.begin = function(transaction) { - return this._transmit("BEGIN", { - transaction: transaction + var client, txid; + txid = transaction || "tx-" + this.counter++; + this._transmit("BEGIN", { + transaction: txid }); + client = this; + return { + id: txid, + commit: function() { + return client.commit(txid); + }, + abort: function() { + return client.abort(txid); + } + }; }; Client.prototype.commit = function(transaction) { @@ -355,7 +469,6 @@ })(); Stomp = { - libVersion: "2.0.0-next", VERSIONS: { V1_0: '1.0', V1_1: '1.1', @@ -379,11 +492,20 @@ Frame: Frame }; - if (typeof window !== "undefined" && window !== null) { - window.Stomp = Stomp; - } else { + if (typeof exports !== "undefined" && exports !== null) { exports.Stomp = Stomp; - Stomp.WebSocketClass = require('./test/server.mock.js').StompServerMock; } -}).call(this); + if (typeof window !== "undefined" && window !== null) { + Stomp.setInterval = function(interval, f) { + return window.setInterval(f, interval); + }; + Stomp.clearInterval = function(id) { + return window.clearInterval(id); + }; + window.Stomp = Stomp; + } else if (!exports) { + self.Stomp = Stomp; + } + +}).call(this); \ No newline at end of file