WebSocket with socket.io

Here’s a sample chat using socket.io. You can find the codes here. Live Demo. The style sheet is modified to work on iPhone, Android, Chrome, etc.

The server echoes back all messages sent by each user in a browser. Socket.io falls back gracefully with browser’s capability on supporting websocket.

server.js using Express 3, Consolidate, Dust and Socket.IO. Socket.IO listens on port 8080 while Express listens on port 3000.

var express = require('express')
  , http = require('http')
  , _ = require('underscore')._
  , engines = require('consolidate')
  , path = require('path');

var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);

io.set('log level', 1);

app.engine('dust', engines.dust);

app.configure(function(){
  app.set('port', process.env.PORT || 3000);
  app.set('views', __dirname + '/');
  app.set('view engine', 'dust');
  app.use(express.favicon());
  app.use(express.logger('default'));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(express.cookieParser('your secret here'));
  app.use(express.session());
  app.use(app.router);
  app.use(express.static(path.join(__dirname, '/public')));
});

app.configure('production', function(){
  app.use(express.errorHandler());
});

app.get('/', function(req, res) {
  res.render('index', {});
});

io.configure('production', function() {
  io.enable('browser client minification');
  io.enable('browser client gzip');
  io.enable('browser client etag');
  io.enable('log');
  io.set('transports', [
    'websocket'
   ,'flashsocket'
   ,'htmlfile'
   ,'xhr-polling'
   ,'json-polling'
  ]);
});

server.listen(8080);
console.log("io server listening on port 8080");

app.listen(app.get('port'), function(){
  console.log("express server listening on port " + app.get('port'));
});

var nicknames = {};

io.sockets.on('connection', function(socket) {
  socket.on('message', function(msg) {
    socket.broadcast.emit('message', socket.nickname, msg);
  });

  socket.on('nickname', function(nick, fn) {
    if (nicknames[nick]) {
      fn(true);
    } else {
      fn(false);
      nicknames[nick] = socket.nickname = nick;
      socket.broadcast.emit('announcement', nick + ' connected');
      io.sockets.emit('nicknames', nicknames);
    }
  });

  socket.on('disconnect', function() {
    if (!socket.nickname) return;

    delete nicknames[socket.nickname];
    socket.broadcast.emit('announcement', socket.nickname + ' disconnected');
    socket.broadcast.emit('nicknames', nicknames);
  });

});

Client index.html

<!DOCTYPE html>
<html>
<head>
<link href="style.css" rel="stylesheet" type="text/css"/>
<script src="http://code.jquery.com/jquery-1.7.1.min.js" type="text/javascript"></script>
<script src="socket.io.js" type="text/javascript"></script>
<script type="text/javascript">
  var socket = io.connect('http://69.55.55.81:8080');

  socket.on('connect', function() {
    console.log('connected');
    $('#chat').addClass('connected');
  });

  socket.on('announcement', function(msg) {
    console.log(msg);
    $('#lines').append($('<p>').append($('<em>').text(msg)));
  });

  socket.on('nicknames', function(nicknames) {
    $('#nicknames').empty().append($('<span>Online: </span>'));
    for (var i in nicknames) {
      $('#nicknames').append($('<b>').text(nicknames[i]));
    }
  });

  socket.on('message', message);

  socket.on('reconnect', function() {
    console.log('reconnect');
    $('#lines').remove();
    message('System', 'Reconnected to the server');
  });

  socket.on('reconnecting', function() {
    message('System', 'Attempting to reconnect to the server');
  });

  socket.on('error', function(e) {
    message('System', e ? e : 'An unknown error occured');
  });

  function message(from, msg) {
    console.log(msg);
    $('#lines').append($('<p>').append($('<b>').text(from), msg));
  }

  $(function() {
    $('#set-nickname').submit(function(e) {
      socket.emit('nickname', $('#nick').val(), function(set) {
        if (!set) {
          clear();
          return $('#chat').addClass('nickname-set');
        }
        $('#nickname-err').css('visibility', 'visible');
      });
      return false;
    });

    $('#send-message').submit(function() {
      console.log('submit');
      message('me', $('#message').val());
      socket.emit('message', $('#message').val());
      clear();
      $('#lines').get(0).scrollTop = 10000000;
      return false;
    });

    function clear() {
      console.log('focus');
      $('#message').val('').focus();
    };
  });
</script>
</head>
<body>
<div id="chat">
  <div id="nickname">
    <form class="wrap" id="set-nickname">
      <p>Please type in your nickname and press enter.</p>
      <input id="nick" type="text"/>
      <p id="nickname-err">Nickname already in use</p>
    </form>
  </div>
  <div id="connecting">
    <span class="wrap">Connecting to socket.io server</span>
  </div>
  <div id="messages">
    <div id="nicknames"></div>
    <div id="lines"></div>
  </div>
  <form id="send-message">
    <input id="message" type="text"/>
    <button type="button" text="Send"/>
  </form>
</div>

</body>
</html>

About rp8

Specialized in building sophisticated systems for trading & risks in commodity, exotics, commodity index & structured products. Specially interested in using open source stacks and cloud computing to build new generation of services and apps. Enjoy mountain biking & photography. github
This entry was posted in Node.js and tagged , , , , . Bookmark the permalink.