`InvalidID` is raised after Discord restart
FrzMtrsprt opened this issue · 14 comments
When trying to update after Discord has restarted, a BrokenPipe
exception will raise a InvaldID
exception.
And if I catch the InvalidID
exception and try to reconnect with Presence.connect()
, RuntimeError: There is no current event loop in thread 'Thread-1 (_target)'.
is raised at loop = asyncio.get_event_loop()
, as described in #208.
Below is a script to reproduce the error:
import time
from threading import Event, Thread
from pypresence import InvalidID, Presence
client_id = 'CLIENT_ID_HERE'
presence = Presence(client_id)
presence.connect()
class RepeatedTimer:
def __init__(self, interval, function):
self.interval = interval
self.function = function
self.start = time.time()
self.event = Event()
self.thread = Thread(target=self._target)
self.thread.start()
def _target(self):
while not self.event.wait(self._time):
self.function()
@property
def _time(self):
return self.interval - ((time.time() - self.start) % self.interval)
def update():
try:
print("Updating")
presence.update(state="test") # InvalidID
except InvalidID:
print("Reconnecting")
presence.connect() # RuntimeError: There is no current event loop in thread 'Thread-1 (_target)'.
RepeatedTimer(15, update)
If Discord was restarted during the 15 seconds interval, the InvalidID
exception will be raised at the next update, and connect()
will fail to get the current event loop.
Which platform @FrzMtrsprt
Which platform @FrzMtrsprt
Windows
Try modify the script utils.py as shown here
Try modify the script utils.py as shown here
It works, and connect()
is now able to create a new event loop.
But should we use another exception for the broken pipe after Discord restart, instead of InvalidID
?
Send the full error on the console see if i can do something
Send the full error on the console see if i can do something
Exception has occurred: InvalidID
Client ID is Invalid
File "...\pypresence\baseclient.py", line 81, in read_output
preamble = await self.sock_reader.read(8)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
BrokenPipeError: [WinError 232] The pipe has been ended.
During handling of the above exception, another exception occurred:
File "...\pypresence\baseclient.py", line 85, in read_output
raise InvalidID
File "...\pypresence\presence.py", line 34, in update
return self.loop.run_until_complete(self.read_output())
File "...\main.py", line 227, in update
RPC.update(pid=pid,
File "...\main.py", line 47, in _target
self.function()
pypresence.exceptions.InvalidID: Client ID is Invalid
The best way to do this is by checking if the pipe is opened. After capturing the InvalidID
error add a function or these lines that checks if discord is running if true reconnect something like this.
import psutil
def update():
try:
print("Updating")
presence.update(state="test") # InvalidID
except InvalidID:
print("Reconnecting")
try:
presence.connect()
except BrokenPipeError:
port_range = range(6463,6473) #range of ports the rpc may use
for port in port_range:
if port in ([i.laddr.port for i in psutil.net_connections()]): #check if either one of the port is open
presence.connect() #if open we reconnect
Maybe I didn't describe the error clearly, but presence.connect()
didn't throw BrokenPipeError
, presence.update()
did.
It was thrown in the following code:
# baseclient.py
# BaseClient.read_output(self)
try:
preamble = await self.sock_reader.read(8) # BrokenPipeError was thrown here
status_code, length = struct.unpack('<II', preamble[:8])
data = await self.sock_reader.read(length)
except BrokenPipeError:
raise InvalidID
The situation now (after applying the changes from your PR) is, doing presence.update()
after a discord restart will raise an InvalidID
exception. If I catch it and do a presence.connect()
, everything will go back to normal, but I don't think that is the intended behaviour.
The intended behaviour should be, throwing a dedicated exception (for example ConnectionLost
) telling the user to reconnect, or just reconnect automatically within presence.update()
In my opinion, scanning for rpc ports should be the work of pypresence
, not the user. If pypresence is not able to decide whether it's an invalid ID or a broken connection, at least make the exception name less confusing.
Yeah the reconnecting should be done on the pypresence module, to be brief the pypresence modules is not that clean and misses some things but if the solution works that should hold on for a while
So I tested everything and the issue is caused when updating as you said, the fix is simply putting a time delay befor updating.
Atleast this worked for me
def update():
if start_presence(): #Before we send an update we check if discord is running
print("Updating")
presence.update(state="test")
def start_presence():
time.sleep(2) #add a delay here
for i in range(6463,6473): #same function as the psutil I used earlier this doesnt require extra installs
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(0.01)
conn = s.connect_ex(('localhost', i))
if (conn == 0):
return(True)
else:
return(False)
Thanks for the suggection, but I'll stick to catching the InvalidID
for the time being, because my program is quite time crucial and can't afford a 2 second sleep. Thanks for helping out anyway!
The time delay is not that important you can remove it, provided when the error occurs close the rpc then check if discord is open before reconnecting cause it may cause errors then reconnect
Try modify the script utils.py as shown here
It works, and
connect()
is now able to create a new event loop. But should we use another exception for the broken pipe after Discord restart, instead ofInvalidID
?
@FrzMtrsprt Could you please confirm if 1022b07
fixes this?
If you're deploying pypresence in an application my suggestion would be to create your own connectDiscord() function that calls .connect()
and catches DiscordNotFound, InvalidPipe, ConnectionTimeout. Whether you then want to wait an amount of time before retrying or instantly attempt to reconnect is completely up to you.
Yes, everything works fine in the lastest commit.