Permalink
Browse files

Initial import

Original code from sockjs-node/examples/multiplex commit 5481094b322541e5976b3577b87b82031c824645
0 parents commit f7a346d5406e9975ae317bc84c5bce708efe90e2 @majek majek committed Mar 16, 2012
Showing with 448 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +20 −0 Makefile
  3. +68 −0 README.md
  4. +3 −0 VERSION-GEN
  5. +19 −0 examples/sockjs/README.md
  6. +96 −0 examples/sockjs/index.html
  7. +9 −0 examples/sockjs/package.json
  8. +52 −0 examples/sockjs/server.js
  9. +86 −0 multiplex_client.js
  10. +78 −0 multiplex_server.js
  11. +15 −0 package.json
@@ -0,0 +1,2 @@
+examples/sockjs/node_modules
+
@@ -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
@@ -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.
@@ -0,0 +1,3 @@
+#!/usr/bin/env node
+var fs = require('fs')
+console.log(JSON.parse(fs.readFileSync('package.json')).version)
@@ -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.
@@ -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>
@@ -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" : "*"
+ }
+}
@@ -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');
+});
@@ -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;
+})();
Oops, something went wrong.

0 comments on commit f7a346d

Please sign in to comment.