Skip to content

Commit f7a346d

Browse files
committed
Initial import
Original code from sockjs-node/examples/multiplex commit 5481094b322541e5976b3577b87b82031c824645
0 parents  commit f7a346d

11 files changed

+448
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
examples/sockjs/node_modules
2+

Makefile

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
all:
2+
3+
VER:=$(shell ./VERSION-GEN)
4+
MAJVER:=$(shell echo $(VER)|sed 's|^\([^.]\+[.][^.]\+\).*$$|\1|' )
5+
6+
CLIENT_ARTIFACTS=\
7+
websocket-multiplex-$(VER).js \
8+
websocket-multiplex-$(MAJVER).js
9+
10+
upload_client:
11+
echo "VER=$(VER) MAJVER=$(MAJVER)"
12+
cp multiplex_client.js websocket-multiplex-$(VER).js
13+
cp multiplex_client.js websocket-multiplex-$(MAJVER).js
14+
@echo -e 'Run:'
15+
@echo -e '\ts3cmd put --acl-public index.html $(CLIENT_ARTIFACTS) s3://sockjs'
16+
@echo -e '\tmake clean'
17+
18+
clean:
19+
rm $(CLIENT_ARTIFACTS)
20+
rm -rf examples/sockjs/node_modules

README.md

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
2+
WebSocket-multiplex
3+
===================
4+
5+
WebSocket-multiplex is a small library on top of SockJS that allows
6+
you to do multiplexing over a single SockJS connection.
7+
8+
The rationale for that is explained in details in the following blog
9+
post:
10+
11+
* https://www.rabbitmq.com/blog/2012/02/23/how-to-compose-apps-using-websockets/
12+
13+
14+
Usage from the browser
15+
----------------------
16+
17+
On the client side (browser) load library like that:
18+
19+
<script src="http://cdn.sockjs.org/websocket-multiplex-0.1.js">
20+
</script>
21+
22+
Alternatively, if you're using SSL:
23+
24+
<script src="https://d1fxtkz8shb9d2.cloudfront.net/websocket-multiplex-0.1.js">
25+
</script>
26+
27+
Usage example:
28+
29+
var sockjs_url = '/multiplex';
30+
var sockjs = new SockJS(sockjs_url);
31+
32+
var multiplexer = new WebSocketMultiplex(sockjs);
33+
var ann = multiplexer.channel('ann');
34+
var bob = multiplexer.channel('bob');
35+
var carl = multiplexer.channel('carl');
36+
37+
38+
Usage from the node.js server
39+
-----------------------------
40+
41+
On the node.js server side, you can use npm to get the code:
42+
43+
npm install websocket-multiplex
44+
45+
And a simplistic example:
46+
47+
var multiplex_server = require('websocket-multiplex');
48+
49+
// 1. Setup SockJS server
50+
var service = sockjs.createServer();
51+
52+
// 2. Setup multiplexing
53+
var multiplexer = new multiplex_server.MultiplexServer(service);
54+
55+
var ann = multiplexer.registerChannel('ann');
56+
ann.on('connection', function(conn) {
57+
conn.write('Ann says hi!');
58+
conn.on('data', function(data) {
59+
conn.write('Ann nods: ' + data);
60+
});
61+
});
62+
63+
// 3. Setup http server
64+
var server = http.createServer();
65+
sockjs_echo.installHandlers(server, {prefix:'/multiplex'});
66+
var app = express.createServer();
67+
68+
For a full-featured example see the `/examples` directory.

VERSION-GEN

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/usr/bin/env node
2+
var fs = require('fs')
3+
console.log(JSON.parse(fs.readFileSync('package.json')).version)

examples/sockjs/README.md

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
WebSocket-multiplex SockJS example
2+
==================================
3+
4+
To run this example, first install dependencies:
5+
6+
npm install
7+
8+
And run a server:
9+
10+
node server.js
11+
12+
13+
That will spawn an http server at http://127.0.0.1:9999/ which will
14+
serve both html (served from the current directory) and also SockJS
15+
service (under the [/multiplex](http://127.0.0.1:9999/multiplex)
16+
path).
17+
18+
With that set up, WebSocket-multiplex is able to push three virtual
19+
connections over a single SockJS connection. See the code for details.

examples/sockjs/index.html

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<!doctype html>
2+
<html><head>
3+
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
4+
<script src="http://cdn.sockjs.org/sockjs-0.2.min.js"></script>
5+
<script src="http://cdn.sockjs.org/websocket-multiplex-0.1.js"></script>
6+
<style>
7+
.box {
8+
width: 300px;
9+
float: left;
10+
margin: 0 20px 0 20px;
11+
}
12+
.box div, .box input {
13+
border: 1px solid;
14+
-moz-border-radius: 4px;
15+
border-radius: 4px;
16+
width: 100%;
17+
padding: 0px;
18+
margin: 5px;
19+
}
20+
.box div {
21+
border-color: grey;
22+
height: 300px;
23+
overflow: auto;
24+
}
25+
.box input {
26+
height: 30px;
27+
}
28+
h1 {
29+
margin-left: 75px;
30+
}
31+
body {
32+
background-color: #F0F0F0;
33+
font-family: "Arial";
34+
}
35+
</style>
36+
</head><body lang="en">
37+
<h1>SockJS Multiplex example</h1>
38+
39+
<div id="first" class="box">
40+
<div></div>
41+
<form><input autocomplete="off" value="Type here..."></input></form>
42+
</div>
43+
44+
<div id="second" class="box">
45+
<div></div>
46+
<form><input autocomplete="off"></input></form>
47+
</div>
48+
49+
<div id="third" class="box">
50+
<div></div>
51+
<form><input autocomplete="off"></input></form>
52+
</div>
53+
54+
<script>
55+
// Pipe - convenience wrapper to present data received from an
56+
// object supporting WebSocket API in an html element. And the other
57+
// direction: data typed into an input box shall be sent back.
58+
var pipe = function(ws, el_name) {
59+
var div = $(el_name + ' div');
60+
var inp = $(el_name + ' input');
61+
var form = $(el_name + ' form');
62+
63+
var print = function(m, p) {
64+
p = (p === undefined) ? '' : JSON.stringify(p);
65+
div.append($("<code>").text(m + ' ' + p));
66+
div.append($("<br>"));
67+
div.scrollTop(div.scrollTop() + 10000);
68+
};
69+
70+
ws.onopen = function() {print('[*] open', ws.protocol);};
71+
ws.onmessage = function(e) {print('[.] message', e.data);};
72+
ws.onclose = function() {print('[*] close');};
73+
74+
form.submit(function() {
75+
print('[ ] sending', inp.val());
76+
ws.send(inp.val());
77+
inp.val('');
78+
return false;
79+
});
80+
};
81+
82+
var sockjs_url = '/multiplex';
83+
var sockjs = new SockJS(sockjs_url);
84+
85+
var multiplexer = new WebSocketMultiplex(sockjs);
86+
var ann = multiplexer.channel('ann');
87+
var bob = multiplexer.channel('bob');
88+
var carl = multiplexer.channel('carl');
89+
90+
pipe(ann, '#first');
91+
pipe(bob, '#second');
92+
pipe(carl, '#third');
93+
94+
$('#first input').focus();
95+
</script>
96+
</body></html>

examples/sockjs/package.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name" : "websocket-multiplex-sockjs-example",
3+
"version" : "0.0.0-unreleasable",
4+
"dependencies" : {
5+
"express" : "2.5.8",
6+
"sockjs" : "0.2.x",
7+
"websocket-multiplex" : "*"
8+
}
9+
}

examples/sockjs/server.js

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
var express = require('express');
2+
var websocket_multiplex = require('websocket-multiplex');
3+
4+
var sockjs = require('sockjs');
5+
6+
7+
// 1. Setup SockJS server
8+
var sockjs_opts = {sockjs_url: "http://cdn.sockjs.org/sockjs-0.2.min.js"};
9+
var service = sockjs.createServer(sockjs_opts);
10+
11+
12+
// 2. Setup multiplexing
13+
var multiplexer = new websocket_multiplex.MultiplexServer(service);
14+
15+
var ann = multiplexer.registerChannel('ann');
16+
ann.on('connection', function(conn) {
17+
conn.write('Ann says hi!');
18+
conn.on('data', function(data) {
19+
conn.write('Ann nods: ' + data);
20+
});
21+
});
22+
23+
var bob = multiplexer.registerChannel('bob');
24+
bob.on('connection', function(conn) {
25+
conn.write('Bob doesn\'t agree.');
26+
conn.on('data', function(data) {
27+
conn.write('Bob says no to: ' + data);
28+
});
29+
});
30+
31+
var carl = multiplexer.registerChannel('carl');
32+
carl.on('connection', function(conn) {
33+
conn.write('Carl says goodbye!');
34+
// Explicitly cancel connection
35+
conn.end();
36+
});
37+
38+
39+
// 3. Express server
40+
var app = express.createServer();
41+
service.installHandlers(app, {prefix:'/multiplex'});
42+
43+
console.log(' [*] Listening on 0.0.0.0:9999' );
44+
app.listen(9999, '0.0.0.0');
45+
46+
app.get('/', function (req, res) {
47+
res.sendfile(__dirname + '/index.html');
48+
});
49+
50+
app.get('/multiplex.js', function (req, res) {
51+
res.sendfile(__dirname + '/multiplex.js');
52+
});

multiplex_client.js

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
var WebSocketMultiplex = (function(){
2+
3+
4+
// ****
5+
6+
var DumbEventTarget = function() {
7+
this._listeners = {};
8+
};
9+
DumbEventTarget.prototype._ensure = function(type) {
10+
if(!(type in this._listeners)) this._listeners[type] = [];
11+
};
12+
DumbEventTarget.prototype.addEventListener = function(type, listener) {
13+
this._ensure(type);
14+
this._listeners[type].push(listener);
15+
};
16+
DumbEventTarget.prototype.emit = function(type) {
17+
this._ensure(type);
18+
var args = Array.prototype.slice.call(arguments, 1);
19+
if(this['on' + type]) this['on' + type].apply(this, args);
20+
for(var i=0; i < this._listeners[type].length; i++) {
21+
this._listeners[type][i].apply(this, args);
22+
}
23+
};
24+
25+
26+
// ****
27+
28+
var WebSocketMultiplex = function(ws) {
29+
var that = this;
30+
this.ws = ws;
31+
this.channels = {};
32+
this.ws.addEventListener('message', function(e) {
33+
var t = e.data.split(',');
34+
var type = t.shift(), name = t.shift(), payload = t.join();
35+
if(!(name in that.channels)) {
36+
return;
37+
}
38+
var sub = that.channels[name];
39+
40+
switch(type) {
41+
case 'uns':
42+
delete that.channels[name];
43+
sub.emit('close', {});
44+
break;
45+
case 'msg':
46+
sub.emit('message', {data: payload});
47+
break;
48+
}
49+
});
50+
};
51+
WebSocketMultiplex.prototype.channel = function(raw_name) {
52+
return this.channels[escape(raw_name)] =
53+
new Channel(this.ws, escape(raw_name), this.channels);
54+
};
55+
56+
57+
var Channel = function(ws, name, channels) {
58+
DumbEventTarget.call(this);
59+
var that = this;
60+
this.ws = ws;
61+
this.name = name;
62+
this.channels = channels;
63+
var onopen = function() {
64+
that.ws.send('sub,' + that.name);
65+
that.emit('open');
66+
};
67+
if(ws.readyState > 0) {
68+
setTimeout(onopen, 0);
69+
} else {
70+
this.ws.addEventListener('open', onopen);
71+
}
72+
};
73+
Channel.prototype = new DumbEventTarget()
74+
75+
Channel.prototype.send = function(data) {
76+
this.ws.send('msg,' + this.name + ',' + data);
77+
};
78+
Channel.prototype.close = function() {
79+
var that = this;
80+
this.ws.send('uns,' + this.name);
81+
delete this.channels[this.name];
82+
setTimeout(function(){that.emit('close', {});},0);
83+
};
84+
85+
return WebSocketMultiplex;
86+
})();

0 commit comments

Comments
 (0)