aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaximilien Cuony <maximilien@theglu.org>2016-09-11 03:02:00 +0200
committerMaximilien Cuony <maximilien@theglu.org>2016-09-11 03:02:00 +0200
commit007ea5571e2dca4d2ce6db7b3e7f98b86bf929ab (patch)
tree1485b4bb170f99cf5937bac13aef98b021160810
parentd381c117e8ac5986805ede5db2beca273b967e2f (diff)
downloadglutte-serial-web-007ea5571e2dca4d2ce6db7b3e7f98b86bf929ab.tar.gz
glutte-serial-web-007ea5571e2dca4d2ce6db7b3e7f98b86bf929ab.tar.bz2
glutte-serial-web-007ea5571e2dca4d2ce6db7b3e7f98b86bf929ab.zip
Use websocket and add multiple-user at the same time
-rw-r--r--.gitignore2
-rwxr-xr-xglutte_serial_web.py58
-rw-r--r--glutte_serial_web.unit.example2
-rw-r--r--requirements.txt2
-rw-r--r--serialrx.py44
-rw-r--r--templates/index.html27
6 files changed, 88 insertions, 47 deletions
diff --git a/.gitignore b/.gitignore
index de7c34d..2f0f98c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,5 @@ bin
include
lib
pip-selfcheck.json
+*.pyc
+.ropeproject
diff --git a/glutte_serial_web.py b/glutte_serial_web.py
index bcb3261..016c8da 100755
--- a/glutte_serial_web.py
+++ b/glutte_serial_web.py
@@ -2,7 +2,7 @@
#
# The MIT License (MIT)
#
-# Copyright (c) 2016 Matthias P. Braendli
+# Copyright (c) 2016 Matthias P. Braendli, Maximilien Cuony
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -22,35 +22,57 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-from gevent.wsgi import WSGIServer
+from geventwebsocket.handler import WebSocketHandler
+from gevent import pywsgi, Timeout
from time import sleep
from flask import Flask, render_template
+from flask_sockets import Sockets
import serialrx
app = Flask(__name__)
+sockets = Sockets(app)
ser = serialrx.SerialRX()
+
@app.route('/')
def index():
return render_template('index.html')
-@app.route('/stream')
-def stream():
- def generate():
- while True:
- line = ser.get_line()
- if line is not None:
- yield line
+
+@sockets.route('/stream')
+def stream(socket):
+
+ try:
+
+ queue = ser.register_client()
+
+ while not socket.closed:
+ # Force to check if the client is still here
+ try:
+ with Timeout(0.1, False):
+ socket.receive()
+ except:
+ pass
+ try:
+ line = queue.popleft()
+ socket.send(line)
+ except IndexError:
+ pass
sleep(0.1)
+ except:
+ raise
+ finally:
+ ser.unregister_client(queue)
- return app.response_class(generate(), mimetype='text/plain')
+ser.start()
-try:
- ser.start()
- http_server = WSGIServer(('', 5000), app)
- http_server.serve_forever()
-except KeyboardInterrupt:
- print("Ctrl-C received, quitting")
-finally:
- ser.stop()
+if __name__ == "__main__":
+ print("You're running in dev mode, only one client at a time will works ! Please use gunicorn to fix this :)")
+ try:
+ http_server = pywsgi.WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
+ http_server.serve_forever()
+ except KeyboardInterrupt:
+ print("Ctrl-C received, quitting")
+ finally:
+ ser.stop()
diff --git a/glutte_serial_web.unit.example b/glutte_serial_web.unit.example
index cbc86db..5ee8b4b 100644
--- a/glutte_serial_web.unit.example
+++ b/glutte_serial_web.unit.example
@@ -6,5 +6,5 @@ After=syslog.target network.target
Type=simple
User=glutte
WorkingDirectory=/home/glutte/glutte-serial-web
-ExecStart=/home/glutte/glutte-serial-web/bin/python /home/glutte/glutte-serial-web/glutte_serial_web.py
+ExecStart=/home/glutte/glutte-serial-web/bin/gunicorn -k flask_sockets.worker glutte_serial_web:app -b 0.0.0.0:5000
diff --git a/requirements.txt b/requirements.txt
index 84f7820..e9ee31f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,3 +7,5 @@ Jinja2==2.8
MarkupSafe==0.23
pyserial==3.1.1
Werkzeug==0.11.11
+Flask-Sockets==0.2.1
+gunicorn==19.6.0
diff --git a/serialrx.py b/serialrx.py
index 66de50b..37855f6 100644
--- a/serialrx.py
+++ b/serialrx.py
@@ -2,7 +2,7 @@
#
# The MIT License (MIT)
#
-# Copyright (c) 2016 Matthias P. Braendli
+# Copyright (c) 2016 Matthias P. Braendli, Maximilien Cuony
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -22,16 +22,17 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-from time import sleep
import serial
import threading
import collections
-SERIALPORT="/dev/ttyACM0"
-BAUDRATE=9600
-LINES_TO_KEEP=200
+SERIALPORT = "/dev/ttyACM0"
+BAUDRATE = 9600
+LINES_TO_KEEP = 200
+
class SerialRX(threading.Thread):
+
def __init__(self):
threading.Thread.__init__(self)
@@ -41,7 +42,7 @@ class SerialRX(threading.Thread):
self.event_stop = threading.Event()
self.data_lock = threading.Lock()
- self.data_queue = collections.deque()
+ self.clients = []
self.line_accumulator = []
@@ -56,24 +57,39 @@ class SerialRX(threading.Thread):
if databyte == "\n":
self.data_lock.acquire()
try:
- self.data_queue.append("".join(self.line_accumulator))
- if len(self.data_queue) > LINES_TO_KEEP:
- self.data_queue.popleft()
+ for queue in self.clients:
+ queue.append("".join(self.line_accumulator))
+
+ if len(queue) > LINES_TO_KEEP:
+ queue.popleft()
except:
raise
finally:
self.data_lock.release()
self.line_accumulator = []
-
def stop(self):
self.event_stop.set()
self.join()
- def get_line(self):
+ def register_client(self):
+ self.data_lock.acquire()
try:
- return self.data_queue.popleft()
- except IndexError:
- return None
+ new_queue = collections.deque()
+ self.clients.append(new_queue)
+ except:
+ raise
+ finally:
+ self.data_lock.release()
+
+ return new_queue
+ def unregister_client(self, queue):
+ self.data_lock.acquire()
+ try:
+ self.clients.remove(queue)
+ except:
+ raise
+ finally:
+ self.data_lock.release()
diff --git a/templates/index.html b/templates/index.html
index 1b68ce2..038130d 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -5,19 +5,18 @@
<title>Moniteur de Glutte</title>
<link rel="stylesheet" href="static/style.css" type="text/css" media="screen" charset="utf-8"/>
</head>
-<body>
- <h1>Ceci n'est pas une Glutte</h1>
-<pre id="output"></pre>
-<script>
- var output = document.getElementById('output');
+ <body>
+ <h1>Ceci n'est pas une Glutte</h1>
+ <pre id="output"></pre>
+ <script>
+ var output = document.getElementById('output');
- var xhr = new XMLHttpRequest();
- xhr.open('GET', '{{ url_for('stream') }}');
- xhr.send();
+ var socket = new WebSocket("ws://" + window.location.host + "/stream");
- setInterval(function() {
- output.textContent = xhr.responseText;
- window.scrollTo(0, document.body.scrollHeight);
- }, 1000);
-</script>
-</body></html>
+ socket.onmessage = function(data) {
+ output.textContent += data.data;
+ window.scrollTo(0, document.body.scrollHeight);
+ }
+ </script>
+ </body>
+</html>