From 798c126d76247d9b41d07bf30aaa41d5daea63bb Mon Sep 17 00:00:00 2001 From: Miguel Grinberg <miguelgrinberg50@gmail.com> Date: Tue, 1 Sep 2015 23:10:44 -0700 Subject: [PATCH] Added a latency check example --- examples/README.rst | 49 +++++++++++++++++ {example => examples}/app.py | 0 examples/latency.py | 46 ++++++++++++++++ {example => examples}/requirements.txt | 0 examples/static/style.css | 4 ++ {example => examples}/templates/index.html | 2 +- examples/templates/latency.html | 64 ++++++++++++++++++++++ socketio/server.py | 2 +- tox.ini | 2 +- 9 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 examples/README.rst rename {example => examples}/app.py (100%) create mode 100755 examples/latency.py rename {example => examples}/requirements.txt (100%) create mode 100644 examples/static/style.css rename {example => examples}/templates/index.html (99%) mode change 100644 => 100755 create mode 100755 examples/templates/latency.html mode change 100644 => 100755 socketio/server.py diff --git a/examples/README.rst b/examples/README.rst new file mode 100644 index 0000000..a67563e --- /dev/null +++ b/examples/README.rst @@ -0,0 +1,49 @@ +Engine.IO Examples +================== + +This directory contains example Engine.IO applications. + +app.py +------ + +A basic "kitchen sink" type application that allows the user to experiment +with most of the available features of the server. + +latency.py +---------- + +A port of the latency application included in the official Engine.IO +Javascript server. In this application the client sends *ping* messages to +the server, which are responded by the server with a *pong*. The client +measures the time it takes for each of these exchanges and plots these in real +time to the page. + +This is an ideal application to measure the performance of the different +asynchronous modes supported by the Socket.IO server. + +Running the Examples +-------------------- + +To run these examples using the default ``'threading'`` mode, create a virtual +environment, install the requirements and then run:: + + $ python app.py + +or:: + + $ python latency.py + +Near the top of the ``app.py`` and ``latency.py`` source files there is a +``async_mode`` variable that can be edited to swich to the other asynchornous +modes. Accepted values for ``async_mode`` are ``'threading'``, ``'eventlet'`` +and ``'gevent'``. + +Note 1: when using the ``'eventlet'`` mode, the eventlet package must be +installed in the virtual environment:: + + $ pip install eventlet + +Note 2: when using the ``'gevent'`` mode, the gevent and gevent-websocket +packages must be installed in the virtual environment:: + + $ pip install gevent gevent-websocket diff --git a/example/app.py b/examples/app.py similarity index 100% rename from example/app.py rename to examples/app.py diff --git a/examples/latency.py b/examples/latency.py new file mode 100755 index 0000000..191a069 --- /dev/null +++ b/examples/latency.py @@ -0,0 +1,46 @@ +from flask import Flask, render_template + +import socketio + +# set this to 'threading', 'eventlet', or 'gevent' +async_mode = 'eventlet' + +sio = socketio.Server(async_mode=async_mode) +app = Flask(__name__) +app.wsgi_app = socketio.Middleware(sio, app.wsgi_app) + + +@app.route('/') +def index(): + return render_template('latency.html') + + +@sio.on('ping') +def ping(sid): + sio.emit('pong', room=sid) + + +if __name__ == '__main__': + if async_mode == 'threading': + # deploy with Werkzeug + app.run(threaded=True) + elif async_mode == 'eventlet': + # deploy with eventlet + import eventlet + from eventlet import wsgi + wsgi.server(eventlet.listen(('', 5000)), app) + elif async_mode == 'gevent': + # deploy with gevent + from gevent import pywsgi + try: + from geventwebsocket.handler import WebSocketHandler + websocket = True + except ImportError: + websocket = False + if websocket: + pywsgi.WSGIServer(('', 5000), app, + handler_class=WebSocketHandler).serve_forever() + else: + pywsgi.WSGIServer(('', 5000), app).serve_forever() + else: + print('Unknown async_mode: ' + async_mode) diff --git a/example/requirements.txt b/examples/requirements.txt similarity index 100% rename from example/requirements.txt rename to examples/requirements.txt diff --git a/examples/static/style.css b/examples/static/style.css new file mode 100644 index 0000000..d20bcad --- /dev/null +++ b/examples/static/style.css @@ -0,0 +1,4 @@ +body { margin: 0; padding: 0; font-family: Helvetica Neue; } +h1 { margin: 100px 100px 10px; } +h2 { color: #999; margin: 0 100px 30px; font-weight: normal; } +#latency { color: red; } diff --git a/example/templates/index.html b/examples/templates/index.html old mode 100644 new mode 100755 similarity index 99% rename from example/templates/index.html rename to examples/templates/index.html index 402bf40..1668814 --- a/example/templates/index.html +++ b/examples/templates/index.html @@ -2,7 +2,7 @@ <html> <head> <title>Flask-SocketIO Test</title> - <script type="text/javascript" src="//code.jquery.com/jquery-1.4.2.min.js"></script> + <script type="text/javascript" src="//code.jquery.com/jquery-2.1.4.min.js"></script> <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script> <script type="text/javascript" charset="utf-8"> $(document).ready(function(){ diff --git a/examples/templates/latency.html b/examples/templates/latency.html new file mode 100755 index 0000000..f2f8624 --- /dev/null +++ b/examples/templates/latency.html @@ -0,0 +1,64 @@ +<!doctype html> +<html> + <head> + <title>Socket.IO Latency</title> + <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}" /> + </head> + <body> + <h1>Socket.IO Latency <span id="latency"></span></h1> + <h2 id="transport">(connecting)</h2> + <canvas id="chart" height="200"></canvas> + + <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js"></script> + <script src="//cdnjs.cloudflare.com/ajax/libs/smoothie/1.27.0/smoothie.js"></script> + <script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script> + <script> + // socket + var socket = io.connect('http://' + document.domain + ':' + location.port); + var char = $('chart').get(0); + socket.on('connect', function() { + if (chart.getContext) { + render(); + window.onresize = render; + } + send(); + }); + socket.on('pong', function() { + var latency = new Date - last; + $('#latency').text(latency + 'ms'); + if (time) + time.append(+new Date, latency); + setTimeout(send, 100); + }); + socket.on('disconnect', function() { + if (smoothie) + smoothie.stop(); + $('#transport').text('(disconnected)'); + }); + + var last; + function send() { + last = new Date; + socket.emit('ping'); + $('#transport').text(socket.io.engine.transport.name); + } + + // chart + var smoothie; + var time; + function render() { + if (smoothie) + smoothie.stop(); + chart.width = document.body.clientWidth; + smoothie = new SmoothieChart(); + smoothie.streamTo(chart, 1000); + time = new TimeSeries(); + smoothie.addTimeSeries(time, { + strokeStyle: 'rgb(255, 0, 0)', + fillStyle: 'rgba(255, 0, 0, 0.4)', + lineWidth: 2 + }); + } + </script> + </body> +</html> diff --git a/socketio/server.py b/socketio/server.py old mode 100644 new mode 100755 index 1e8495e..a9cdbb5 --- a/socketio/server.py +++ b/socketio/server.py @@ -150,7 +150,7 @@ class Server(object): return set_handler set_handler(handler) - def emit(self, event, data, room=None, skip_sid=None, namespace=None, + def emit(self, event, data=None, room=None, skip_sid=None, namespace=None, callback=None): """Emit a custom event to one or more connected clients. diff --git a/tox.ini b/tox.ini index c1d118a..224f72e 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,7 @@ basepython=python deps= flake8 commands= - flake8 --exclude=".*" socketio tests example + flake8 --exclude=".*" socketio tests [testenv:py27] basepython=python2.7