Skip to content

Commit

Permalink
bglib: convert uncaught exceptions to events
Browse files Browse the repository at this point in the history
This does not solve the underlying problem of an unhandled exception in
the connection handler thread, but means that the outer app layer
actually receives an event, giving them a chance of taking action.

We only have a single string field, but the traceback is still
important, so include it anyway, as a string, it's better than nothing.

Signed-off-by: Karl Palsson <karlp@etactica.com>
  • Loading branch information
karlp committed Feb 1, 2023
1 parent bdd4a9a commit 4712def
Showing 1 changed file with 11 additions and 0 deletions.
11 changes: 11 additions & 0 deletions bgapi/bglib.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

from array import array
import threading
import traceback
try:
import queue
except ImportError:
Expand Down Expand Up @@ -76,6 +77,8 @@ def __init__(self, connection, event_handler, *apis):
threading.Thread.__init__(self)
self.daemon = True # Daemon thread
self.stop_flag = threading.Event()
threading.excepthook = self._handle_thread_exceptions
self._apis, = apis

self.conn = connection
self.event_handler = event_handler
Expand All @@ -86,6 +89,14 @@ def __init__(self, connection, event_handler, *apis):
self.response_queue = queue.Queue(maxsize=1)
self.waiting_response = threading.Event()

def _handle_thread_exceptions(self, ee):
# This is called on the thread that excepted
# It's just nicer than wrapping everything in a try: block
# Create a synthetic event for the outer world to discover that the thread has gone.
# We can't keep the traceback, as system.error only has definitions for code+string
val = f"{ee.exc_type}:{ee.exc_value} {traceback.format_tb(ee.exc_traceback)}"
self.event_handler(BGEvent(self._apis["system"].events["error"], (99, val)))

def send_command(self, bgcmd, response_timeout):
try:
# Send command
Expand Down

0 comments on commit 4712def

Please sign in to comment.