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:
- Real-time display of the incoming flow of bids to all participants
- 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