#10 transport (obdcore/transport.py): - TcpTransport.read raises IOError on a real socket error or peer-close instead of swallowing it as a timeout, so a dead WiFi link surfaces (via the #8 poll handler) as 'connection lost' rather than a frozen dashboard. - TcpTransport.reset_input_buffer drains at most 64 chunks — never spins forever. - BleTransport closes the client + stops the event-loop thread on connect timeout (no leak), caps the notification buffer at 64 KiB, and close() is robust when only partially initialised. #11 controller (gui/controller.py, obdcore/store.py): - connect() closes the transport and nulls the link if init()/connect() raises, so a failed/retried connect doesn't orphan sockets/threads. - stop_record() unhooks store.recorder BEFORE closing it, and CsvRecorder now has a 'closed' guard so a poll-thread write racing close() is a no-op instead of an I/O-on-closed-file crash. Closes #10 Closes #11 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016yT89n4zR4qbrySoSiEyZs
This commit is contained in:
@@ -128,13 +128,19 @@ class CsvRecorder:
|
||||
self._f = open(path, "w")
|
||||
self._f.write("t,key,value\n")
|
||||
self._lock = threading.Lock()
|
||||
self._closed = False
|
||||
|
||||
def write(self, key, t, v):
|
||||
with self._lock:
|
||||
if self._closed: # a poll-thread write racing close() is a no-op
|
||||
return
|
||||
self._f.write(f"{t:.3f},{key},{'' if v is None else v}\n")
|
||||
|
||||
def close(self):
|
||||
with self._lock:
|
||||
if self._closed:
|
||||
return
|
||||
self._closed = True
|
||||
self._f.close()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user