fix: mumble disconnect loop from stale socket and dead parent thread

Two issues causing ~2min reconnect cycles:

1. pymumble captures threading.current_thread() as parent_thread at
   init. Since we construct it in a run_in_executor thread, the parent
   dies after _connect_sync returns, triggering pymumble's loop exit.
   Fix: point parent_thread at threading.main_thread().

2. pymumble's init_connection() drops the control_socket reference
   without closing it. The lingering TCP connection makes Murmur kick
   the new session with "connected from another device". Fix: patch
   init_connection to close the old socket before reconnecting.
This commit is contained in:
user
2026-02-22 04:24:23 +01:00
parent 221cb1f06b
commit 165938a801
2 changed files with 30 additions and 0 deletions
+24
View File
@@ -43,3 +43,27 @@ new_opus = "lib_location = find_library('opus') or 'libopus.so.0'"
assert old_opus in src, "opuslib find_library patch target not found" assert old_opus in src, "opuslib find_library patch target not found"
p.write_text(src.replace(old_opus, new_opus)) p.write_text(src.replace(old_opus, new_opus))
print("opuslib musl patch applied") print("opuslib musl patch applied")
# -- pymumble: close old socket before reconnecting --
# init_connection() drops control_socket reference without closing it.
# The lingering TCP connection causes Murmur to kick the new session
# with "You connected to the server from another device".
p = pathlib.Path(f"{site}/pymumble_py3/mumble.py")
src = p.read_text()
old_init = """\
self.connected = PYMUMBLE_CONN_STATE_NOT_CONNECTED
self.control_socket = None"""
new_init = """\
self.connected = PYMUMBLE_CONN_STATE_NOT_CONNECTED
if getattr(self, 'control_socket', None) is not None:
try:
self.control_socket.close()
except Exception:
pass
self.control_socket = None"""
assert old_init in src, "pymumble init_connection socket patch target not found"
p.write_text(src.replace(old_init, new_init))
print("pymumble reconnect socket patch applied")
+6
View File
@@ -9,6 +9,7 @@ import logging
import os import os
import re import re
import struct import struct
import threading
import time import time
from dataclasses import dataclass, field from dataclasses import dataclass, field
from pathlib import Path from pathlib import Path
@@ -176,6 +177,11 @@ class MumbleBot:
certfile=self._certfile, keyfile=self._keyfile, certfile=self._certfile, keyfile=self._keyfile,
reconnect=True, reconnect=True,
) )
# pymumble captures threading.current_thread() as parent_thread at
# init time. Since we run in an executor thread (which is transient),
# the parent check in pymumble's loop would see a dead thread and
# disconnect. Point it at the main thread instead.
self._mumble.parent_thread = threading.main_thread()
self._mumble.callbacks.set_callback( self._mumble.callbacks.set_callback(
PYMUMBLE_CLBK_TEXTMESSAGERECEIVED, PYMUMBLE_CLBK_TEXTMESSAGERECEIVED,
self._on_text_message, self._on_text_message,