Technology

Real-Time Auctions with Node.js

A real-time auctions web site may seem complicated. Submitting a bid is just a button click, but how are you going to display it to other users in real-time. One can think of all sorts of complicated jQuery timers and calls, but there is a much simpler way with Node.js - JavaScript on the server-side.

#What We Need?

A real-time auctions web site needs two things:

  1. Real-time display of the incoming flow of bids to all participants
  2. Storage of the flow of bids from the beginning of the auction. As participants join in the middle, we need to bring them up to speed

Node.js, JavaScript on the server-side, comes built-in with what we need.

#Real-Time Communication

The real-time display of bids lets a participating user at a browser submit a bid, and the auctions site to broadcast the bid to all participants in the auction. Thus, the server should push messages to browsers. An analogy comes to mind - this is just like online Facebook chat, but here we have group calls.

Indeed, the WebSockets protocol built into Node.js with the socket.io module was intended for such real-time communication. It works in any browser, including the old-fashioned Internet Explorer 6+, on desktops, tablets, and smartphones

The real-time communication is between an auction server and any number of auctions clients - each client is a user in a browser - no download necessary - just plain old HTML and JavaScript.

#Auction Server

var httpd = require('http').createServer(handler);
var io = require('socket.io').listen(httpd);</code>
// create the server
httpd.listen(5000);

// when a client connects
io.sockets.on('connection', function (socket) {

    // listen to incoming bids
    socket.on('bid', function(content) {

        // echo to the sender
        socket.emit('bid', content["amount"]);

        // broadcast the bid to all clients
        socket.broadcast.emit('bid', socket.id + ' 
            bid: ' + content["amount"]);

    });

});

#Auction Client

A simple HTML page: an input box for the bid amount, a submit button, and a display area for bids to be filled with the incoming flow

<html>
  <body>
      <input type ="text" id="input"</input>
      <button> type="button" id="submit">Submit Bid</button>
      <p id="bids"></p>
  </body>
</html>

Include jQuery, and the socket.io.js module.

 <script src=“http://code.jquery.com/jquery-1.10.2.min.js”/>
 <script src=“http://www.example.com:5000/socket.io/socket.io.js”/>

The functionality is simple. Create a socket, listen to bids, and display them. Once a user submits a bid, transmit it to the auction server.

var socket = io.connect('http://www.example.com:5000');

socket.on('bid', function(content) {
	$('#bids').append(content["amount"] + "<br/>");
});

$('#submit').click(function(){
	socket.emit('bid', { "amount" : $('#input').val() });
});

User Identification

But wait, how we going to identify the participants. Well session management is naturally built-in as we can set values for keys on a socket. So, when a socket connects, the auction server will send a login message:

io.sockets.on('connection', function (socket) {
	socket.emit('login');
});

The auction client on receiving a login message, will reply with the username:

socket.on('login', function(){
	socket.emit('username', 'johndoe'); // hard-wired 
    	// here for simplicity
});

The server, on receiving the username, saves the username  as a key-value pair on the socket  (so you have built-in session management):

socket.on('username', function(username){
	socket.set('username', username);
});

#Storing the History of Bids

All is fine if all participants are present at the beginning of the auction in which case, each incoming bid is seen by everybody. But if participants join in later, we need to bring them up to speed.

As all bids go through the auction server listen function, we store all bids in a database. Because everything is JavaScript and JSON so far, it is easy do it with MongoDB, but MySQL is just as easy.

For a MongoDB database, using the MongoDB Native Node.js driver, we store a bid in a database on the server,

var db = new Db('auctions', new Server('locahost', 27017));
// Fetch a collection to insert document into
var collection = db.collection("bids");
// Insert a single document
collection.insert({ "username" : "johndoe", "item" : 
	"Tesla Model S", "amount" : 5000});

#Getting a Client Up to Speed

When a client connects, the server will send first the history of auctions.

#Use the Database for Historical Record

Any serious auctioneer will want to maintain the historical record and carry all sorts of analytics.

#Multiple Concurrent Auctions

Any real world auctions site will have multiple concurrent auctions running. Again, our analogy with group calls and chat helps. So when a user joins into an auction, we will set on the socket the name of the auction.

#Beefing Up the Auction Client

In the real world, we need to provide the user with some real-time trading analytics, slicing and dicing the incoming flow of bids. In most general terms, we need a database with querying capabilities. And being real-time, we want this in the browser without communication with the server. We store all bids reaching the client in an in-memory JavaScript database, TaffyDB. TaffyDB can store MB of data and has all the essential SQL stuff.

Include in your HTML,

<script src="https://github.com/typicaljoe/taffydb/raw/master/taffy.js"/>

This works in old browsers, tablets, and smartphones, as well.

Yoram Kornatzky

Yoram Kornatzky