diff --git a/example2/README b/example2/README
new file mode 100644
index 0000000000..30ee544316
--- /dev/null
+++ b/example2/README
@@ -0,0 +1,18 @@
+Channel or Chat Room Example.
+===========
+
+This is an extension of the original chat example showcasing how one may want to
+use channels for communication versus a catch all approach.
+
+The user is asked for their username and the channels they want to subscribe to.
+
+If users are connected to at least one common channel then they can chat with each
+other. Channels can be entered in comma delimeted form.
+
+There is also an example of two APIs
+ /api/who - responds with the usernames of who is connected in JSON
+ /api/send - Allows you to send data to a channel. You need to specify the
+ following parameters (username, message, publish) where publish is
+ the channel list.
+
+Note: This example is lacking the buffering that is used in the first example.
diff --git a/example2/chat.html b/example2/chat.html
new file mode 100644
index 0000000000..7a5def4291
--- /dev/null
+++ b/example2/chat.html
@@ -0,0 +1,109 @@
+
+
+ socket.io client test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example2/json.js b/example2/json.js
new file mode 100644
index 0000000000..0dff7ccdb2
--- /dev/null
+++ b/example2/json.js
@@ -0,0 +1,18 @@
+if(!this.JSON){JSON=function(){function f(n){return n<10?'0'+n:n;}
+Date.prototype.toJSON=function(){return this.getUTCFullYear()+'-'+
+f(this.getUTCMonth()+1)+'-'+
+f(this.getUTCDate())+'T'+
+f(this.getUTCHours())+':'+
+f(this.getUTCMinutes())+':'+
+f(this.getUTCSeconds())+'Z';};var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};function stringify(value,whitelist){var a,i,k,l,r=/["\\\x00-\x1f\x7f-\x9f]/g,v;switch(typeof value){case'string':return r.test(value)?'"'+value.replace(r,function(a){var c=m[a];if(c){return c;}
+c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+
+(c%16).toString(16);})+'"':'"'+value+'"';case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
+if(typeof value.toJSON==='function'){return stringify(value.toJSON());}
+a=[];if(typeof value.length==='number'&&!(value.propertyIsEnumerable('length'))){l=value.length;for(i=0;i 50) return null;
+ if (/[^\w_\-^!]/.exec(username)) return null;
+
+ // Create or add to the channel and add the client to it.
+ for (var i=0; i< channelNames.length; i++) {
+ cn = channelNames[i];
+ if (!subscriptions.channels[cn]) subscriptions.channels[cn] = [];
+ subscriptions.channels[cn].push(client);
+ }
+
+ // Store the details of the subscription
+ var membership = {
+ username: username,
+ channels: channelNames,
+ id: client.sessionId,
+ timestamp: new Date(),
+
+ poke: function () {
+ membership.timestamp = new Date();
+ },
+
+ destroy: function () {
+ var clientChannels = subscriptions.memberships[client.sessionId].channels;
+ for (var i=0; i< clientChannels.length; i++) {
+ var channel = clientChannels[i],
+ idx = subscriptions.channels[channel].indexOf(client);
+ subscriptions.channels[channel].splice(idx,1);
+ }
+ delete subscriptions.memberships[client.sessionId];
+ }
+ };
+
+ subscriptions.memberships[membership.id] = membership;
+ },
+
+ publish: function (channels,message) {
+ var receivedClients = [];
+ for (var i = 0; i < channels.length; i++) {
+ var clients = this.channels[channels[i]];
+ if (clients === undefined) continue;
+ for (var j = 0; j < clients.length; j++) {
+ if (receivedClients.indexOf(clients[j]) > -1) continue;
+ clients[j].send(message);
+ receivedClients.push(clients[j]);
+ }
+ }
+ }
+},
+
+ processMessage = function(client,obj){
+ if (client != null && obj.subscribe && obj.username) {
+ sys.log("Rx: subscribing to " +obj.subscribe+ " by "+obj.username);
+ subscriptions.newSubscription(client,obj.username,obj.subscribe);
+ var membership = subscriptions.memberships[client.sessionId],
+ message = { announcement: membership.username + ' connected' };
+ subscriptions.publish(membership.channels,message);
+ client.send({ subscribed: true });
+ } else if (client != null && obj.publish && obj.message) {
+ var membership = subscriptions.memberships[client.sessionId],
+ message = {message: [membership.username, obj.message]};
+ sys.log("Rx: publishing to " +obj.publish+ " by "+membership.username);
+ subscriptions.publish(obj.publish,message);
+ } else if (client == null && obj.publish && obj.message && obj.username) {
+ var message = {message: [obj.username, obj.message]};
+ sys.log("Rx: publishing TEXT to " +obj.publish+ " by "+obj.username);
+ subscriptions.publish(obj.publish,message);
+ } else if (client == null && obj.publish && obj.json && obj.username) {
+ var message = {json: [obj.username, obj.json]};
+ sys.log("Rx: publishing JSON to " +obj.publish+ " by "+obj.username);
+ subscriptions.publish(obj.publish,message);
+ } else {
+ var obj_str = [],
+ error = new Error("API:processMessage:unknownParams -");
+ for(a in obj) obj_str.push(" obj["+ a + "] => " + obj[a]);
+ error.message += obj_str.join();
+ error['code'] = 100;
+ throw error;
+ }
+ },
+
+server = http.createServer(function(req, res){
+ // your normal server code
+ var path = url.parse(req.url).pathname;
+ switch (path){
+ case '/':
+ res.writeHead(200, {'Content-Type': 'text/html'});
+ res.write('Welcome. Try the chat example.
');
+ res.end();
+ break;
+ case '/json.js':
+ case '/chat.html':
+ fs.readFile(__dirname + path, function(err, data){
+ if (err) return send404(res);
+ res.writeHead(200, {'Content-Type': path == 'json.js' ? 'text/javascript' : 'text/html'})
+ res.write(data, 'utf8');
+ res.end();
+ });
+ break;
+ case "/api/who":
+ var usernames = [];
+ for (var id in subscriptions.memberships) {
+ if (!subscriptions.memberships.hasOwnProperty(id)) continue;
+ var membership = subscriptions.memberships[id];
+ usernames.push(membership.username);
+ }
+ sendJSON(res, 200, { usernames: usernames, stat: "ok" });
+ break;
+
+ case "/api/send":
+ var obj = {
+ username: qs.parse(url.parse(req.url).query).username,
+ message: qs.parse(url.parse(req.url).query).text,
+ publish: qs.parse(url.parse(req.url).query).channels
+ }
+
+ try {
+ processMessage(null,obj);
+ sendJSON(res,200,{stat: "ok"});
+ } catch(e) {
+ sendJSON(res,200,{stat: "fail", code: e.code, message: e.message});
+ }
+ break;
+ default: send404(res);
+ }
+});
+
+server.listen(8080);
+var io = io.listen(server);
+
+io.on('connection', function(client){
+
+ client.on('message', function(obj) {
+ processMessage(client,obj);
+ });
+
+ client.on('disconnect', function(){
+ if (subscriptions.memberships.hasOwnProperty(client.sessionId)) {
+ var membership = subscriptions.memberships[client.sessionId],
+ message = { announcement: membership.username + ' disconnected' };
+ subscriptions.publish(membership.channels,message);
+ subscriptions.memberships[client.sessionId].destroy();
+ }
+ });
+
+});