Skip to content

Instantly share code, notes, and snippets.

@nivertech
Forked from linus/Publish a message
Created January 19, 2012 21:50
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nivertech/1643038 to your computer and use it in GitHub Desktop.
Save nivertech/1643038 to your computer and use it in GitHub Desktop.
Server-side Events with Node.js and Redis
redis = require 'redis'
# Make sure multi-line messages are properly formatted
formatData = (data) ->
data.split(/\n/).join "\ndata: "
# Format data as an event
formatEvent = (data) ->
"""
id: #{+new Date}
data: #{formatData data}
"""
# Stream events on redis channel to response
stream = (sub, req, res) ->
res.writeHead 200,
'content-type': 'text/event-stream'
'cache-control': 'no-cache'
'connection': 'keep-alive'
res.write ''
sub.on 'message', (channel, message) ->
res.write formatEvent message
sub.subscribe req.url
req.on 'close', ->
sub.unsubscribe req.url
res.end()
# SSE middleware
module.exports = (sub = redis.createClient()) ->
(req, res, next) ->
if req.accepts 'event-stream'
stream sub, req, res
else
next()
linus@Newton:~$ redis-cli
redis 127.0.0.1:6379> publish /updates.foo "hello there!"
(integer) 1
redis 127.0.0.1:6379>
http = require 'http'
redis = require 'redis'
# Send data as an event of optional type
sendEvent = (res, data, type) ->
# Make sure multi-line messages are properly formatted
formatData = (data) ->
data.split(/\n/).join "\ndata: "
res.write "id: #{+new Date}\n"
res.write "event: #{type}\n" if type
res.write "data: #{formatData data}\n\n"
# Handle event-stream requests
sendEvents = (req, res) ->
# Write header
res.writeHead 200,
'content-type': 'text/event-stream'
'cache-control': 'no-cache'
'connection': 'keep-alive'
res.write '' # Flush headers
# Subscribe to redis channels matching the request url
sub = redis.createClient()
channels = "#{req.url}.*"
sub.psubscribe channels
# Message handler
sub.on 'pmessage', (pattern, channel, message) ->
# Type is the last part of the channel name
type = channel.split(".").pop()
sendEvent res, message, type
# Clean up when request is closed
req.on 'close', ->
sub.unsubscribe channels
res.end()
# Send the page
sendPage = (req, res) ->
res.writeHead 200, 'content-type': 'text/html'
res.end """<!doctype html>
<html>
<head>
<script>
var logger = function(channel) {
return function(message) {
var data = message.data || message;
console.log(channel + ": ", data);
}
};
var messages = new EventSource("updates");
messages.onopen = logger("open");
messages.onerror = logger("error");
messages.onmessage = logger("message");
messages.addEventListener("foo", logger("foo"), false);
messages.addEventListener("bar", logger("bar"), false);
</script>
</head>
<body>hai</body>
</html>
"""
# Create our app
app = http.createServer (req, res) ->
if req.headers.accept is 'text/event-stream'
sendEvents req, res
else
sendPage req, res
app.listen 8000
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment