Cleaner code

This commit is contained in:
Andreas Völker 2018-12-30 20:45:11 +01:00
parent bc1d3312a8
commit f200a954b1

163
main.py
View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3
import config import config
import subprocess import subprocess
import os import os
@ -14,11 +14,13 @@ import signal
import logging import logging
import math import math
logging.basicConfig(filename='pixelserver.log',level=config.LogLevel) logging.basicConfig(filename='pixelserver.log', level=config.LogLevel)
running = True running = True
########################################################################
# Utils #
########################################################################
class DataSource: class DataSource:
def __init__(self, initial): def __init__(self, initial):
self.data = initial self.data = initial
@ -33,6 +35,47 @@ class DataSource:
with listener: with listener:
listener.notify_all() listener.notify_all()
class WatchDog(threading.Thread):
def __init__(self, check, action):
super().__init__()
self.check = check
self.action = action
self.running = True
def run(self):
while running and self.running:
if self.check():
logging.error("Watchdog: Executed")
self.action()
time.sleep(1)
def stop(self):
self.running = False
class LogReader(threading.Thread):
def __init__(self, runner):
super().__init__()
self.runner = runner
self.log = ""
self.running = True
def clear(self):
self.log = ""
def getLog(self):
return self.log
def run(self):
logging.info("LogReader started")
while running and self.running:
try:
self.log += self.runner.app.stderr.read(1).decode("utf-8")
except Exception as e:
print(e)
logging.error(str(e))
time.sleep(1)
logging.info("LogReader closed")
def stop(self):
self.running = False
########################################################################
# GUI #
########################################################################
if config.UseGui: if config.UseGui:
import pygame import pygame
@ -42,7 +85,6 @@ if config.UseGui:
self.datasource = datasource self.datasource = datasource
self.cv = threading.Condition() self.cv = threading.Condition()
self.datasource.addListener(self.cv) self.datasource.addListener(self.cv)
def run(self): def run(self):
global running global running
logging.info("Starting GUI") logging.info("Starting GUI")
@ -63,10 +105,8 @@ if config.UseGui:
r = (data[i*3+0]) r = (data[i*3+0])
g = (data[i*3+1]) g = (data[i*3+1])
b = (data[i*3+2]) b = (data[i*3+2])
pygame.draw.rect(screen, (r, g, b), pygame.Rect(sf*x, sf*y, sf, sf)) pygame.draw.rect(screen, (r, g, b), pygame.Rect(sf*x, sf*y, sf, sf))
except: except:
pass
raise raise
pygame.display.flip() pygame.display.flip()
logging.info("Closing GUI") logging.info("Closing GUI")
@ -75,6 +115,9 @@ if config.UseGui:
self.cv.notify_all() self.cv.notify_all()
super().join() super().join()
########################################################################
# Serial #
########################################################################
class SerialWriter(threading.Thread): class SerialWriter(threading.Thread):
def __init__(self, datasource): def __init__(self, datasource):
super().__init__() super().__init__()
@ -82,7 +125,6 @@ class SerialWriter(threading.Thread):
self.datasource = datasource self.datasource = datasource
self.datasource.addListener(self.cv) self.datasource.addListener(self.cv)
self.updateGamma = False self.updateGamma = False
def run(self): def run(self):
should_connect = True should_connect = True
ser = None ser = None
@ -124,10 +166,9 @@ class SerialWriter(threading.Thread):
should_connect = True should_connect = True
time.sleep(5) time.sleep(5)
logging.info("Closing SerialWriter") logging.info("Closing SerialWriter")
def joint(self): def join(self):
self.cv.notify_all() self.cv.notify_all()
super().join() super().join()
def setGamma(self, r, g, b): def setGamma(self, r, g, b):
with self.cv: with self.cv:
self.r = r self.r = r
@ -136,46 +177,9 @@ class SerialWriter(threading.Thread):
self.updateGamma = True self.updateGamma = True
self.cv.notify_all() self.cv.notify_all()
class WatchDog(threading.Thread): ########################################################################
def __init__(self, check, action): # App #
super().__init__() ########################################################################
self.check = check
self.action = action
self.running = True
def run(self):
while running and self.running:
if self.check():
logging.error("Watchdog: Executed")
self.action()
time.sleep(1)
def stop(self):
self.running = False
class LogReader(threading.Thread):
def __init__(self, runner):
super().__init__()
self.runner = runner
self.log = ""
self.running = True
def clear(self):
self.log = ""
def getLog(self):
return self.log
def run(self):
logging.info("LogReader started")
while running and self.running:
try:
self.log += self.runner.app.stderr.read(1).decode("utf-8")
except Exception as e:
print(e)
time.sleep(1)
logging.info("LogReader closed")
def stop(self):
self.running = False
class App(threading.Thread): class App(threading.Thread):
def __init__(self, cmd, param, listener, is_persistent): def __init__(self, cmd, param, listener, is_persistent):
super().__init__() super().__init__()
@ -194,7 +198,6 @@ class App(threading.Thread):
self.running = running self.running = running
self.listener = listener self.listener = listener
self.is_persistent = is_persistent self.is_persistent = is_persistent
def run(self): def run(self):
while running and self.running and self.alive(): while running and self.running and self.alive():
oshandle = self.app.stdout.fileno() oshandle = self.app.stdout.fileno()
@ -205,18 +208,14 @@ class App(threading.Thread):
self.datasource.pushData(data) self.datasource.pushData(data)
except Exception as e: except Exception as e:
logging.debug("Exception in App.run") logging.debug("Exception in App.run")
with self.listener: with self.listener:
self.listener.notify_all() self.listener.notify_all()
self.watchdog.stop() self.watchdog.stop()
self.logreader.stop() self.logreader.stop()
self.watchdog.join() self.watchdog.join()
self.logreader.join() self.logreader.join()
def alive(self): def alive(self):
return self.app.poll() == None return self.app.poll() == None
def stop(self): def stop(self):
self.running = False self.running = False
self.app.kill() self.app.kill()
@ -224,21 +223,19 @@ class App(threading.Thread):
self.app.stderr.close() self.app.stderr.close()
self.watchdog.stop() self.watchdog.stop()
self.logreader.stop() self.logreader.stop()
def getLog(self): def getLog(self):
return self.logreader.getLog() return self.logreader.getLog()
def isPersistent(self): def isPersistent(self):
return self.is_persistent return self.is_persistent
def terminateApp(self): def terminateApp(self):
logging.error("Terminate app!") logging.error("Terminate app!")
self.stop() self.stop()
def isAppTimedOut(self): def isAppTimedOut(self):
return time.time()-self.last_update > config.NoDataTimeout return time.time()-self.last_update > config.NoDataTimeout
########################################################################
# Main #
########################################################################
class AppRunner(threading.Thread): class AppRunner(threading.Thread):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -258,28 +255,23 @@ class AppRunner(threading.Thread):
newapp.datasource.addListener(self.cv) newapp.datasource.addListener(self.cv)
newapp.start() newapp.start()
self.persistent_apps[i] = newapp self.persistent_apps[i] = newapp
if config.UseGui: if config.UseGui:
self.gui = Gui(self.datasource) self.gui = Gui(self.datasource)
self.gui.start() self.gui.start()
def requestApp(self, app, param=""): def requestApp(self, app, param=""):
with self.cv: with self.cv:
self.requestedApp = app self.requestedApp = app
self.param = param self.param = param
self.cv.notify_all() self.cv.notify_all()
logging.info("Requesting app: "+str(app)) logging.info("Requesting app: "+str(app))
def updateApp(self): def updateApp(self):
if self.app != None and not self.app.isPersistent(): if self.app != None and not self.app.isPersistent():
self.app.stop() self.app.stop()
self.currentApp = self.requestedApp self.currentApp = self.requestedApp
if self.currentApp in self.persistent_apps.keys(): if self.currentApp in self.persistent_apps.keys():
self.app = self.persistent_apps[self.currentApp] self.app = self.persistent_apps[self.currentApp]
else: else:
persistent = config.Apps[self.requestedApp]["persistent"] persistent = config.Apps[self.requestedApp]["persistent"]
logging.info("Starting app "+config.Apps[self.requestedApp]["name"]) logging.info("Starting app "+config.Apps[self.requestedApp]["name"])
cmd = config.Apps[self.requestedApp]["cmd"] cmd = config.Apps[self.requestedApp]["cmd"]
logging.debug(str(cmd)) logging.debug(str(cmd))
@ -288,7 +280,6 @@ class AppRunner(threading.Thread):
self.app.start() self.app.start()
if persistent: if persistent:
self.persistent_apps[self.currentApp] = self.app self.persistent_apps[self.currentApp] = self.app
def run(self): def run(self):
logging.info("Starting Apprunner") logging.info("Starting Apprunner")
while running: while running:
@ -296,10 +287,8 @@ class AppRunner(threading.Thread):
if self.app == None or not self.app.alive(): if self.app == None or not self.app.alive():
self.requestedApp = 0 self.requestedApp = 0
if self.requestedApp != None: if self.requestedApp != None:
self.updateApp() self.updateApp()
self.requestedApp = None self.requestedApp = None
self.cv.wait() self.cv.wait()
if self.app != None: if self.app != None:
data = self.app.datasource.getData() data = self.app.datasource.getData()
@ -308,7 +297,6 @@ class AppRunner(threading.Thread):
if config.UseGui: if config.UseGui:
self.gui.join() self.gui.join()
logging.info("Close Apprunner") logging.info("Close Apprunner")
def getLog(self): def getLog(self):
if self.app == None: if self.app == None:
return "" return ""
@ -316,9 +304,9 @@ class AppRunner(threading.Thread):
def setGamma(self, r, g, b): def setGamma(self, r, g, b):
self.serial.setGamma(r, g, b) self.serial.setGamma(r, g, b)
########################################################################
# Startup #
########################################################################
#normalize config #normalize config
for app in config.Apps: for app in config.Apps:
if "persistent" not in app.keys(): if "persistent" not in app.keys():
@ -326,7 +314,7 @@ for app in config.Apps:
if "guiname" not in app.keys(): if "guiname" not in app.keys():
app["guiname"] = app["name"] app["guiname"] = app["name"]
#remove unavalible apps #remove non existing apps
for app in config.Apps: for app in config.Apps:
cmd = app["cmd"] cmd = app["cmd"]
if type(cmd) == str and not os.path.isfile(cmd): if type(cmd) == str and not os.path.isfile(cmd):
@ -336,6 +324,9 @@ for app in config.Apps:
runner = AppRunner() runner = AppRunner()
runner.start() runner.start()
########################################################################
# Web Api #
########################################################################
@bottle.route('/<:re:.*>', method='OPTIONS') @bottle.route('/<:re:.*>', method='OPTIONS')
def enable_cors_generic_route(): def enable_cors_generic_route():
add_cors_headers() add_cors_headers()
@ -351,6 +342,12 @@ def add_cors_headers():
bottle.response.headers['Access-Control-Allow-Headers'] = \ bottle.response.headers['Access-Control-Allow-Headers'] = \
'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token' 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'
def getAppIdx(name):
for i in range(len(config.Apps)):
if config.Apps[i]["name"] == name:
return i
return -1
@route("/apps/list") @route("/apps/list")
def apps_list(): def apps_list():
s = [] s = []
@ -364,29 +361,30 @@ def apps_list():
@route("/apps/start/<name>") @route("/apps/start/<name>")
def apps_start_param(name): def apps_start_param(name):
for i in range(len(config.Apps)): i = getAppIdx(name)
if config.Apps[i]["name"] == name: if i >= 0:
runner.requestApp(i) runner.requestApp(i)
return "ok" return "ok"
else:
return "not_found" return "not_found"
@post("/apps/start/<name>") @post("/apps/start/<name>")
def apps_start_post(name): def apps_start_post(name):
param = request.forms.get('param') param = request.forms.get('param')
for i in range(len(config.Apps)): i = getAppIdx(name)
if config.Apps[i]["name"] == name: if i >= 0:
runner.requestApp(i, param) runner.requestApp(i, param)
return "ok" return "ok"
else:
return "not_found" return "not_found"
@route("/apps/start/<name>/<param>") @route("/apps/start/<name>/<param>")
def apps_start(name, param): def apps_start(name, param):
for i in range(len(config.Apps)): i = getAppIdx(name)
if i >= 0:
if config.Apps[i]["name"] == name:
runner.requestApp(i, param) runner.requestApp(i, param)
return "ok" return "ok"
else:
return "not_found" return "not_found"
@route("/apps/log") @route("/apps/log")
@ -401,7 +399,7 @@ def apps_running():
@route("/") @route("/")
def index(): def index():
return bottle.static_file("index.html", root='html') return bottle.static_file("index.html", root='html')
#return open("html/index.html").read()
@route("/setgamma/<r>/<g>/<b>") @route("/setgamma/<r>/<g>/<b>")
def setGamma(r, g, b): def setGamma(r, g, b):
r = float(r) r = float(r)
@ -410,6 +408,9 @@ def setGamma(r, g, b):
runner.setGamma(r, g, b) runner.setGamma(r, g, b)
return "ok" return "ok"
########################################################################
# Shutdown #
########################################################################
run(host=config.WebHost, port=config.WebPort) run(host=config.WebHost, port=config.WebPort)
running = False running = False
runner.join() runner.join()