Skip to content

Commit 4328cd9

Browse files
authored
Merge pull request #63 from ImDevinC/fix-socket-read
fix(sockets): improve socket connection reliability and callback cleanup
2 parents 7d5255f + c4dd1e8 commit 4328cd9

5 files changed

Lines changed: 51 additions & 24 deletions

File tree

actions/DiscordCore.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,13 @@ def register_backend_callback(self, key: str, callback: callable):
4747
"""Register a callback and track it for cleanup."""
4848
self.backend.register_callback(key, callback)
4949
self._registered_callbacks.append((key, callback))
50+
self.plugin_base.add_callback(key, callback)
5051

5152
def cleanup_callbacks(self):
5253
"""Unregister all tracked callbacks to prevent memory leaks."""
5354
for key, callback in self._registered_callbacks:
5455
self.backend.unregister_callback(key, callback)
56+
self.plugin_base.remove_callback(key, callback)
5557
self._registered_callbacks.clear()
5658

5759
def __del__(self):

discordrpc/asyncdiscord.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import requests
66
from loguru import logger as log
77

8-
from .sockets import UnixPipe
8+
from .sockets import UnixPipe, SOCKET_BAD_BUFFER_SIZE, SOCKET_DISCONNECTED
99
from .commands import *
1010
from .exceptions import *
1111
from .constants import MAX_SOCKET_RETRY_ATTEMPTS
@@ -39,15 +39,27 @@ def is_connected(self):
3939
def connect(self, callback: callable):
4040
tries = 0
4141
while tries < MAX_SOCKET_RETRY_ATTEMPTS:
42-
log.debug(
43-
f"Attempting to connect to socket, attempt {tries + 1}/{MAX_SOCKET_RETRY_ATTEMPTS}"
44-
)
45-
self.rpc.connect()
46-
self.rpc.send({"v": 1, "client_id": self.client_id}, OP_HANDSHAKE)
47-
_, resp = self.rpc.receive()
48-
if resp:
42+
try:
43+
log.debug(
44+
f"Attempting to connect to socket, attempt {tries + 1}/{MAX_SOCKET_RETRY_ATTEMPTS}"
45+
)
46+
self.rpc.connect()
4947
break
50-
tries += 1
48+
except Exception as ex:
49+
log.error(f"failed to connect to socket. {ex}")
50+
tries += 1
51+
52+
self.rpc.send({"v": "1", "client_id": self.client_id}, OP_HANDSHAKE)
53+
code, resp = self.rpc.receive()
54+
55+
if not resp:
56+
log.error("no response from discord client")
57+
raise RPCException
58+
59+
if code == SOCKET_BAD_BUFFER_SIZE:
60+
log.error("bad buffer size when receiving data from socket")
61+
raise RPCException
62+
5163
try:
5264
data = json.loads(resp)
5365
except Exception as ex:
@@ -74,7 +86,9 @@ def poll_callback(self, callback: callable):
7486
log.error(f"error receiving data from socket. {ex}")
7587
self.disconnect()
7688
return
77-
if val[0] == -1:
89+
if val[0] == SOCKET_BAD_BUFFER_SIZE:
90+
log.debug("bad buffer size when receiving data from socket")
91+
if val[0] == SOCKET_DISCONNECTED:
7892
self.disconnect()
7993
callback(val[0], val[1])
8094

discordrpc/sockets.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,19 @@
1111
from .constants import MAX_IPC_SOCKET_RANGE, SOCKET_SELECT_TIMEOUT, SOCKET_BUFFER_SIZE
1212

1313
SOCKET_DISCONNECTED: int = -1
14-
14+
SOCKET_BAD_BUFFER_SIZE: int = -2
15+
SOCKET_SEND_TIMEOUT: int = 5
16+
SOCKET_CONNECT_TIMEOUT: int = 2
17+
SOCKET_RECEIVE_TIMEOUT: int = 5
1518

1619
class UnixPipe:
1720
def __init__(self):
1821
self.socket: socket.socket = None
1922

2023
def connect(self):
2124
if self.socket is None:
22-
self.socket = socket.socket(socket.AF_UNIX)
23-
self.socket.setblocking(False)
25+
self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
26+
self.socket.settimeout(SOCKET_CONNECT_TIMEOUT)
2427
base_path = path = (
2528
os.environ.get("XDG_RUNTIME_DIR")
2629
or os.environ.get("TMPDIR")
@@ -44,6 +47,7 @@ def connect(self):
4447
pass
4548
else:
4649
raise DiscordNotOpened
50+
self.socket.setblocking(False)
4751

4852
def disconnect(self):
4953
if self.socket is None:
@@ -60,17 +64,15 @@ def disconnect(self):
6064
self.socket = None # Reset so connect() creates a fresh socket
6165

6266
def send(self, payload, op):
63-
payload = json.dumps(payload).encode("UTF-8")
64-
payload = struct.pack("<ii", op, len(payload)) + payload
65-
size = 0
66-
while size == 0 or size < len(payload):
67-
res = self.socket.send(payload[size:])
68-
size += res
67+
log.debug(f"Sending payload: {payload} with op: {op}")
68+
payload_bytes = json.dumps(payload).encode("UTF-8")
69+
header = struct.pack("<ii", op, len(payload_bytes))
70+
message = header + payload_bytes
71+
self.socket.settimeout(SOCKET_SEND_TIMEOUT)
72+
self.socket.sendall(message)
6973

7074
def receive(self) -> (int, str):
71-
ready = select.select([self.socket], [], [], SOCKET_SELECT_TIMEOUT)
72-
if not ready[0]:
73-
return 0, {}
75+
self.socket.settimeout(SOCKET_RECEIVE_TIMEOUT)
7476
data = self.socket.recv(SOCKET_BUFFER_SIZE)
7577
if len(data) == 0:
7678
return SOCKET_DISCONNECTED, {}
@@ -80,7 +82,7 @@ def receive(self) -> (int, str):
8082
all_data = data[8:]
8183
buffer_size = length - len(all_data)
8284
if buffer_size < 0:
83-
return 0, {}
85+
return SOCKET_BAD_BUFFER_SIZE, {}
8486
data = self.socket.recv(length - len(all_data))
8587
all_data += data
8688
return code, all_data.decode("UTF-8")

main.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,12 @@ def on_auth_callback(self, success: bool, message: str = None):
190190

191191
def get_settings_area(self):
192192
return self._settings_manager.get_settings_area()
193+
194+
def clear_callbacks(self, key: str, callback: callable):
195+
callbacks = self.callbacks.get(key, [])
196+
if callback in callbacks:
197+
callbacks.remove(callback)
198+
if callbacks:
199+
self.callbacks[key] = callbacks
200+
else:
201+
del self.callbacks[key]

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "1.9.0",
2+
"version": "1.9.1",
33
"thumbnail": "store/thumbnail.png",
44
"id": "com_imdevinc_StreamControllerDiscordPlugin",
55
"name": "Discord - Debug",

0 commit comments

Comments
 (0)