From c934abb28bb71daaa358e8ed7b17ddb19bb370ee Mon Sep 17 00:00:00 2001 From: June Tate-Gans Date: Sun, 9 May 2021 12:26:51 -0500 Subject: [PATCH] applet: Make the AppletManager more resilient in the face of errors This wraps most of the proxy calls with some exception handling code which removes an applet from the list of applets. This is kinda remedial, but should make developing applets a bit smoother, as we end up restarting them periodically. IOW, this prevents the configurator from completely crashing out. - Give switcher the ability to handle applet removals - Wrap most proxy methods in try...except blocks - Add a removeActiveApplet method to kill off the currently stuck applet in the face of an error. --- g13gui/applet/manager.py | 46 ++++++++++++++++++++++++++++++++------- g13gui/applet/switcher.py | 6 ++--- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/g13gui/applet/manager.py b/g13gui/applet/manager.py index 75eec1a..a868d0a 100644 --- a/g13gui/applet/manager.py +++ b/g13gui/applet/manager.py @@ -46,7 +46,13 @@ class AppletManager(dbus.service.Object, Subject): @activeApplet.setter def activeApplet(self, appletName): (name, appletProxy) = self._applets[appletName] - self._activeApplet.Unpresent() + + try: + self._activeApplet.Unpresent() + except dbus.exceptions.DBusException as err: + print('Failed to unpresent %s: %s' % (appletName, err)) + self._removeActiveApplet() + self.setProperty('activeApplet', appletProxy) self.onPresent() @@ -61,10 +67,24 @@ class AppletManager(dbus.service.Object, Subject): def _updateLCD(self, frame): self._manager.setLCDBuffer(frame) + def _removeActiveApplet(self): + senders = {proxy: name for (name, (_, proxy)) in self._applets.items()} + print('senders is %s' % (repr(senders))) + name = senders[self._activeApplet] + del self._applets[name] + + self.addChange(ChangeType.REMOVE, 'applet', name) + self._activeApplet = self._switcher + self.activeApplet = 'Switcher' + def onPresent(self): - frame = self._activeApplet.Present(time.time(), byte_arrays=True) - frame = bytes(frame) - self._updateLCD(frame) + try: + frame = self._activeApplet.Present(time.time(), byte_arrays=True) + frame = bytes(frame) + self._updateLCD(frame) + except dbus.exceptions.DBusException as err: + print('Failed to present applet: %s' % (err)) + self._removeActiveApplet() def onKeyPressed(self, key): # Swap to the switcher @@ -72,12 +92,22 @@ class AppletManager(dbus.service.Object, Subject): self.activeApplet = 'Switcher' return - frame = self._activeApplet.KeyPressed(time.time(), key.value['bit']) - self._updateLCD(frame) + try: + frame = self._activeApplet.KeyPressed(time.time(), + key.value['bit']) + self._updateLCD(frame) + except dbus.exceptions.DBusException as err: + print('Failed to send keyPressed for applet: %s' % (err)) + self._removeActiveApplet() def onKeyReleased(self, key): - frame = self._activeApplet.KeyReleased(time.time(), key.value['bit']) - self._updateLCD(frame) + try: + frame = self._activeApplet.KeyReleased(time.time(), + key.value['bit']) + self._updateLCD(frame) + except dbus.exceptions.DBusException as err: + print('Failed to send keyReleased for applet: %s' % (err)) + self._removeActiveApplet() def _registerApplet(self, name, sender): proxy = self._bus.get_object(sender, '/com/theonelab/g13/Applet') diff --git a/g13gui/applet/switcher.py b/g13gui/applet/switcher.py index ec5c934..d4ce824 100644 --- a/g13gui/applet/switcher.py +++ b/g13gui/applet/switcher.py @@ -27,9 +27,7 @@ class Switcher(Observer): self._applets = [] self._appletManager.registerObserver(self, {'activeApplet', 'applet'}) - self.changeTrigger(self.onNewApplet, - changeType=ChangeType.ADD, - keys={'applet'}) + self.changeTrigger(self.onAppletChange, keys={'applet'}) self._initWidgets() @@ -37,7 +35,7 @@ class Switcher(Observer): def bus_name(self): return self - def onNewApplet(self, subject, changeType, key, data): + def onAppletChange(self, subject, changeType, key, data): self._applets = sorted(self._appletManager.appletNames) self._lv.model = self._applets self._lv.update()