-
-
Save nivertech/1643038 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 = (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() |
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 | |
# 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