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
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')

View File

@ -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()