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.
This commit is contained in:
June Tate-Gans 2021-05-09 12:26:51 -05:00
parent 4eb039bc27
commit c934abb28b
2 changed files with 40 additions and 12 deletions

View File

@ -46,7 +46,13 @@ class AppletManager(dbus.service.Object, Subject):
@activeApplet.setter @activeApplet.setter
def activeApplet(self, appletName): def activeApplet(self, appletName):
(name, appletProxy) = self._applets[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.setProperty('activeApplet', appletProxy)
self.onPresent() self.onPresent()
@ -61,10 +67,24 @@ class AppletManager(dbus.service.Object, Subject):
def _updateLCD(self, frame): def _updateLCD(self, frame):
self._manager.setLCDBuffer(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): def onPresent(self):
frame = self._activeApplet.Present(time.time(), byte_arrays=True) try:
frame = bytes(frame) frame = self._activeApplet.Present(time.time(), byte_arrays=True)
self._updateLCD(frame) 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): def onKeyPressed(self, key):
# Swap to the switcher # Swap to the switcher
@ -72,12 +92,22 @@ class AppletManager(dbus.service.Object, Subject):
self.activeApplet = 'Switcher' self.activeApplet = 'Switcher'
return return
frame = self._activeApplet.KeyPressed(time.time(), key.value['bit']) try:
self._updateLCD(frame) 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): def onKeyReleased(self, key):
frame = self._activeApplet.KeyReleased(time.time(), key.value['bit']) try:
self._updateLCD(frame) 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): def _registerApplet(self, name, sender):
proxy = self._bus.get_object(sender, '/com/theonelab/g13/Applet') proxy = self._bus.get_object(sender, '/com/theonelab/g13/Applet')

View File

@ -27,9 +27,7 @@ class Switcher(Observer):
self._applets = [] self._applets = []
self._appletManager.registerObserver(self, {'activeApplet', 'applet'}) self._appletManager.registerObserver(self, {'activeApplet', 'applet'})
self.changeTrigger(self.onNewApplet, self.changeTrigger(self.onAppletChange, keys={'applet'})
changeType=ChangeType.ADD,
keys={'applet'})
self._initWidgets() self._initWidgets()
@ -37,7 +35,7 @@ class Switcher(Observer):
def bus_name(self): def bus_name(self):
return self return self
def onNewApplet(self, subject, changeType, key, data): def onAppletChange(self, subject, changeType, key, data):
self._applets = sorted(self._appletManager.appletNames) self._applets = sorted(self._appletManager.appletNames)
self._lv.model = self._applets self._lv.model = self._applets
self._lv.update() self._lv.update()