Extracted App class from runner
This commit is contained in:
parent
3247d97b0d
commit
01f4671fdf
214
main.py
214
main.py
@ -14,18 +14,30 @@ logging.basicConfig(filename='pixelserver.log',level=config.LogLevel)
|
|||||||
|
|
||||||
running = True
|
running = True
|
||||||
|
|
||||||
|
|
||||||
|
class DataSource:
|
||||||
|
def __init__(self, initial):
|
||||||
|
self.data = initial
|
||||||
|
self.listeners = []
|
||||||
|
def getData(self):
|
||||||
|
return self.data
|
||||||
|
def addListener(self, listener):
|
||||||
|
self.listeners.append(listener)
|
||||||
|
def pushData(self, data):
|
||||||
|
self.data = data
|
||||||
|
for listener in self.listeners:
|
||||||
|
with listener:
|
||||||
|
listener.notify_all()
|
||||||
|
|
||||||
if config.UseGui:
|
if config.UseGui:
|
||||||
import pygame
|
import pygame
|
||||||
|
|
||||||
class Gui(threading.Thread):
|
class Gui(threading.Thread):
|
||||||
def __init__(self):
|
def __init__(self, datasource):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.data = b"\x00"*config.ScreenX*config.ScreenY*3
|
self.datasource = datasource
|
||||||
self.lock = threading.Lock()
|
self.cv = threading.Condition()
|
||||||
|
self.datasource.addListener(self.cv)
|
||||||
def setData(self, data):
|
|
||||||
with self.lock:
|
|
||||||
self.data = data
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
global running
|
global running
|
||||||
@ -35,35 +47,36 @@ if config.UseGui:
|
|||||||
pygame.display.set_caption("Pixelserver - GUI Vis")
|
pygame.display.set_caption("Pixelserver - GUI Vis")
|
||||||
while running:
|
while running:
|
||||||
for event in pygame.event.get():
|
for event in pygame.event.get():
|
||||||
if event.type == pygame.QUIT:
|
pass
|
||||||
logging.debug("GUI quits app")
|
with self.cv:
|
||||||
running = False
|
self.cv.wait()
|
||||||
|
data = self.datasource.getData()
|
||||||
screen.fill((0, 255, 0))
|
screen.fill((0, 255, 0))
|
||||||
with self.lock:
|
|
||||||
try:
|
try:
|
||||||
for x in range(config.ScreenX):
|
for x in range(config.ScreenX):
|
||||||
for y in range(config.ScreenY):
|
for y in range(config.ScreenY):
|
||||||
i = x+y*config.ScreenX
|
i = x+y*config.ScreenX
|
||||||
r = (self.data[i*3+0])
|
r = (data[i*3+0])
|
||||||
g = (self.data[i*3+1])
|
g = (data[i*3+1])
|
||||||
b = (self.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
|
pass
|
||||||
time.sleep(1/30)
|
raise
|
||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
logging.info("Closing GUI")
|
logging.info("Closing GUI")
|
||||||
|
def join(self):
|
||||||
|
with self.cv:
|
||||||
|
self.cv.notify_all()
|
||||||
|
super().join()
|
||||||
|
|
||||||
class SerialWriter(threading.Thread):
|
class SerialWriter(threading.Thread):
|
||||||
def __init__(self):
|
def __init__(self, datasource):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.lock = threading.Lock()
|
self.cv = threading.Condition()
|
||||||
self.data = b"\x00"*config.ScreenX*config.ScreenY*3
|
self.datasource = datasource
|
||||||
|
self.datasource.addListener(self.cv)
|
||||||
def setData(self, data):
|
|
||||||
with self.lock:
|
|
||||||
self.data = data
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
should_connect = True
|
should_connect = True
|
||||||
@ -75,49 +88,120 @@ class SerialWriter(threading.Thread):
|
|||||||
ser = serial.Serial(config.Serial)
|
ser = serial.Serial(config.Serial)
|
||||||
should_connect = False
|
should_connect = False
|
||||||
logging.info("Serial Opened")
|
logging.info("Serial Opened")
|
||||||
with self.lock:
|
with self.cv:
|
||||||
|
self.cv.wait(timeout = 1/30)
|
||||||
|
data = self.datasource.getData()
|
||||||
ser.write(b"\01")
|
ser.write(b"\01")
|
||||||
ser.write(self.data)
|
ser.write(data)
|
||||||
time.sleep(1/120)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if ser != None:
|
if ser != None:
|
||||||
ser.close()
|
ser.close()
|
||||||
ser = None
|
ser = None
|
||||||
logging.warning("Serial was close because: "+str(e))
|
logging.warning("Serial was close because: "+str(e))
|
||||||
should_connect = True
|
should_connect = True
|
||||||
time.sleep(0.1)
|
time.sleep(5)
|
||||||
logging.info("Closing SerialWriter")
|
logging.info("Closing SerialWriter")
|
||||||
|
def joint(self):
|
||||||
|
self.cv.notify_all()
|
||||||
|
super().join()
|
||||||
|
|
||||||
class WatchDog(threading.Thread):
|
class WatchDog(threading.Thread):
|
||||||
def __init__(self, check, action):
|
def __init__(self, check, action):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.check = check
|
self.check = check
|
||||||
self.action = action
|
self.action = action
|
||||||
|
self.running = True
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
while running:
|
while running and self.running:
|
||||||
if self.check():
|
if self.check():
|
||||||
logging.error("Watchdog: Executed")
|
logging.error("Watchdog: Executed")
|
||||||
self.action()
|
self.action()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
def stop(self):
|
||||||
|
self.running = False
|
||||||
|
|
||||||
class LogReader(threading.Thread):
|
class LogReader(threading.Thread):
|
||||||
def __init__(self, runner):
|
def __init__(self, runner):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.runner = runner
|
self.runner = runner
|
||||||
self.log = ""
|
self.log = ""
|
||||||
|
self.running = True
|
||||||
def clear(self):
|
def clear(self):
|
||||||
self.log = ""
|
self.log = ""
|
||||||
|
|
||||||
|
def getLog(self):
|
||||||
|
return self.log
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
logging.info("LogReader started")
|
logging.info("LogReader started")
|
||||||
while running:
|
while running and self.running:
|
||||||
try:
|
try:
|
||||||
self.log += runner.app.stderr.read(1).decode("utf-8")
|
self.log += runner.app.stderr.read(1).decode("utf-8")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
time.sleep(0.1)
|
time.sleep(1)
|
||||||
logging.info("LogReader closed")
|
logging.info("LogReader closed")
|
||||||
|
def stop(self):
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
class App(threading.Thread):
|
||||||
|
def __init__(self, cmd, param, listener):
|
||||||
|
super().__init__()
|
||||||
|
#start app
|
||||||
|
if type(cmd) != list:
|
||||||
|
cmd = [cmd,]
|
||||||
|
args = cmd+[str(config.ScreenX), str(config.ScreenY), param]
|
||||||
|
self.app = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
|
||||||
|
self.last_update = time.time()
|
||||||
|
self.cv = threading.Condition()
|
||||||
|
self.watchdog = WatchDog(lambda: self.isAppTimedOut(), lambda: self.terminateApp())
|
||||||
|
self.watchdog.start()
|
||||||
|
self.logreader = LogReader(self)
|
||||||
|
self.logreader.start()
|
||||||
|
self.datasource = DataSource(b"\x00"*config.ScreenX*config.ScreenY*3)
|
||||||
|
self.running = running
|
||||||
|
self.listener = listener
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while running and self.running and self.alive():
|
||||||
|
oshandle = self.app.stdout.fileno()
|
||||||
|
try:
|
||||||
|
data = os.read(oshandle, config.ScreenX*config.ScreenY*3)
|
||||||
|
assert len(data) == config.ScreenX*config.ScreenY*3
|
||||||
|
self.last_update = time.time()
|
||||||
|
self.datasource.pushData(data)
|
||||||
|
except Exception as e:
|
||||||
|
logging.debug("Exception in App.run")
|
||||||
|
|
||||||
|
with self.listener:
|
||||||
|
self.listener.notify_all()
|
||||||
|
self.watchdog.stop()
|
||||||
|
self.logreader.stop()
|
||||||
|
self.watchdog.join()
|
||||||
|
self.logreader.join()
|
||||||
|
|
||||||
|
|
||||||
|
def alive(self):
|
||||||
|
return self.app.poll() == None
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.running = False
|
||||||
|
self.app.kill()
|
||||||
|
self.app.stdout.close()
|
||||||
|
self.app.stderr.close()
|
||||||
|
self.watchdog.stop()
|
||||||
|
self.logreader.stop()
|
||||||
|
|
||||||
|
def getLog(self):
|
||||||
|
return self.logreader.getLog()
|
||||||
|
|
||||||
|
def terminateApp(self):
|
||||||
|
logging.error("Terminate app!")
|
||||||
|
self.stop()
|
||||||
|
|
||||||
|
|
||||||
|
def isAppTimedOut(self):
|
||||||
|
return time.time()-self.last_update > config.NoDataTimeout
|
||||||
|
|
||||||
class AppRunner(threading.Thread):
|
class AppRunner(threading.Thread):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -125,80 +209,58 @@ class AppRunner(threading.Thread):
|
|||||||
self.currentApp = -1
|
self.currentApp = -1
|
||||||
self.requestedApp = 0
|
self.requestedApp = 0
|
||||||
self.app = None
|
self.app = None
|
||||||
self.lock = threading.Lock()
|
self.cv = threading.Condition()
|
||||||
self.param = ""
|
self.param = ""
|
||||||
self.serial = SerialWriter()
|
self.datasource = DataSource(b"\x00"*config.ScreenX*config.ScreenY*3)
|
||||||
|
self.serial = SerialWriter(self.datasource)
|
||||||
self.serial.start()
|
self.serial.start()
|
||||||
self.last_update = time.time()
|
|
||||||
self.watchdog = WatchDog(lambda: self.appTimedOut(), lambda: self.terminateApp())
|
|
||||||
self.watchdog.start()
|
|
||||||
self.logreader = LogReader(self)
|
|
||||||
self.logreader.start()
|
|
||||||
if config.UseGui:
|
if config.UseGui:
|
||||||
self.gui = Gui()
|
self.gui = Gui(self.datasource)
|
||||||
self.gui.start()
|
self.gui.start()
|
||||||
|
|
||||||
def requestApp(self, app, param=""):
|
def requestApp(self, app, param=""):
|
||||||
with self.lock:
|
with self.cv:
|
||||||
self.requestedApp = app
|
self.requestedApp = app
|
||||||
self.param = param
|
self.param = param
|
||||||
|
self.cv.notify_all()
|
||||||
def terminateApp(self):
|
logging.info("Requesting app: "+str(app))
|
||||||
if self.app != None:
|
|
||||||
logging.error("Terminate app "+config.Apps[self.currentApp]["name"])
|
|
||||||
# don't ask
|
|
||||||
self.app.terminate()
|
|
||||||
if self.app != None:
|
|
||||||
self.app.kill()
|
|
||||||
self.app.stdout.close()
|
|
||||||
self.app.stderr.close()
|
|
||||||
self.last_update = time.time()
|
|
||||||
self.requestedApp = 0
|
|
||||||
|
|
||||||
def appTimedOut(self):
|
|
||||||
return time.time()-self.last_update > config.NoDataTimeout
|
|
||||||
|
|
||||||
def updateApp(self):
|
def updateApp(self):
|
||||||
if self.app != None:
|
if self.app != None:
|
||||||
self.app.terminate()
|
self.app.stop()
|
||||||
self.app.stderr.close()
|
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))
|
||||||
if type(cmd) != list:
|
self.app = App(cmd, self.param, self.cv)
|
||||||
cmd = [cmd,]
|
self.app.datasource.addListener(self.cv)
|
||||||
args = cmd+[str(config.ScreenX), str(config.ScreenY), self.param]
|
self.app.start()
|
||||||
self.app = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
|
|
||||||
self.logreader.clear()
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
logging.info("Starting Apprunner")
|
logging.info("Starting Apprunner")
|
||||||
while running:
|
while running:
|
||||||
with self.lock:
|
with self.cv:
|
||||||
if self.app == None or self.app.poll() != None:
|
if self.app == None or not self.app.alive():
|
||||||
self.requestedApp = 0
|
self.requestedApp = 0
|
||||||
if self.requestedApp != None:
|
if self.requestedApp != None:
|
||||||
self.currentApp = self.requestedApp
|
self.currentApp = self.requestedApp
|
||||||
self.updateApp()
|
self.updateApp()
|
||||||
self.requestedApp = None
|
self.requestedApp = None
|
||||||
d = self.app.stdout
|
|
||||||
oshandle = d.fileno()
|
self.cv.wait()
|
||||||
try:
|
if self.app != None:
|
||||||
data = os.read(oshandle, config.ScreenX*config.ScreenY*3)
|
data = self.app.datasource.getData()
|
||||||
self.last_update = time.time()
|
self.datasource.pushData(data)
|
||||||
self.serial.setData(data)
|
|
||||||
if config.UseGui:
|
|
||||||
self.gui.setData(data)
|
|
||||||
except:
|
|
||||||
logging.debug("Exception in Apprunner.run")
|
|
||||||
self.watchdog.join()
|
|
||||||
self.serial.join()
|
self.serial.join()
|
||||||
self.logreader.join()
|
|
||||||
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):
|
||||||
return self.logreader.log
|
if self.app == None:
|
||||||
|
return ""
|
||||||
|
return self.app.getLog()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
runner = AppRunner()
|
runner = AppRunner()
|
||||||
runner.start()
|
runner.start()
|
||||||
|
Loading…
Reference in New Issue
Block a user