Skip to content

Commit

Permalink
Initial import
Browse files Browse the repository at this point in the history
Original code from sockjs-node/examples/multiplex commit 5481094b322541e5976b3577b87b82031c824645
  • Loading branch information
majek committed Mar 16, 2012
0 parents commit f7a346d
Show file tree
Hide file tree
Showing 11 changed files with 448 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,2 @@
examples/sockjs/node_modules

20 changes: 20 additions & 0 deletions Makefile
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,20 @@
all:

VER:=$(shell ./VERSION-GEN)
MAJVER:=$(shell echo $(VER)|sed 's|^\([^.]\+[.][^.]\+\).*$$|\1|' )

CLIENT_ARTIFACTS=\
websocket-multiplex-$(VER).js \
websocket-multiplex-$(MAJVER).js

upload_client:
echo "VER=$(VER) MAJVER=$(MAJVER)"
cp multiplex_client.js websocket-multiplex-$(VER).js
cp multiplex_client.js websocket-multiplex-$(MAJVER).js
@echo -e 'Run:'
@echo -e '\ts3cmd put --acl-public index.html $(CLIENT_ARTIFACTS) s3://sockjs'
@echo -e '\tmake clean'

clean:
rm $(CLIENT_ARTIFACTS)
rm -rf examples/sockjs/node_modules
68 changes: 68 additions & 0 deletions README.md
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,68 @@

WebSocket-multiplex
===================

WebSocket-multiplex is a small library on top of SockJS that allows
you to do multiplexing over a single SockJS connection.

The rationale for that is explained in details in the following blog
post:

* https://www.rabbitmq.com/blog/2012/02/23/how-to-compose-apps-using-websockets/


Usage from the browser
----------------------

On the client side (browser) load library like that:

<script src="http://cdn.sockjs.org/websocket-multiplex-0.1.js">
</script>

Alternatively, if you're using SSL:

<script src="https://d1fxtkz8shb9d2.cloudfront.net/websocket-multiplex-0.1.js">
</script>

Usage example:

var sockjs_url = '/multiplex';
var sockjs = new SockJS(sockjs_url);

var multiplexer = new WebSocketMultiplex(sockjs);
var ann = multiplexer.channel('ann');
var bob = multiplexer.channel('bob');
var carl = multiplexer.channel('carl');


Usage from the node.js server
-----------------------------

On the node.js server side, you can use npm to get the code:

npm install websocket-multiplex

And a simplistic example:

var multiplex_server = require('websocket-multiplex');

// 1. Setup SockJS server
var service = sockjs.createServer();

// 2. Setup multiplexing
var multiplexer = new multiplex_server.MultiplexServer(service);

var ann = multiplexer.registerChannel('ann');
ann.on('connection', function(conn) {
conn.write('Ann says hi!');
conn.on('data', function(data) {
conn.write('Ann nods: ' + data);
});
});

// 3. Setup http server
var server = http.createServer();
sockjs_echo.installHandlers(server, {prefix:'/multiplex'});
var app = express.createServer();

For a full-featured example see the `/examples` directory.
3 changes: 3 additions & 0 deletions VERSION-GEN
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env node
var fs = require('fs')
console.log(JSON.parse(fs.readFileSync('package.json')).version)
19 changes: 19 additions & 0 deletions examples/sockjs/README.md
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,19 @@
WebSocket-multiplex SockJS example
==================================

To run this example, first install dependencies:

npm install

And run a server:

node server.js


That will spawn an http server at http://127.0.0.1:9999/ which will
serve both html (served from the current directory) and also SockJS
service (under the [/multiplex](http://127.0.0.1:9999/multiplex)
path).

With that set up, WebSocket-multiplex is able to push three virtual
connections over a single SockJS connection. See the code for details.
96 changes: 96 additions & 0 deletions examples/sockjs/index.html
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,96 @@
<!doctype html>
<html><head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://cdn.sockjs.org/sockjs-0.2.min.js"></script>
<script src="http://cdn.sockjs.org/websocket-multiplex-0.1.js"></script>
<style>
.box {
width: 300px;
float: left;
margin: 0 20px 0 20px;
}
.box div, .box input {
border: 1px solid;
-moz-border-radius: 4px;
border-radius: 4px;
width: 100%;
padding: 0px;
margin: 5px;
}
.box div {
border-color: grey;
height: 300px;
overflow: auto;
}
.box input {
height: 30px;
}
h1 {
margin-left: 75px;
}
body {
background-color: #F0F0F0;
font-family: "Arial";
}
</style>
</head><body lang="en">
<h1>SockJS Multiplex example</h1>

<div id="first" class="box">
<div></div>
<form><input autocomplete="off" value="Type here..."></input></form>
</div>

<div id="second" class="box">
<div></div>
<form><input autocomplete="off"></input></form>
</div>

<div id="third" class="box">
<div></div>
<form><input autocomplete="off"></input></form>
</div>

<script>
// Pipe - convenience wrapper to present data received from an
// object supporting WebSocket API in an html element. And the other
// direction: data typed into an input box shall be sent back.
var pipe = function(ws, el_name) {
var div = $(el_name + ' div');
var inp = $(el_name + ' input');
var form = $(el_name + ' form');

var print = function(m, p) {
p = (p === undefined) ? '' : JSON.stringify(p);
div.append($("<code>").text(m + ' ' + p));
div.append($("<br>"));
div.scrollTop(div.scrollTop() + 10000);
};

ws.onopen = function() {print('[*] open', ws.protocol);};
ws.onmessage = function(e) {print('[.] message', e.data);};
ws.onclose = function() {print('[*] close');};

form.submit(function() {
print('[ ] sending', inp.val());
ws.send(inp.val());
inp.val('');
return false;
});
};

var sockjs_url = '/multiplex';
var sockjs = new SockJS(sockjs_url);

var multiplexer = new WebSocketMultiplex(sockjs);
var ann = multiplexer.channel('ann');
var bob = multiplexer.channel('bob');
var carl = multiplexer.channel('carl');

pipe(ann, '#first');
pipe(bob, '#second');
pipe(carl, '#third');

$('#first input').focus();
</script>
</body></html>
9 changes: 9 additions & 0 deletions examples/sockjs/package.json
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name" : "websocket-multiplex-sockjs-example",
"version" : "0.0.0-unreleasable",
"dependencies" : {
"express" : "2.5.8",
"sockjs" : "0.2.x",
"websocket-multiplex" : "*"
}
}
52 changes: 52 additions & 0 deletions examples/sockjs/server.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,52 @@
var express = require('express');
var websocket_multiplex = require('websocket-multiplex');

var sockjs = require('sockjs');


// 1. Setup SockJS server
var sockjs_opts = {sockjs_url: "http://cdn.sockjs.org/sockjs-0.2.min.js"};
var service = sockjs.createServer(sockjs_opts);


// 2. Setup multiplexing
var multiplexer = new websocket_multiplex.MultiplexServer(service);

var ann = multiplexer.registerChannel('ann');
ann.on('connection', function(conn) {
conn.write('Ann says hi!');
conn.on('data', function(data) {
conn.write('Ann nods: ' + data);
});
});

var bob = multiplexer.registerChannel('bob');
bob.on('connection', function(conn) {
conn.write('Bob doesn\'t agree.');
conn.on('data', function(data) {
conn.write('Bob says no to: ' + data);
});
});

var carl = multiplexer.registerChannel('carl');
carl.on('connection', function(conn) {
conn.write('Carl says goodbye!');
// Explicitly cancel connection
conn.end();
});


// 3. Express server
var app = express.createServer();
service.installHandlers(app, {prefix:'/multiplex'});

console.log(' [*] Listening on 0.0.0.0:9999' );
app.listen(9999, '0.0.0.0');

app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});

app.get('/multiplex.js', function (req, res) {
res.sendfile(__dirname + '/multiplex.js');
});
86 changes: 86 additions & 0 deletions multiplex_client.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,86 @@
var WebSocketMultiplex = (function(){


// ****

var DumbEventTarget = function() {
this._listeners = {};
};
DumbEventTarget.prototype._ensure = function(type) {
if(!(type in this._listeners)) this._listeners[type] = [];
};
DumbEventTarget.prototype.addEventListener = function(type, listener) {
this._ensure(type);
this._listeners[type].push(listener);
};
DumbEventTarget.prototype.emit = function(type) {
this._ensure(type);
var args = Array.prototype.slice.call(arguments, 1);
if(this['on' + type]) this['on' + type].apply(this, args);
for(var i=0; i < this._listeners[type].length; i++) {
this._listeners[type][i].apply(this, args);
}
};


// ****

var WebSocketMultiplex = function(ws) {
var that = this;
this.ws = ws;
this.channels = {};
this.ws.addEventListener('message', function(e) {
var t = e.data.split(',');
var type = t.shift(), name = t.shift(), payload = t.join();
if(!(name in that.channels)) {
return;
}
var sub = that.channels[name];

switch(type) {
case 'uns':
delete that.channels[name];
sub.emit('close', {});
break;
case 'msg':
sub.emit('message', {data: payload});
break;
}
});
};
WebSocketMultiplex.prototype.channel = function(raw_name) {
return this.channels[escape(raw_name)] =
new Channel(this.ws, escape(raw_name), this.channels);
};


var Channel = function(ws, name, channels) {
DumbEventTarget.call(this);
var that = this;
this.ws = ws;
this.name = name;
this.channels = channels;
var onopen = function() {
that.ws.send('sub,' + that.name);
that.emit('open');
};
if(ws.readyState > 0) {
setTimeout(onopen, 0);
} else {
this.ws.addEventListener('open', onopen);
}
};
Channel.prototype = new DumbEventTarget()

Channel.prototype.send = function(data) {
this.ws.send('msg,' + this.name + ',' + data);
};
Channel.prototype.close = function() {
var that = this;
this.ws.send('uns,' + this.name);
delete this.channels[this.name];
setTimeout(function(){that.emit('close', {});},0);
};

return WebSocketMultiplex;
})();
Loading

0 comments on commit f7a346d

Please sign in to comment.