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