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 + + + + + + + + + +
+ Username: + +
+ + +
+ Channels: + +
+ + +

Connecting...

+
+ +
+ + + + + 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(); + } + }); + +});