Skip to content

Instantly share code, notes, and snippets.

@bryanmacfarlane
Last active July 28, 2019 23:23
Show Gist options
  • Save bryanmacfarlane/7684730 to your computer and use it in GitHub Desktop.
Save bryanmacfarlane/7684730 to your computer and use it in GitHub Desktop.
node.js http long polling server. using a messaging as an example of longpoll usage.
//
// Crude node.js longpoll example via a simple message queue
//
//--------------------
// app.js
//--------------------
var queue = require('./queue/messagequeue');
app.get('/messages/:queueName/:lastMsgId', queue.getMessages);
app.post('/messages/:queueName', queue.postMessages);
//--------------------------
// queue/messagequeue.js
//--------------------------
// message lists keyed by queuenames (dictionary of arrays)
var messages = {};
// counter for each queuename - represents next id to insert @ for a given queue (dictionary of numbers)
var counters = {};
// dictionary by queueName with a list of requests for that queueName
var queuedRequests = {}
exports.postMessages = function(req, res) {
var msgs = req.body;
var queueName = req.params.queueName;
if ((!msgs || !queueName) || (!(msgs instanceof Array))){
res.status(400).send('Bad request. Body must be an array of messages.');
return;
}
if (!messages.hasOwnProperty(queueName)) {
console.log('creating queue ' + queueName);
counters = {};
counters[queueName] = 1; // start @ 1 so client starts with lastMsgId of 0
messages[queueName] = [{"data":"0"}];
}
messages[queueName] = messages[queueName].concat(msgs);
counters[queueName] += msgs.length;
// send queued messages
if (queuedRequests.hasOwnProperty(queueName)) {
queuedRequests[queueName].forEach(function(queuedMessage){
sendMessages(queueName, queuedMessage.lastMsgId, queuedMessage.response);
});
}
res.status(200).send(msgs);
}
exports.getMessages = function(req, res) {
var queueName = req.params.queueName;
var lastMsgId = req.params.lastMsgId;
console.log('getMessages ' + queueName);
if ((!messages.hasOwnProperty(queueName)) ||
(lastMsgId == counters[queueName] - 1)) {
console.log('queuing response ...');
queueResponse(queueName, lastMsgId, res);
return;
}
if (lastMsgId >= counters[queueName]) {
res.status(400).send('Bad request. Invalid lastMsgId.');
}
sendMessages(queueName, lastMsgId, res);
}
var queueResponse = function(queueName, lastMsgId, res) {
if (!queuedRequests.hasOwnProperty(queueName)) {
queuedRequests[queueName] = [];
}
queuedRequests[queueName].push({"lastMsgId": lastMsgId, "response": res});
}
var sendMessages = function(queueName, lastMsgId, res) {
var msgs = messages[queueName].slice(parseInt(lastMsgId) + 1, counters[queueName]);
res.status(200).send({"lastMsgId": counters[queueName] - 1, "data": msgs});
}
//---------------------------------------------------------------------------------------
// client messagelistener (rest.js is just a class to do get requests and return JSON)
//---------------------------------------------------------------------------------------
var rest = require("./rest");
var _queueName;
var _host;
var _port;
var _basePath = "/messages";
var _lastMsgId = 0;
var _callback;
exports.start = function(queueName, host, port, callback) {
_queueName = queueName;
_host = host;
_port = port;
_callback = callback;
getMessages();
}
var getMessages = function() {
var path = _basePath + "/" + _queueName + "/" + _lastMsgId;
var options = {
host: _host,
port: _port,
path: path,
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
rest.getJSON(options,
function(statusCode, payload) {
_lastMsgId = payload.lastMsgId;
console.log('lastMsgId: ' + _lastMsgId);
_callback(payload.data);
getMessages();
});
}
//-----------------------------------------------
// client.js
//-----------------------------------------------
var listener = require('./messagelistener');
var queueName = "myqueue";
var host = "localhost";
var port = 3000;
console.log('listening to ' + queueName);
listener.start(queueName, host, port, function(messages) {
console.log('callback ...')
console.log(JSON.stringify(messages, null, 2));
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment