forked from viewit/KX-Bridge-Release
The bridge could get permanently stuck after a printer went offline and came back, even with the printer confirmed reachable via ping/nc - only a full container restart recovered it. Two compounding bugs: 1. Two independent code paths could trigger _reconnect() concurrently with no coordination: the reader thread (on a failed keepalive ping) and publish()/publish_web() (on a failed sendall(), which happens constantly once the socket is dead, since the poll loop calls query_info() every poll_interval). Both would race into their own _do_connect(), each opening a competing TLS handshake against a printer that likely only accepts one mTLS session at a time - so neither converges, and the failure repeats every ~3s instead of backing off. Added a lock so a second _reconnect() call waits for the first to finish instead of starting a competing handshake. 2. publish() swallows send/reconnect failures internally and returns None instead of raising - so _poll_loop's `if info: ...` branch was silently skipped on failure, but the surrounding except-block (which would have triggered the existing, correct offline/reconnect transition) was never reached, since no exception was ever thrown. The poll loop had no way to tell "printer sent nothing this tick" apart from "the MQTT session is dead". Added client.is_connected() and check it explicitly when query_info() returns falsy, routing a dead session into the same clean offline branch already used for a TCP-unreachable printer. Verified: bridge continued printing normally throughout (live print in progress on the real printer during this fix), full test suite green (111 tests), new tests cover the concurrent-reconnect lock and the poll-loop offline transition on a swallowed send failure.