Skip to content

Instantly share code, notes, and snippets.

@joewalnes
Created September 22, 2012 18:23
Show Gist options
  • Save joewalnes/3767299 to your computer and use it in GitHub Desktop.
Save joewalnes/3767299 to your computer and use it in GitHub Desktop.
WebSocket Slide Server

Demonstrates a way to build an HTML slide deck and allow multiple browsers to all see slide changes at the same time, triggered by something externally (via an HTTP request). Uses WebSockets to for real time updates.

Instructions

  • Requires Python. Tested on 2.7. Runs on a Pi and any old Linux/OSX setup. Should work on Python 3 - maybe.
  • Install Tornado. You can use pip install tornado or download the tarball from http://www.tornadoweb.org/.
  • Copy slides.html and slide-server.py into the same directory.
  • Run python slide-server.py. Uses sensible defaults. --help for options.
  • Open http://localhost:54321/ in your browser. Recommend Chrome.

Notes

  • If you want to include other static files, create a directory called static, and reference from /static from the web site.
  • If you want the web page to automatically reconnect if it loses connection to the server, run this: https://github.com/joewalnes/reconnecting-websocket
#!/usr/bin/env python
import tornado.ioloop
from socket import gethostname
from tornado.ioloop import IOLoop
from tornado.options import define, options, parse_command_line
from tornado.web import Application, RequestHandler, StaticFileHandler
from tornado.websocket import WebSocketHandler
# Command line options. Use --help to list
define('port', default=54321, help='HTTP port to listen on')
define('autoreload', default=False, help='Automatically watch for Python changes and restart webserver')
define('staticfiles', default='static', help='Path to static files that shall get served at /static')
# State
current_slide = 0
# Who needs to be notified when the slide changes.
slide_change_listeners = set()
class SlidesControlHandler(RequestHandler):
"""Any HTTP request to /slides-control shall increment the current slide
number and notify all listener."""
def get(self):
global current_slide
current_slide += 1
print('Slide updated: %d' % current_slide)
for listener in slide_change_listeners:
listener(current_slide)
self.write(str(current_slide))
class SlidesSubscribeHandler(WebSocketHandler):
"""WebSocket endpoint at /slides-subscribe. Upon connection it shall
send a message saying what the current slide is, and then send a new
message whenever the slide changes.
The protocol is simply a number encoded as a string. e.g. '4'. """
def open(self):
print('Websocket opened')
self.write_message(str(current_slide))
slide_change_listeners.add(self.on_slide_change)
def on_close(self):
print('Websocket closed')
slide_change_listeners.remove(self.on_slide_change)
def on_slide_change(self, slide_number):
self.write_message(str(slide_number))
def main():
parse_command_line()
application = Application([
(r"/slides-control", SlidesControlHandler),
(r"/slides-subscribe", SlidesSubscribeHandler),
(r"/()", StaticFileHandler, dict(path='slides.html')),
], debug=options.autoreload, static_path=options.staticfiles)
application.listen(options.port)
print('Listening on http://%s:%s/' % (gethostname(), options.port))
IOLoop.instance().start()
if __name__ == '__main__':
main()
<!DOCTYPE html>
<title>Slides</title>
<style>
.slide-number {
font-size: 40px;
}
</style>
<script src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
<script>
$(function() {
// Subscribe to slide changes
$('.status').text('Connecting...');
var ws = new WebSocket('ws://' + document.location.host + '/slides-subscribe');
ws.onopen = function() {
$('.status').text('Connected');
};
ws.onclose = function() {
$('.status').text('Lost connection');
};
ws.onmessage = function(e) {
var slideNumber = parseInt(e.data);
$('.slide-number').text(slideNumber);
};
// Increment
$('.next').click(function() {
$.get('/slides-control');
});
// Update curl instructions
$('.hostname').text(document.location.host);
});
</script>
<h1>Current Slide</h1>
<h2 class="slide-number">?</h2>
<div class="status"></div>
<p>
<button class="next">Next</button> or
<code>curl http://<span class="hostname"></span>/slides-control</code>
</p>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment