Browse files

Add support for node.js

Connect to a STOMP broker over TCP socket or Web socket from node.js
applications

rename npm package to stompjs
update doc for node.js support
  • Loading branch information...
1 parent e506016 commit f84f64a44c25d42c1c3e27a0eb63797c76a08d99 @jmesnil committed Sep 24, 2013
View
4 Cakefile
@@ -38,12 +38,12 @@ task 'build', 'Build source and tests', ->
task 'build:src', 'Build the src files into lib', ->
util.log "Compiling src..."
- exec binDir + "coffee -o dist/ -c src/", (err, stdout, stderr) ->
+ exec binDir + "coffee -o lib/ -c src/", (err, stdout, stderr) ->
handleError(err) if err
task 'build:min', 'Build the minified files into lib', ->
util.log "Minify src..."
- exec binDir + "uglifyjs -m --comments all -o dist/stomp.min.js dist/stomp.js", (err, stdout, stderr) ->
+ exec binDir + "uglifyjs -m --comments all -o lib/stomp.min.js lib/stomp.js", (err, stdout, stderr) ->
handleError(err) if err
task 'build:doc', 'Build docco documentation', ->
View
32 README.md
@@ -1,21 +1,43 @@
-# STOMP Over WebSocket
+# STOMP.js
-The library file is located in `dist/stomp.js` (a minified version is available in `dist/stomp.min.js`).
+This library provides a STOMP client for Web browser (using Web Sockets) or node.js applications (either using raw TCP sockets or Web Sockets).
+
+## Web Browser support
+
+The library file is located in `lib/stomp.js` (a minified version is available in `lib/stomp.min.js`).
It does not require any dependency (except WebSocket support from the browser or an alternative to WebSocket!)
-Online [documentation][doc] describes the library API (including the [annotated source code][annotated])
+Online [documentation][doc] describes the library API (including the [annotated source code][annotated]).
+
+## node.js support
+
+Install the 'stompjs' module
+
+ $ npm install stompjs
+
+In the node.js app, require the module with:
+
+ var Stomp = require('stompjs');
+
+To connect to a STOMP broker over a TCP socket, use the `Stomp.overTCP(host, port)` method:
+
+ var client = Stomp.overTCP('localhost', 61613);
+
+To connect to a STOMP broker over a WebSocket, use instead the `Stomp.overWS(url)` method:
+
+ var client = Stomp.overWS('ws://localhost:61614');
## Development Requirements
-For development (testing, building) the project requires node.js. This allows us to run tests without the browser continuously during development (see `cake watch`).
+For development (testing, building) the project requires node.js. This allows us to run tests without the browser continuously during development (see `cake watch`).
$ npm install
## Building and Testing
[![Build Status](https://secure.travis-ci.org/jmesnil/stomp-websocket.png)](http://travis-ci.org/jmesnil/stomp-websocket)
-To build JavaScript:
+To build JavaScript from the CoffeeScript source code:
$ cake build
View
2 browsertests/index.html
@@ -7,7 +7,7 @@
<script src="qunit.js"></script>
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js'></script>
- <script src="../dist/stomp.js"></script>
+ <script src="../lib/stomp.js"></script>
<!-- define all valid Test variables used by the tests -->
<script src="unit/config.js"></script>
View
1 doc/.gitignore
@@ -1,2 +1,3 @@
docco.css
stomp.html
+stomp-node.html
View
38 doc/index.html
@@ -138,9 +138,9 @@ <h3 id=stilts>Stilts &amp; Torquebox</h3>
<h2 id=download>Download stomp.js JavaScript file</h2>
-<p>You can download <a href="https://raw.github.com/jmesnil/stomp-websocket/master/dist/stomp.js">stomp.js</a> to use it in your Web applications</p>
+<p>You can download <a href="https://raw.github.com/jmesnil/stomp-websocket/master/lib/stomp.js">stomp.js</a> to use it in your Web applications</p>
-<p>A <a href="https://raw.github.com/jmesnil/stomp-websocket/master/dist/stomp.min.js">minified version</a> is also provided to be used in production.
+<p>A <a href="https://raw.github.com/jmesnil/stomp-websocket/master/lib/stomp.min.js">minified version</a> is also provided to be used in production.
<p>This JavaScript file is generated from <a href=http://jashkenas.github.com/coffee-script/>CoffeeScript</a> files. See the <a href=#contribute>Contribute</a> section to download the source code or browse the <a href="stomp.html">annotated source code</a>.
@@ -165,6 +165,8 @@ <h3 id=frame>STOMP Frame</h3>
<h3 id=client>Create a STOMP client</h3>
+<h4 id=clientws>In a Web browser with regular Web Socket</h4>
+
<p>STOMP JavaScript clients will communicate to a STOMP server using a <code>ws://</code> URL.</p>
<p>To create a STOMP client JavaScript object, you need to call <code>Stomp.client(url)</code>
with the URL corresponding to the server's WebSocket endpoint:
@@ -176,7 +178,7 @@ <h3 id=client>Create a STOMP client</h3>
<p>The <code>Stomp.client(url, protocols)</code> can also be used to override the default subprotocols provided by the library: <code>['v10.stomp', 'v11.stomp]'</code> (for STOMP 1.0 &amp; 1.1 specifications). This second argument can either be a single string or an array of strings to specify multiple subprotocols.
-<h3 id=alternative>Create a STOMP client with a WebSocket</h3>
+<h4 id=alternative>In the Web browser with a custom WebSocket</h3>
<p>Web browsers supports different versions of the WebSocket protocol. Some older browsers does not provide the WebSocket JavaScript or expose it under another name. By default, <code>stomp.js</code> will use the Web browser native <code>WebSocket</code> class to create the WebSocket.
<p>However it is possible to use other type of WebSockets by using the <code>Stomp.over(ws)</code> method.
@@ -193,11 +195,39 @@ <h3 id=alternative>Create a STOMP client with a WebSocket</h3>
[...]
&lt;/script>
</code></pre>
-</strike>
<p>Use <code>Stomp.client(url)</code> to use regular WebSockets or use <code>Stomp.over(ws)</code> if you required another type of WebSocket.
<p>Apart from this initialization, the STOMP API remains the same in both cases.
+<h4 id=nodejs>In a node.js application</h3>
+
+<p>The library can also be used in <a href="http://nodejs.org">node.js</a> application by using the
+ <a href="https://npmjs.org/package/stompjs">stompjs npm package</a>.
+
+<pre>
+ <samp>$ </samp><kbd>npm install <mark>stompjs</mark></kbd>
+</pre>
+
+<p>In the node.js app, require the module with:
+
+<pre><code>
+ var <mark>Stomp</mark> = require(<mark>'stompjs'</mark>);
+</code></pre>
+
+<p>To connect to a STOMP broker over a <em>TCP socket</em>, use the <code>Stomp.overTCP(host, port)</code> method:
+
+<pre><code>
+ var client = Stomp.<mark>overTCP</mark>('localhost', 61613);
+</code></pre>
+
+<p>To connect to a STOMP broker over a <em>Web Socket</em>, use instead the <code>Stomp.overWS(url)</code> method:
+
+<pre><code>
+ var client = Stomp.<mark>overWS</mark>('ws://localhost:61614/stomp');
+</code></pre>
+
+<p>Apart from this initialization, the STOMP API remains the same whether it is running in a Web browser or in node.js application.
+
<h3 id=connection>Connection to the server</h3>
<p>Once a STOMP client is created, it must call its <code>connect()</code> method to effectively
View
2 example/server.js
@@ -3,6 +3,6 @@ var connect = require('connect');
connect()
.use(connect.logger('dev'))
.use(connect.static(__dirname))
- .use(connect.static(__dirname + '/../dist/'))
+ .use(connect.static(__dirname + '/../lib/'))
.listen(8080);
console.log('Server running at http://0.0.0.0:8080/');
View
6 index.js
@@ -0,0 +1,6 @@
+var Stomp = require('./lib/stomp.js');
+var StompNode = require('./lib/stomp-node.js');
+
+module.exports = Stomp.Stomp;
+module.exports.overTCP = StompNode.overTCP;
+module.exports.overWS = StompNode.overWS;
View
93 lib/stomp-node.js
@@ -0,0 +1,93 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ var Stomp, net, overTCP, overWS, wrapTCP, wrapWS;
+
+ Stomp = require('./stomp');
+
+ net = require('net');
+
+ wrapTCP = function(port, host) {
+ var socket, ws;
+ socket = null;
+ ws = {
+ url: 'tcp:// ' + host + ':' + port,
+ send: function(d) {
+ return socket.write(d);
+ },
+ close: function() {
+ return socket.end();
+ }
+ };
+ socket = net.connect(port, host, function(e) {
+ return ws.onopen();
+ });
+ socket.on('error', function(e) {
+ return typeof ws.onclose === "function" ? ws.onclose(e) : void 0;
+ });
+ socket.on('close', function(e) {
+ return typeof ws.onclose === "function" ? ws.onclose(e) : void 0;
+ });
+ socket.on('data', function(data) {
+ var event;
+ event = {
+ 'data': data.toString()
+ };
+ return ws.onmessage(event);
+ });
+ return ws;
+ };
+
+ wrapWS = function(url) {
+ var WebSocketClient, connection, socket, ws;
+ WebSocketClient = require('websocket').client;
+ connection = null;
+ ws = {
+ url: url,
+ send: function(d) {
+ return connection.sendUTF(d);
+ },
+ close: function() {
+ return connection.close();
+ }
+ };
+ socket = new WebSocketClient();
+ socket.on('connect', function(conn) {
+ connection = conn;
+ ws.onopen();
+ connection.on('error', function(error) {
+ return typeof ws.onclose === "function" ? ws.onclose(error) : void 0;
+ });
+ connection.on('close', function() {
+ return typeof ws.onclose === "function" ? ws.onclose(error) : void 0;
+ });
+ return connection.on('message', function(message) {
+ var event;
+ if (message.type === 'utf8') {
+ event = {
+ 'data': message.utf8Data
+ };
+ return ws.onmessage(event);
+ }
+ });
+ });
+ socket.connect(url);
+ return ws;
+ };
+
+ overTCP = function(host, port) {
+ var socket;
+ socket = wrapTCP(port, host);
+ return Stomp.Stomp.over(socket);
+ };
+
+ overWS = function(url) {
+ var socket;
+ socket = wrapWS(url);
+ return Stomp.Stomp.over(socket);
+ };
+
+ exports.overTCP = overTCP;
+
+ exports.overWS = overWS;
+
+}).call(this);
View
1 dist/stomp.js → lib/stomp.js
@@ -449,7 +449,6 @@
window.Stomp = Stomp;
} else if (typeof exports !== "undefined" && exports !== null) {
exports.Stomp = Stomp;
- Stomp.WebSocketClass = require('./test/server.mock.js').StompServerMock;
} else {
self.Stomp = Stomp;
}
View
2 dist/stomp.min.js → lib/stomp.min.js
@@ -5,4 +5,4 @@
Copyright (C) 2010-2013 [Jeff Mesnil](http://jmesnil.net/)
Copyright (C) 2012 [FuseSource, Inc.](http://fusesource.com)
*/
-!function(){var t,e,n,i,o={}.hasOwnProperty,r=[].slice;t={LF:"\n",NULL:"\0"};n=function(){var e;function n(t,e,n){this.command=t;this.headers=e!=null?e:{};this.body=n!=null?n:""}n.prototype.toString=function(){var e,n,i,r;e=[this.command];r=this.headers;for(n in r){if(!o.call(r,n))continue;i=r[n];e.push(""+n+":"+i)}if(this.body){e.push("content-length:"+(""+this.body).length)}e.push(t.LF+this.body);return e.join(t.LF)};e=function(e){var i,o,r,s,u,a,c,f,d,h,l,p,b,g,m,v,y;s=e.search(RegExp(""+t.LF+t.LF));u=e.substring(0,s).split(t.LF);r=u.shift();a={};p=function(t){return t.replace(/^\s+|\s+$/g,"")};v=u.reverse();for(b=0,m=v.length;b<m;b++){h=v[b];f=h.indexOf(":");a[p(h.substring(0,f))]=p(h.substring(f+1))}i="";l=s+2;if(a["content-length"]){d=parseInt(a["content-length"]);i=(""+e).substring(l,l+d)}else{o=null;for(c=g=l,y=e.length;l<=y?g<y:g>y;c=l<=y?++g:--g){o=e.charAt(c);if(o===t.NULL){break}i+=o}}return new n(r,a,i)};n.unmarshall=function(n){var i;return function(){var o,r,s,u;s=n.split(RegExp(""+t.NULL+t.LF+"*"));u=[];for(o=0,r=s.length;o<r;o++){i=s[o];if((i!=null?i.length:void 0)>0){u.push(e(i))}}return u}()};n.marshall=function(e,i,o){var r;r=new n(e,i,o);return r.toString()+t.NULL};return n}();e=function(){var e;function o(t){this.ws=t;this.ws.binaryType="arraybuffer";this.counter=0;this.connected=false;this.heartbeat={outgoing:1e4,incoming:1e4};this.maxWebSocketFrameSize=16*1024;this.subscriptions={}}o.prototype.debug=function(t){var e;return typeof window!=="undefined"&&window!==null?(e=window.console)!=null?e.log(t):void 0:void 0};e=function(){return Date.now||(new Date).valueOf};o.prototype._transmit=function(t,e,i){var o;o=n.marshall(t,e,i);if(typeof this.debug==="function"){this.debug(">>> "+o)}while(true){if(o.length>this.maxWebSocketFrameSize){this.ws.send(o.substring(0,this.maxWebSocketFrameSize));o=o.substring(this.maxWebSocketFrameSize);if(typeof this.debug==="function"){this.debug("remaining = "+o.length)}}else{return this.ws.send(o)}}};o.prototype._setupHeartbeat=function(n){var o,r,s,u,a,c,f=this;if((a=n.version)!==i.VERSIONS.V1_1&&a!==i.VERSIONS.V1_2){return}c=function(){var t,e,i,o;i=n["heart-beat"].split(",");o=[];for(t=0,e=i.length;t<e;t++){u=i[t];o.push(parseInt(u))}return o}(),r=c[0],o=c[1];if(!(this.heartbeat.outgoing===0||o===0)){s=Math.max(this.heartbeat.outgoing,o);if(typeof this.debug==="function"){this.debug("send PING every "+s+"ms")}this.pinger=typeof window!=="undefined"&&window!==null?window.setInterval(function(){f.ws.send(t.LF);return typeof f.debug==="function"?f.debug(">>> PING"):void 0},s):void 0}if(!(this.heartbeat.incoming===0||r===0)){s=Math.max(this.heartbeat.incoming,r);if(typeof this.debug==="function"){this.debug("check PONG every "+s+"ms")}return this.ponger=typeof window!=="undefined"&&window!==null?window.setInterval(function(){var t;t=e()-f.serverActivity;if(t>s*2){if(typeof f.debug==="function"){f.debug("did not receive server activity for the last "+t+"ms")}return f.ws.close()}},s):void 0}};o.prototype._parseConnect=function(){var t,e,n,i;t=1<=arguments.length?r.call(arguments,0):[];i={};switch(t.length){case 2:i=t[0],e=t[1];break;case 3:if(t[1]instanceof Function){i=t[0],e=t[1],n=t[2]}else{i.login=t[0],i.passcode=t[1],e=t[2]}break;case 4:i.login=t[0],i.passcode=t[1],e=t[2],n=t[3];break;default:i.login=t[0],i.passcode=t[1],e=t[2],n=t[3],i.host=t[4]}return[i,e,n]};o.prototype.connect=function(){var o,s,u,a,c=this;o=1<=arguments.length?r.call(arguments,0):[];a=this._parseConnect.apply(this,o);u=a[0],this.connectCallback=a[1],s=a[2];if(typeof this.debug==="function"){this.debug("Opening Web Socket...")}this.ws.onmessage=function(i){var o,r,u,a,f,d,h,l,p,b,g,m;a=typeof ArrayBuffer!=="undefined"&&i.data instanceof ArrayBuffer?(o=new Uint8Array(i.data),typeof c.debug==="function"?c.debug("--- got data length: "+o.length):void 0,function(){var t,e,n;n=[];for(t=0,e=o.length;t<e;t++){r=o[t];n.push(String.fromCharCode(r))}return n}().join("")):i.data;c.serverActivity=e();if(a===t.LF){if(typeof c.debug==="function"){c.debug("<<< PONG")}return}if(typeof c.debug==="function"){c.debug("<<< "+a)}g=n.unmarshall(a);m=[];for(p=0,b=g.length;p<b;p++){f=g[p];switch(f.command){case"CONNECTED":if(typeof c.debug==="function"){c.debug("connected to server "+f.headers.server)}c.connected=true;c._setupHeartbeat(f.headers);m.push(typeof c.connectCallback==="function"?c.connectCallback(f):void 0);break;case"MESSAGE":l=f.headers.subscription;h=c.subscriptions[l]||c.onreceive;if(h){u=c;d=f.headers["message-id"];f.ack=function(t){if(t==null){t={}}return u.ack(d,l,t)};f.nack=function(t){if(t==null){t={}}return u.nack(d,l,t)};m.push(h(f))}else{m.push(typeof c.debug==="function"?c.debug("Unhandled received MESSAGE: "+f):void 0)}break;case"RECEIPT":m.push(typeof c.onreceipt==="function"?c.onreceipt(f):void 0);break;case"ERROR":m.push(typeof s==="function"?s(f):void 0);break;default:m.push(typeof c.debug==="function"?c.debug("Unhandled frame: "+f):void 0)}}return m};this.ws.onclose=function(){var t;t="Whoops! Lost connection to "+c.ws.url;if(typeof c.debug==="function"){c.debug(t)}c._cleanUp();return typeof s==="function"?s(t):void 0};return this.ws.onopen=function(){if(typeof c.debug==="function"){c.debug("Web Socket Opened...")}u["accept-version"]=i.VERSIONS.supportedVersions();u["heart-beat"]=[c.heartbeat.outgoing,c.heartbeat.incoming].join(",");return c._transmit("CONNECT",u)}};o.prototype.disconnect=function(t){this._transmit("DISCONNECT");this.ws.onclose=null;this.ws.close();this._cleanUp();return typeof t==="function"?t():void 0};o.prototype._cleanUp=function(){this.connected=false;if(this.pinger){if(typeof window!=="undefined"&&window!==null){window.clearInterval(this.pinger)}}if(this.ponger){return typeof window!=="undefined"&&window!==null?window.clearInterval(this.ponger):void 0}};o.prototype.send=function(t,e,n){if(e==null){e={}}if(n==null){n=""}e.destination=t;return this._transmit("SEND",e,n)};o.prototype.subscribe=function(t,e,n){var i;if(n==null){n={}}if(!n.id){n.id="sub-"+this.counter++}n.destination=t;this.subscriptions[n.id]=e;this._transmit("SUBSCRIBE",n);i=this;return{id:n.id,unsubscribe:function(){return i.unsubscribe(n.id)}}};o.prototype.unsubscribe=function(t){delete this.subscriptions[t];return this._transmit("UNSUBSCRIBE",{id:t})};o.prototype.begin=function(t){var e,n;n=t||"tx-"+this.counter++;this._transmit("BEGIN",{transaction:n});e=this;return{id:n,commit:function(){return e.commit(n)},abort:function(){return e.abort(n)}}};o.prototype.commit=function(t){return this._transmit("COMMIT",{transaction:t})};o.prototype.abort=function(t){return this._transmit("ABORT",{transaction:t})};o.prototype.ack=function(t,e,n){if(n==null){n={}}n["message-id"]=t;n.subscription=e;return this._transmit("ACK",n)};o.prototype.nack=function(t,e,n){if(n==null){n={}}n["message-id"]=t;n.subscription=e;return this._transmit("NACK",n)};return o}();i={libVersion:"2.0.0-next",VERSIONS:{V1_0:"1.0",V1_1:"1.1",V1_2:"1.2",supportedVersions:function(){return"1.1,1.0"}},client:function(t,n){var o,r;if(n==null){n=["v10.stomp","v11.stomp"]}o=i.WebSocketClass||WebSocket;r=new o(t,n);return new e(r)},over:function(t){return new e(t)},Frame:n};if(typeof window!=="undefined"&&window!==null){window.Stomp=i}else if(typeof exports!=="undefined"&&exports!==null){exports.Stomp=i;i.WebSocketClass=require("./test/server.mock.js").StompServerMock}else{self.Stomp=i}}.call(this);
+!function(){var t,n,e,i,o={}.hasOwnProperty,r=[].slice;t={LF:"\n",NULL:"\0"};e=function(){var n;function e(t,n,e){this.command=t;this.headers=n!=null?n:{};this.body=e!=null?e:""}e.prototype.toString=function(){var n,e,i,r;n=[this.command];r=this.headers;for(e in r){if(!o.call(r,e))continue;i=r[e];n.push(""+e+":"+i)}if(this.body){n.push("content-length:"+(""+this.body).length)}n.push(t.LF+this.body);return n.join(t.LF)};n=function(n){var i,o,r,s,u,a,c,f,d,h,l,p,g,b,m,y,v;s=n.search(RegExp(""+t.LF+t.LF));u=n.substring(0,s).split(t.LF);r=u.shift();a={};p=function(t){return t.replace(/^\s+|\s+$/g,"")};y=u.reverse();for(g=0,m=y.length;g<m;g++){h=y[g];f=h.indexOf(":");a[p(h.substring(0,f))]=p(h.substring(f+1))}i="";l=s+2;if(a["content-length"]){d=parseInt(a["content-length"]);i=(""+n).substring(l,l+d)}else{o=null;for(c=b=l,v=n.length;l<=v?b<v:b>v;c=l<=v?++b:--b){o=n.charAt(c);if(o===t.NULL){break}i+=o}}return new e(r,a,i)};e.unmarshall=function(e){var i;return function(){var o,r,s,u;s=e.split(RegExp(""+t.NULL+t.LF+"*"));u=[];for(o=0,r=s.length;o<r;o++){i=s[o];if((i!=null?i.length:void 0)>0){u.push(n(i))}}return u}()};e.marshall=function(n,i,o){var r;r=new e(n,i,o);return r.toString()+t.NULL};return e}();n=function(){var n;function o(t){this.ws=t;this.ws.binaryType="arraybuffer";this.counter=0;this.connected=false;this.heartbeat={outgoing:1e4,incoming:1e4};this.maxWebSocketFrameSize=16*1024;this.subscriptions={}}o.prototype.debug=function(t){var n;return typeof window!=="undefined"&&window!==null?(n=window.console)!=null?n.log(t):void 0:void 0};n=function(){return Date.now||(new Date).valueOf};o.prototype._transmit=function(t,n,i){var o;o=e.marshall(t,n,i);if(typeof this.debug==="function"){this.debug(">>> "+o)}while(true){if(o.length>this.maxWebSocketFrameSize){this.ws.send(o.substring(0,this.maxWebSocketFrameSize));o=o.substring(this.maxWebSocketFrameSize);if(typeof this.debug==="function"){this.debug("remaining = "+o.length)}}else{return this.ws.send(o)}}};o.prototype._setupHeartbeat=function(e){var o,r,s,u,a,c,f=this;if((a=e.version)!==i.VERSIONS.V1_1&&a!==i.VERSIONS.V1_2){return}c=function(){var t,n,i,o;i=e["heart-beat"].split(",");o=[];for(t=0,n=i.length;t<n;t++){u=i[t];o.push(parseInt(u))}return o}(),r=c[0],o=c[1];if(!(this.heartbeat.outgoing===0||o===0)){s=Math.max(this.heartbeat.outgoing,o);if(typeof this.debug==="function"){this.debug("send PING every "+s+"ms")}this.pinger=typeof window!=="undefined"&&window!==null?window.setInterval(function(){f.ws.send(t.LF);return typeof f.debug==="function"?f.debug(">>> PING"):void 0},s):void 0}if(!(this.heartbeat.incoming===0||r===0)){s=Math.max(this.heartbeat.incoming,r);if(typeof this.debug==="function"){this.debug("check PONG every "+s+"ms")}return this.ponger=typeof window!=="undefined"&&window!==null?window.setInterval(function(){var t;t=n()-f.serverActivity;if(t>s*2){if(typeof f.debug==="function"){f.debug("did not receive server activity for the last "+t+"ms")}return f.ws.close()}},s):void 0}};o.prototype._parseConnect=function(){var t,n,e,i;t=1<=arguments.length?r.call(arguments,0):[];i={};switch(t.length){case 2:i=t[0],n=t[1];break;case 3:if(t[1]instanceof Function){i=t[0],n=t[1],e=t[2]}else{i.login=t[0],i.passcode=t[1],n=t[2]}break;case 4:i.login=t[0],i.passcode=t[1],n=t[2],e=t[3];break;default:i.login=t[0],i.passcode=t[1],n=t[2],e=t[3],i.host=t[4]}return[i,n,e]};o.prototype.connect=function(){var o,s,u,a,c=this;o=1<=arguments.length?r.call(arguments,0):[];a=this._parseConnect.apply(this,o);u=a[0],this.connectCallback=a[1],s=a[2];if(typeof this.debug==="function"){this.debug("Opening Web Socket...")}this.ws.onmessage=function(i){var o,r,u,a,f,d,h,l,p,g,b,m;a=typeof ArrayBuffer!=="undefined"&&i.data instanceof ArrayBuffer?(o=new Uint8Array(i.data),typeof c.debug==="function"?c.debug("--- got data length: "+o.length):void 0,function(){var t,n,e;e=[];for(t=0,n=o.length;t<n;t++){r=o[t];e.push(String.fromCharCode(r))}return e}().join("")):i.data;c.serverActivity=n();if(a===t.LF){if(typeof c.debug==="function"){c.debug("<<< PONG")}return}if(typeof c.debug==="function"){c.debug("<<< "+a)}b=e.unmarshall(a);m=[];for(p=0,g=b.length;p<g;p++){f=b[p];switch(f.command){case"CONNECTED":if(typeof c.debug==="function"){c.debug("connected to server "+f.headers.server)}c.connected=true;c._setupHeartbeat(f.headers);m.push(typeof c.connectCallback==="function"?c.connectCallback(f):void 0);break;case"MESSAGE":l=f.headers.subscription;h=c.subscriptions[l]||c.onreceive;if(h){u=c;d=f.headers["message-id"];f.ack=function(t){if(t==null){t={}}return u.ack(d,l,t)};f.nack=function(t){if(t==null){t={}}return u.nack(d,l,t)};m.push(h(f))}else{m.push(typeof c.debug==="function"?c.debug("Unhandled received MESSAGE: "+f):void 0)}break;case"RECEIPT":m.push(typeof c.onreceipt==="function"?c.onreceipt(f):void 0);break;case"ERROR":m.push(typeof s==="function"?s(f):void 0);break;default:m.push(typeof c.debug==="function"?c.debug("Unhandled frame: "+f):void 0)}}return m};this.ws.onclose=function(){var t;t="Whoops! Lost connection to "+c.ws.url;if(typeof c.debug==="function"){c.debug(t)}c._cleanUp();return typeof s==="function"?s(t):void 0};return this.ws.onopen=function(){if(typeof c.debug==="function"){c.debug("Web Socket Opened...")}u["accept-version"]=i.VERSIONS.supportedVersions();u["heart-beat"]=[c.heartbeat.outgoing,c.heartbeat.incoming].join(",");return c._transmit("CONNECT",u)}};o.prototype.disconnect=function(t){this._transmit("DISCONNECT");this.ws.onclose=null;this.ws.close();this._cleanUp();return typeof t==="function"?t():void 0};o.prototype._cleanUp=function(){this.connected=false;if(this.pinger){if(typeof window!=="undefined"&&window!==null){window.clearInterval(this.pinger)}}if(this.ponger){return typeof window!=="undefined"&&window!==null?window.clearInterval(this.ponger):void 0}};o.prototype.send=function(t,n,e){if(n==null){n={}}if(e==null){e=""}n.destination=t;return this._transmit("SEND",n,e)};o.prototype.subscribe=function(t,n,e){var i;if(e==null){e={}}if(!e.id){e.id="sub-"+this.counter++}e.destination=t;this.subscriptions[e.id]=n;this._transmit("SUBSCRIBE",e);i=this;return{id:e.id,unsubscribe:function(){return i.unsubscribe(e.id)}}};o.prototype.unsubscribe=function(t){delete this.subscriptions[t];return this._transmit("UNSUBSCRIBE",{id:t})};o.prototype.begin=function(t){var n,e;e=t||"tx-"+this.counter++;this._transmit("BEGIN",{transaction:e});n=this;return{id:e,commit:function(){return n.commit(e)},abort:function(){return n.abort(e)}}};o.prototype.commit=function(t){return this._transmit("COMMIT",{transaction:t})};o.prototype.abort=function(t){return this._transmit("ABORT",{transaction:t})};o.prototype.ack=function(t,n,e){if(e==null){e={}}e["message-id"]=t;e.subscription=n;return this._transmit("ACK",e)};o.prototype.nack=function(t,n,e){if(e==null){e={}}e["message-id"]=t;e.subscription=n;return this._transmit("NACK",e)};return o}();i={libVersion:"2.0.0-next",VERSIONS:{V1_0:"1.0",V1_1:"1.1",V1_2:"1.2",supportedVersions:function(){return"1.1,1.0"}},client:function(t,e){var o,r;if(e==null){e=["v10.stomp","v11.stomp"]}o=i.WebSocketClass||WebSocket;r=new o(t,e);return new n(r)},over:function(t){return new n(t)},Frame:e};if(typeof window!=="undefined"&&window!==null){window.Stomp=i}else if(typeof exports!=="undefined"&&exports!==null){exports.Stomp=i}else{self.Stomp=i}}.call(this);
View
29 package.json
@@ -1,9 +1,8 @@
{
- "name": "stomp-websocket",
- "preferGlobal": "true",
+ "name": "stompjs",
"version": "2.1.0-next",
- "author": "Jeff Mesnil <jmesnil@gmail.com",
- "description": "STOMP over Web Sockets",
+ "author": "Jeff Mesnil <jmesnil@gmail.com>",
+ "description": "STOMP for JavaScript",
"scripts": {
"build": "cake build",
"test": "coffeelint -f coffeelint.json -r src && cake test"
@@ -15,5 +14,27 @@
"uglify-js": "latest",
"docco": "latest",
"connect": "latest"
+ },
+ "optionalDependencies": {
+ "websocket": "latest"
+ },
+ "directories": {
+ "doc": "doc",
+ "example": "example",
+ "test": "test"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/jmesnil/stomp-websocket"
+ },
+ "keywords": [
+ "STOMP",
+ "Web sockets",
+ "messaging",
+ "queue"
+ ],
+ "license": "APL v2",
+ "bugs": {
+ "url": "https://github.com/jmesnil/stomp-websocket/issues"
}
}
View
60 src/stomp-node.coffee
@@ -0,0 +1,60 @@
+Stomp = require('./stomp')
+net = require('net')
+
+wrapTCP= (port, host) ->
+ socket = null
+
+ ws = {
+ url: 'tcp:// ' + host + ':' + port
+ send: (d) -> socket.write(d)
+ close: -> socket.end()
+ }
+
+ socket = net.connect port, host, (e) -> ws.onopen()
+ socket.on 'error', (e) -> ws.onclose?(e)
+ socket.on 'close', (e) -> ws.onclose?(e)
+ socket.on 'data', (data) ->
+ event = {
+ 'data': data.toString()
+ };
+ ws.onmessage(event)
+
+ return ws;
+
+wrapWS= (url) ->
+ WebSocketClient = require('websocket').client
+
+ connection = null
+
+ ws = {
+ url: url
+ send: (d) -> connection.sendUTF(d)
+ close: ->connection.close()
+ }
+
+ socket = new WebSocketClient()
+ socket.on 'connect', (conn) ->
+ connection = conn
+ ws.onopen()
+ connection.on 'error', (error) -> ws.onclose?(error)
+ connection.on 'close', -> ws.onclose?(error)
+ connection.on 'message', (message) ->
+ if message.type == 'utf8'
+ event = {
+ 'data': message.utf8Data
+ }
+ ws.onmessage(event)
+
+ socket.connect url
+ return ws
+
+overTCP = (host, port) ->
+ socket = wrapTCP port, host
+ Stomp.Stomp.over socket
+
+overWS = (url) ->
+ socket = wrapWS url
+ Stomp.Stomp.over socket
+
+exports.overTCP = overTCP
+exports.overWS = overWS
View
100 src/stomp-node.orig.js
@@ -0,0 +1,100 @@
+var Stomp = require("./stomp");
+var net = require('net');
+
+var wrapTCP = function(port, host) {
+ // node.js net.Socket;
+ var socket;
+
+ // Web Socket-like object
+ var ws = {
+ url: 'tcp:// ' + host + ':' + port,
+ send: function(d) {
+ socket.write(d);
+ },
+ close: function() {
+ socket.end();
+ }
+ };
+
+ socket = net.connect(port, host, function(e) {
+ ws.onopen();
+ });
+ socket.on('error', function(e) {
+ // handler can be null if the ws is properly closed
+ if (ws.onclose) {
+ ws.onclose(e);
+ }
+ });
+ socket.on('close', function(e) {
+ // handler can be null if the ws is properly closed
+ if (ws.onclose) {
+ ws.onclose();
+ }
+ });
+ socket.on('data', function(data) {
+ // wrap the data in an event object
+ var event = {
+ 'data': data.toString()
+ };
+ ws.onmessage(event);
+ });
+
+ return ws;
+};
+
+var wrapWS = function(url) {
+ var WebSocketClient = require('websocket').client;
+
+ var connection;
+
+ var ws = {
+ url: url,
+ send : function(d) {
+ connection.sendUTF(d);
+ },
+ close : function() {
+ connection.close();
+ }
+ };
+
+ var socket = new WebSocketClient();
+ socket.on('connect', function(conn) {
+ connection = conn;
+ ws.onopen();
+ connection.on('error', function(error) {
+ if (ws.onclose) {
+ ws.onclose(error);
+ }
+ });
+ connection.on('close', function() {
+ if (ws.onclose) {
+ ws.onclose();
+ }
+ });
+ connection.on('message', function(message) {
+ if (message.type === 'utf8') {
+ // wrap the data in an event object
+ var event = {
+ 'data': message.utf8Data
+ };
+ ws.onmessage(event);
+ }
+ });
+ });
+
+ socket.connect(url);
+ return ws;
+}
+
+var overTCP = function(host, port) {
+ var socket = wrapTCP(port, host);
+ return Stomp.Stomp.over(socket);
+}
+
+var overWS= function(url) {
+ var socket = wrapWS(url);
+ return Stomp.Stomp.over(socket);
+}
+
+exports.overTCP = overTCP;
+exports.overWS = overWS;
View
1 src/stomp.coffee
@@ -485,7 +485,6 @@ if window?
# or as module (for tests only)
else if exports?
exports.Stomp = Stomp
- Stomp.WebSocketClass = require('./test/server.mock.js').StompServerMock
# or in the current object (e.g. a WebWorker)
else
self.Stomp = Stomp
View
3 test/server.mock.coffee
@@ -1,5 +1,6 @@
WebSocketMock = require('./websocket.mock.js').WebSocketMock
-Stomp = require('../stomp.js').Stomp
+Stomp = require('../../lib/stomp.js').Stomp
+
console = require 'console'
class StompServerMock extends WebSocketMock
View
4 test/stomp.spec.coffee
@@ -1,6 +1,8 @@
-Stomp = require('../stomp.js').Stomp
+Stomp = require('../../lib/stomp.js').Stomp
StompServerMock = require('./server.mock.js').StompServerMock
+Stomp.WebSocketClass = StompServerMock
+
describe "Stomp", ->
it "lets you connect to a server with a websocket and get a callback", ->
ws = new StompServerMock("ws://mocked/stomp/server")

0 comments on commit f84f64a

Please sign in to comment.