@steelbreeze/broker
Version:
Lightweight publish and subscribe using Server-Sent Events for node and express
62 lines (61 loc) • 2.68 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var express_1 = require("express");
// find or create a topic given its name
function getTopic(topics, topic) {
return topics[topic] || (topics[topic] = { lastEventId: -1, data: undefined, subscribers: [] });
}
// write a single message to a client
function sendEvent(client, eventId, data) {
setImmediate(function (client, eventId, data) {
client.write("id:" + eventId + "\ndata:" + data + "\n\n");
}, client, eventId, data);
}
/**
* Creates an instance of a message broker server.
* Many message broker servers may be created, each bound to a different base url.
* @param cacheLastMessage When true, subscribers will receive the last message upon subscrition.
* @returns Returns an express Router for use within an express application.
*/
function server(cacheLastMessage) {
if (cacheLastMessage === void 0) { cacheLastMessage = false; }
var router = express_1.Router();
var topics = {};
// GET method is used to subscribe by EventSource clients
router.get('*', function (req, res) {
var topic = getTopic(topics, req.url);
// remove the subscription when the connection closes
req.on('close', function () {
topic.subscribers.splice(topic.subscribers.indexOf(res), 1);
});
// create the subscription
topic.subscribers.push(res);
// set the response headers to specify this is an event stream
res.set({ 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' });
// update the client with the last message if required
if (cacheLastMessage && topic.data) {
sendEvent(res, topic.lastEventId, topic.data);
}
});
router.post('*', function (req, res) {
var topic = getTopic(topics, req.url);
var body = [];
// read the post body
req.on('data', function (chunk) {
body.push(chunk);
});
req.on('end', function () {
// update the topic with the new event details
topic.data = Buffer.concat(body).toString();
topic.lastEventId = (topic.lastEventId === Number.MAX_VALUE ? -1 : topic.lastEventId) + 1;
// queue dispatch of event to all current subscribers
topic.subscribers.forEach(function (subscriber) {
sendEvent(subscriber, topic.lastEventId, topic.data); // NOTE: as we have just set topic.data we know it's not undefined
});
});
// send response to publisher
res.sendStatus(200);
});
return router;
}
exports.server = server;