1
0
mirror of https://github.com/binary-kitchen/doorlockd synced 2024-12-22 10:24:26 +01:00

Remove socket.io dependency and use http server sent events instead

Signed-off-by: Thomas Schmid <tom@binary-kitchen.de>
This commit is contained in:
Thomas 2018-10-17 19:16:37 +02:00 committed by Thomas Schmid
parent f1c267dc94
commit 7676f957c5
5 changed files with 107 additions and 39 deletions

View File

@ -16,7 +16,6 @@ depends=('python3'
'mosquitto' 'mosquitto'
'mpg123' 'mpg123'
'python-flask-wtf' 'python-flask-wtf'
'python-flask-socketio'
'python-paho-mqtt' 'python-paho-mqtt'
'chromium' 'chromium'
'xf86-video-fbdev' 'xf86-video-fbdev'

View File

@ -24,7 +24,7 @@ from serial import Serial
from threading import Thread from threading import Thread
from time import sleep from time import sleep
from os.path import join from os.path import join
import gevent
from .Door import DoorState from .Door import DoorState
from .Protocol import Protocol from .Protocol import Protocol

34
pydoorlock/EventClient.py Normal file
View File

@ -0,0 +1,34 @@
import requests
import threading
import json
class EventClient:
def __init__(self,url):
self.r = requests.get(url,stream=True)
print("connected")
if self.r.encoding is None:
self.r.encoding = 'utf8'
def parseEvent(self,line_buf):
ret = dict()
for line in line_buf:
if line:
k,v = line.decode().split(':',1)
ret[k] = v
return ret
def events(self):
lines = self.r.iter_lines()
line_buf = []
while True:
line_buf.append(next(lines))
if line_buf:
if not line_buf[-1].decode():
yield self.parseEvent(line_buf)
line_buf = []
if __name__ == "__main__":
e = EventClient("http://localhost:8080/push")
for evt in e.events():
print(json.loads(evt['data']))

View File

@ -16,9 +16,11 @@ details.
""" """
import logging import logging
import json
import gevent
import threading
from flask import abort, Flask, jsonify, render_template, request from flask import abort, Flask, jsonify, render_template, request, Response
from flask_socketio import SocketIO
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import PasswordField, StringField, SubmitField from wtforms import PasswordField, StringField, SubmitField
from wtforms.validators import DataRequired, Length from wtforms.validators import DataRequired, Length
@ -28,19 +30,46 @@ from .Doorlock import DoorlockResponse
from .Authenticator import AuthMethod from .Authenticator import AuthMethod
log = logging.getLogger() log = logging.getLogger()
webapp = Flask(__name__) webapp = Flask(__name__)
socketio = SocketIO(webapp, async_mode='threading') evt = threading.Event()
json_push_state = ""
def emit_doorstate(response=None): def emit_doorstate(response=None):
state = logic.state global json_push_state
json_dict = dict()
if response: if response:
message = str(response) message = str(response)
else: else:
message = str(state) message = str(logic.state)
socketio.emit('status', {'led': state.to_img(), 'message': message})
json_dict['message'] = message
json_dict['status'] = logic.state.value
json_push_state = json.dumps(json_dict)
#Notify push clients
evt.set()
evt.clear()
def event_str():
return "data: {}\n\n".format(json_push_state)
def push_state():
try:
yield event_str()
while True:
evt.wait()
yield event_str()
except GeneratorExit:
return
def push_refresh():
while True:
sleep(10)
emit_doorstate()
evt.set()
evt.clear()
class AuthenticationForm(FlaskForm): class AuthenticationForm(FlaskForm):
username = StringField('Username', [Length(min=3, max=25)]) username = StringField('Username', [Length(min=3, max=25)])
@ -64,13 +93,6 @@ class AuthenticationForm(FlaskForm):
return True return True
@socketio.on('request_status')
@socketio.on('connect')
def on_connect():
emit_doorstate()
@webapp.route('/display') @webapp.route('/display')
def display(): def display():
return render_template('display.html', return render_template('display.html',
@ -78,19 +100,25 @@ def display():
title=title, title=title,
welcome=welcome) welcome=welcome)
@webapp.route('/push')
def push():
if not json_push_state:
emit_doorstate()
return Response(push_state(),mimetype="text/event-stream")
@webapp.route('/api', methods=['POST']) @webapp.route('/api', methods=['POST'])
def api(): def api():
def json_response(response, msg=None): def json_response(response, msg=None):
json = dict() json_dict = dict()
json['err'] = response.value json_dict['err'] = response.value
json['msg'] = str(response) if msg is None else msg json_dict['msg'] = str(response) if msg is None else msg
if response == DoorlockResponse.Success or \ if response == DoorlockResponse.Success or \
response == DoorlockResponse.AlreadyActive: response == DoorlockResponse.AlreadyActive:
# TBD: Remove 'open'. No more users. Still used in App Version 2.1.1! # TBD: Remove 'open'. No more users. Still used in App Version 2.1.1!
json['open'] = logic.state.is_open() json_dict['open'] = logic.state.is_open()
json['status'] = logic.state.value json_dict['status'] = logic.state.value
return jsonify(json) return jsonify(json_dict)
user = request.form.get('user') user = request.form.get('user')
password = request.form.get('pass') password = request.form.get('pass')
@ -137,6 +165,7 @@ def home():
desired_state = authentication_form.desired_state desired_state = authentication_form.desired_state
log.info(' desired state: %s' % desired_state) log.info(' desired state: %s' % desired_state)
log.info(' current state: %s' % logic.state) log.info(' current state: %s' % logic.state)
response = logic.request(desired_state, credentials) response = logic.request(desired_state, credentials)
log.info(' response: %s' % response) log.info(' response: %s' % response)
@ -154,6 +183,7 @@ def home():
def webapp_run(cfg, my_logic, status, version, template_folder, static_folder): def webapp_run(cfg, my_logic, status, version, template_folder, static_folder):
global logic global logic
logic = my_logic logic = my_logic
state = logic.state
debug = cfg.boolean('DEBUG') debug = cfg.boolean('DEBUG')
@ -176,4 +206,5 @@ def webapp_run(cfg, my_logic, status, version, template_folder, static_folder):
webapp.config['SECRET_KEY'] = cfg.str('SECRET_KEY') webapp.config['SECRET_KEY'] = cfg.str('SECRET_KEY')
webapp.template_folder = template_folder webapp.template_folder = template_folder
webapp.static_folder = static_folder webapp.static_folder = static_folder
socketio.run(webapp, host=host, port=8080, use_reloader=False, debug=debug) webapp.debug = debug
webapp.run()

View File

@ -13,23 +13,27 @@
<script type="text/javascript" src="static/socket.io.slim.js"></script> <script type="text/javascript" src="static/socket.io.slim.js"></script>
<script type="text/javascript" charset="utf-8"> <script type="text/javascript" charset="utf-8">
$(document).ready(function() { $(document).ready(function() {
function request_status() { var source = new EventSource('{{ url_for('push')}}');
socket.emit('request_status'); source.onmessage = function(event){
} console.log("event:" + event.data);
try{
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port); var data = JSON.parse(event.data);
var timer = setInterval(request_status, 120000); $('#message').html(data.message);
led = $('#led');
socket.on('connect', function() { switch(data.status){
socket.emit('connected'); case 0:
led.attr('src','static/led-green.png');
break;
case 1:
led.attr('src','static/led-yellow.png');
break;
case 2:
led.attr('src','static/led-red.png');
break;
default:
}
} catch(e){console.log(e);}}
}); });
socket.on('status', function(status) {
$('#led').attr('src', status.led);
$('#message').html(status.message);
clearInterval(timer);
timer = setInterval(request_status, 120000);
});
});
</script> </script>
{% endblock %} {% endblock %}