stomp.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. // Generated by CoffeeScript 1.6.3
  2. /*
  3. Stomp Over WebSocket http://www.jmesnil.net/stomp-websocket/doc/ | Apache License V2.0
  4. */
  5. (function() {
  6. var Byte, Client, Frame, Stomp,
  7. __hasProp = {}.hasOwnProperty;
  8. Byte = {
  9. LF: '\x0A',
  10. NULL: '\x00'
  11. };
  12. Frame = (function() {
  13. function Frame(command, headers, body) {
  14. this.command = command;
  15. this.headers = headers != null ? headers : {};
  16. this.body = body != null ? body : '';
  17. }
  18. Frame.prototype.toString = function() {
  19. var lines, name, value, _ref;
  20. lines = [this.command];
  21. _ref = this.headers;
  22. for (name in _ref) {
  23. if (!__hasProp.call(_ref, name)) continue;
  24. value = _ref[name];
  25. lines.push("" + name + ":" + value);
  26. }
  27. if (this.body) {
  28. lines.push("content-length:" + ('' + this.body).length);
  29. }
  30. lines.push(Byte.LF + this.body);
  31. return lines.join(Byte.LF);
  32. };
  33. Frame._unmarshallSingle = function(data) {
  34. var body, chr, command, divider, headerLines, headers, i, idx, len, line, start, trim, _i, _j, _ref, _ref1;
  35. divider = data.search(RegExp("" + Byte.LF + Byte.LF));
  36. headerLines = data.substring(0, divider).split(Byte.LF);
  37. command = headerLines.shift();
  38. headers = {};
  39. trim = function(str) {
  40. return str.replace(/^\s+|\s+$/g, '');
  41. };
  42. line = idx = null;
  43. for (i = _i = 0, _ref = headerLines.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
  44. line = headerLines[i];
  45. idx = line.indexOf(':');
  46. headers[trim(line.substring(0, idx))] = trim(line.substring(idx + 1));
  47. }
  48. body = '';
  49. start = divider + 2;
  50. if (headers['content-length']) {
  51. len = parseInt(headers['content-length']);
  52. body = ('' + data).substring(start, start + len);
  53. } else {
  54. chr = null;
  55. for (i = _j = start, _ref1 = data.length; start <= _ref1 ? _j < _ref1 : _j > _ref1; i = start <= _ref1 ? ++_j : --_j) {
  56. chr = data.charAt(i);
  57. if (chr === Byte.NULL) {
  58. break;
  59. }
  60. body += chr;
  61. }
  62. }
  63. return new Frame(command, headers, body);
  64. };
  65. Frame.unmarshall = function(datas) {
  66. var data;
  67. return (function() {
  68. var _i, _len, _ref, _results;
  69. _ref = datas.split(RegExp("" + Byte.NULL + Byte.LF + "*"));
  70. _results = [];
  71. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  72. data = _ref[_i];
  73. if ((data != null ? data.length : void 0) > 0) {
  74. _results.push(Frame._unmarshallSingle(data));
  75. }
  76. }
  77. return _results;
  78. })();
  79. };
  80. Frame.marshall = function(command, headers, body) {
  81. var frame;
  82. frame = new Frame(command, headers, body);
  83. return frame.toString() + Byte.NULL;
  84. };
  85. return Frame;
  86. })();
  87. Client = (function() {
  88. function Client(ws) {
  89. this.ws = ws;
  90. this.ws.binaryType = "arraybuffer";
  91. this.counter = 0;
  92. this.connected = false;
  93. this.heartbeat = {
  94. outgoing: 10000,
  95. incoming: 10000
  96. };
  97. this.maxWebSocketFrameSize = 16 * 1024;
  98. this.subscriptions = {};
  99. }
  100. Client.prototype.debug = function(message) {
  101. var _ref;
  102. return typeof window !== "undefined" && window !== null ? (_ref = window.console) != null ? _ref.log(message) : void 0 : void 0;
  103. };
  104. Client.prototype._transmit = function(command, headers, body) {
  105. var out;
  106. out = Frame.marshall(command, headers, body);
  107. if (typeof this.debug === "function") {
  108. this.debug(">>> " + out);
  109. }
  110. while (true) {
  111. if (out.length > this.maxWebSocketFrameSize) {
  112. this.ws.send(out.substring(0, this.maxWebSocketFrameSize));
  113. out = out.substring(this.maxWebSocketFrameSize);
  114. if (typeof this.debug === "function") {
  115. this.debug("remaining = " + out.length);
  116. }
  117. } else {
  118. return this.ws.send(out);
  119. }
  120. }
  121. };
  122. Client.prototype._setupHeartbeat = function(headers) {
  123. var serverIncoming, serverOutgoing, ttl, v, _ref, _ref1,
  124. _this = this;
  125. if ((_ref = headers.version) !== Stomp.VERSIONS.V1_1 && _ref !== Stomp.VERSIONS.V1_2) {
  126. return;
  127. }
  128. _ref1 = (function() {
  129. var _i, _len, _ref1, _results;
  130. _ref1 = headers['heart-beat'].split(",");
  131. _results = [];
  132. for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
  133. v = _ref1[_i];
  134. _results.push(parseInt(v));
  135. }
  136. return _results;
  137. })(), serverOutgoing = _ref1[0], serverIncoming = _ref1[1];
  138. if (!(this.heartbeat.outgoing === 0 || serverIncoming === 0)) {
  139. ttl = Math.max(this.heartbeat.outgoing, serverIncoming);
  140. if (typeof this.debug === "function") {
  141. this.debug("send PING every " + ttl + "ms");
  142. }
  143. this.pinger = typeof window !== "undefined" && window !== null ? window.setInterval(function() {
  144. _this.ws.send(Byte.LF);
  145. return typeof _this.debug === "function" ? _this.debug(">>> PING") : void 0;
  146. }, ttl) : void 0;
  147. }
  148. if (!(this.heartbeat.incoming === 0 || serverOutgoing === 0)) {
  149. ttl = Math.max(this.heartbeat.incoming, serverOutgoing);
  150. if (typeof this.debug === "function") {
  151. this.debug("check PONG every " + ttl + "ms");
  152. }
  153. return this.ponger = typeof window !== "undefined" && window !== null ? window.setInterval(function() {
  154. var delta;
  155. delta = Date.now() - _this.serverActivity;
  156. if (delta > ttl * 2) {
  157. if (typeof _this.debug === "function") {
  158. _this.debug("did not receive server activity for the last " + delta + "ms");
  159. }
  160. return _this.ws.close();
  161. }
  162. }, ttl) : void 0;
  163. }
  164. };
  165. Client.prototype.connect = function(login, passcode, connectCallback, errorCallback, vhost) {
  166. var _this = this;
  167. this.connectCallback = connectCallback;
  168. if (typeof this.debug === "function") {
  169. this.debug("Opening Web Socket...");
  170. }
  171. this.ws.onmessage = function(evt) {
  172. var arr, c, data, frame, onreceive, _i, _len, _ref, _results;
  173. 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() {
  174. var _i, _len, _results;
  175. _results = [];
  176. for (_i = 0, _len = arr.length; _i < _len; _i++) {
  177. c = arr[_i];
  178. _results.push(String.fromCharCode(c));
  179. }
  180. return _results;
  181. })()).join('')) : evt.data;
  182. _this.serverActivity = Date.now();
  183. if (data === Byte.LF) {
  184. if (typeof _this.debug === "function") {
  185. _this.debug("<<< PONG");
  186. }
  187. return;
  188. }
  189. if (typeof _this.debug === "function") {
  190. _this.debug("<<< " + data);
  191. }
  192. _ref = Frame.unmarshall(data);
  193. _results = [];
  194. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  195. frame = _ref[_i];
  196. switch (frame.command) {
  197. case "CONNECTED":
  198. if (typeof _this.debug === "function") {
  199. _this.debug("connected to server " + frame.headers.server);
  200. }
  201. _this.connected = true;
  202. _this._setupHeartbeat(frame.headers);
  203. _results.push(typeof _this.connectCallback === "function" ? _this.connectCallback(frame) : void 0);
  204. break;
  205. case "MESSAGE":
  206. onreceive = _this.subscriptions[frame.headers.subscription] || _this.onreceive;
  207. if (onreceive) {
  208. _results.push(onreceive(frame));
  209. } else {
  210. _results.push(typeof _this.debug === "function" ? _this.debug("Unhandled received MESSAGE: " + frame) : void 0);
  211. }
  212. break;
  213. case "RECEIPT":
  214. _results.push(typeof _this.onreceipt === "function" ? _this.onreceipt(frame) : void 0);
  215. break;
  216. case "ERROR":
  217. _results.push(typeof errorCallback === "function" ? errorCallback(frame) : void 0);
  218. break;
  219. default:
  220. _results.push(typeof _this.debug === "function" ? _this.debug("Unhandled frame: " + frame) : void 0);
  221. }
  222. }
  223. return _results;
  224. };
  225. this.ws.onclose = function() {
  226. var msg;
  227. msg = "Whoops! Lost connection to " + _this.ws.url;
  228. if (typeof _this.debug === "function") {
  229. _this.debug(msg);
  230. }
  231. _this._cleanUp();
  232. return typeof errorCallback === "function" ? errorCallback(msg) : void 0;
  233. };
  234. return this.ws.onopen = function() {
  235. var headers;
  236. if (typeof _this.debug === "function") {
  237. _this.debug('Web Socket Opened...');
  238. }
  239. headers = {
  240. "accept-version": Stomp.VERSIONS.supportedVersions(),
  241. "heart-beat": [_this.heartbeat.outgoing, _this.heartbeat.incoming].join(',')
  242. };
  243. if (vhost) {
  244. headers.host = vhost;
  245. }
  246. if (login) {
  247. headers.login = login;
  248. }
  249. if (passcode) {
  250. headers.passcode = passcode;
  251. }
  252. return _this._transmit("CONNECT", headers);
  253. };
  254. };
  255. Client.prototype.disconnect = function(disconnectCallback) {
  256. this._transmit("DISCONNECT");
  257. this.ws.onclose = null;
  258. this.ws.close();
  259. this._cleanUp();
  260. return typeof disconnectCallback === "function" ? disconnectCallback() : void 0;
  261. };
  262. Client.prototype._cleanUp = function() {
  263. this.connected = false;
  264. if (this.pinger) {
  265. if (typeof window !== "undefined" && window !== null) {
  266. window.clearInterval(this.pinger);
  267. }
  268. }
  269. if (this.ponger) {
  270. return typeof window !== "undefined" && window !== null ? window.clearInterval(this.ponger) : void 0;
  271. }
  272. };
  273. Client.prototype.send = function(destination, headers, body) {
  274. if (headers == null) {
  275. headers = {};
  276. }
  277. if (body == null) {
  278. body = '';
  279. }
  280. headers.destination = destination;
  281. return this._transmit("SEND", headers, body);
  282. };
  283. Client.prototype.subscribe = function(destination, callback, headers) {
  284. if (headers == null) {
  285. headers = {};
  286. }
  287. if (!headers.id) {
  288. headers.id = "sub-" + this.counter++;
  289. }
  290. headers.destination = destination;
  291. this.subscriptions[headers.id] = callback;
  292. this._transmit("SUBSCRIBE", headers);
  293. return headers.id;
  294. };
  295. Client.prototype.unsubscribe = function(id) {
  296. delete this.subscriptions[id];
  297. return this._transmit("UNSUBSCRIBE", {
  298. id: id
  299. });
  300. };
  301. Client.prototype.begin = function(transaction) {
  302. return this._transmit("BEGIN", {
  303. transaction: transaction
  304. });
  305. };
  306. Client.prototype.commit = function(transaction) {
  307. return this._transmit("COMMIT", {
  308. transaction: transaction
  309. });
  310. };
  311. Client.prototype.abort = function(transaction) {
  312. return this._transmit("ABORT", {
  313. transaction: transaction
  314. });
  315. };
  316. Client.prototype.ack = function(messageID, subscription, headers) {
  317. if (headers == null) {
  318. headers = {};
  319. }
  320. headers["message-id"] = messageID;
  321. headers.subscription = subscription;
  322. return this._transmit("ACK", headers);
  323. };
  324. Client.prototype.nack = function(messageID, subscription, headers) {
  325. if (headers == null) {
  326. headers = {};
  327. }
  328. headers["message-id"] = messageID;
  329. headers.subscription = subscription;
  330. return this._transmit("NACK", headers);
  331. };
  332. return Client;
  333. })();
  334. Stomp = {
  335. libVersion: "2.0.0-next",
  336. VERSIONS: {
  337. V1_0: '1.0',
  338. V1_1: '1.1',
  339. V1_2: '1.2',
  340. supportedVersions: function() {
  341. return '1.1,1.0';
  342. }
  343. },
  344. client: function(url, protocols) {
  345. var klass, ws;
  346. if (protocols == null) {
  347. protocols = ['v10.stomp', 'v11.stomp'];
  348. }
  349. klass = Stomp.WebSocketClass || WebSocket;
  350. ws = new klass(url, protocols);
  351. return new Client(ws);
  352. },
  353. over: function(ws) {
  354. return new Client(ws);
  355. },
  356. Frame: Frame
  357. };
  358. if (typeof window !== "undefined" && window !== null) {
  359. window.Stomp = Stomp;
  360. } else if (typeof exports !== "undefined" && exports !== null) {
  361. exports.Stomp = Stomp;
  362. Stomp.WebSocketClass = require('./test/server.mock.js').StompServerMock;
  363. } else {
  364. self.Stomp = Stomp;
  365. }
  366. }).call(this);