Created
January 4, 2012 15:54
-
-
Save linus/1560654 to your computer and use it in GitHub Desktop.
Server-side Events with Node.js and Redis
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
redis = require 'redis' | |
# Make sure multi-line messages are properly formatted | |
formatData = (data) -> | |
data.split(/\n/).join "\ndata: " | |
# Format data as an event | |
formatEvent = (type, data) -> | |
""" | |
id: #{+new Date} | |
event: #{type}\n | |
data: #{formatData data} | |
""" | |
# Stream events on redis channel to response | |
stream = (config, req, res) -> | |
channel = req.url[1..] | |
unless channel in req.user.auctions.concat req.user.username | |
res.writeHead 403 | |
return res.end() | |
res.writeHead 200, | |
'content-type': 'text/event-stream' | |
'cache-control': 'no-cache' | |
'connection': 'keep-alive' | |
res.write '' | |
sub = redis.createClient config | |
sub.on 'pmessage', (pattern, chan, message) -> | |
type = chan.slice channel.length | |
res.write formatEvent type, message | |
sub.psubscribe channel + '*' | |
finish = (err) -> | |
console.error err if err | |
sub.quit() | |
res.end() | |
req.on 'close', finish | |
req.on 'error', finish | |
# SSE middleware | |
module.exports = (config) -> | |
(req, res, next) -> | |
if req.accepts 'event-stream' | |
stream config, req, res | |
else | |
next() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
linus@Newton:~$ redis-cli | |
redis 127.0.0.1:6379> publish /updates.foo "hello there!" | |
(integer) 1 | |
redis 127.0.0.1:6379> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
finish = (err) -> | |
console.error err if err | |
sub.quit() | |
res.end() | |
# Clean up when request is closed | |
req.on 'close', finish | |
req.on 'error', finish | |
# 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