Skip to content

Commit 043683f

Browse files
committed
Fix accidental restoration of initial presence
1 parent 530e72e commit 043683f

File tree

2 files changed

+62
-20
lines changed

2 files changed

+62
-20
lines changed

discord/client.py

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -449,15 +449,24 @@ def _handle_ready(self) -> None:
449449
self._ready.set()
450450

451451
def _handle_connect(self) -> None:
452-
state = self._connection
452+
if self.ws._has_sent_presence:
453+
_log.debug('Skipping initial presence as one has already been sent.')
454+
return
455+
453456
activities = self.initial_activities
454457
status = self.initial_status
455-
if status or activities:
458+
afk = self.initial_afk
459+
since = self.initial_idle_since
460+
if status or activities or afk or since:
456461
if status is None:
457-
status = getattr(state.settings, 'status', None) or Status.unknown
458-
_log.debug('Setting initial presence to %s %s', status, activities)
462+
status = getattr(self._connection.settings, 'status', None) or Status.unknown
463+
_log.debug(
464+
'Setting initial presence to (status=%s, activities=%s, afk=%s, since=%s)', status, activities, afk, since
465+
)
459466
self.loop.create_task(
460-
self.change_presence(activities=activities, status=status, edit_settings=self._sync_presences)
467+
self.change_presence(
468+
activities=activities, status=status, afk=afk, idle_since=since, edit_settings=self._sync_presences
469+
)
461470
)
462471

463472
@property
@@ -1024,7 +1033,7 @@ async def connect(self, *, reconnect: bool = True) -> None:
10241033
except ReconnectWebSocket as e:
10251034
_log.debug('Got a request to %s the websocket.', e.op)
10261035
self.dispatch('disconnect')
1027-
ws_params.update(sequence=self.ws.sequence, resume=e.resume, session=self.ws.session_id)
1036+
ws_params.update(sequence=self.ws.sequence, resume=e.resume, session=self.ws.session_id, old_ws=self.ws)
10281037
if e.resume:
10291038
ws_params['gateway'] = self.ws.gateway
10301039
continue
@@ -1056,6 +1065,7 @@ async def connect(self, *, reconnect: bool = True) -> None:
10561065
initial=False,
10571066
resume=True,
10581067
session=self.ws.session_id,
1068+
old_ws=self.ws,
10591069
)
10601070
continue
10611071

@@ -1079,6 +1089,7 @@ async def connect(self, *, reconnect: bool = True) -> None:
10791089
gateway=self.ws.gateway,
10801090
resume=True,
10811091
session=self.ws.session_id,
1092+
old_ws=self.ws,
10821093
)
10831094

10841095
async def close(self) -> None:
@@ -1305,6 +1316,34 @@ def initial_status(self, value: Status):
13051316
else:
13061317
raise TypeError('status must derive from Status')
13071318

1319+
@property
1320+
def initial_afk(self) -> bool:
1321+
""":class:`bool`: Whether the client is set to AFK upon logging in.
1322+
1323+
.. versionadded:: 2.2
1324+
"""
1325+
return self._connection._afk
1326+
1327+
@initial_afk.setter
1328+
def initial_afk(self, value: bool):
1329+
self._connection._afk = bool(value)
1330+
1331+
@property
1332+
def initial_idle_since(self) -> Optional[datetime]:
1333+
"""Optional[:class:`datetime.datetime`]: When the client is set to go idle upon logging in.
1334+
1335+
.. versionadded:: 2.2
1336+
"""
1337+
idle_since = self._connection._idle_since
1338+
if idle_since is not None:
1339+
return utils.parse_timestamp(idle_since)
1340+
1341+
@initial_idle_since.setter
1342+
def initial_idle_since(self, value: Optional[datetime]):
1343+
if value is not None and not isinstance(value, datetime):
1344+
raise TypeError('idle_since must be a datetime.datetime or None')
1345+
self._connection._idle_since = int(value.timestamp() * 1000) if value else 0
1346+
13081347
@property
13091348
def status(self) -> Status:
13101349
""":class:`.Status`: The user's overall status.
@@ -1835,7 +1874,7 @@ async def change_presence(
18351874
18361875
.. code-block:: python3
18371876
1838-
game = discord.Game("with the API")
1877+
game = discord.Activity(name="with the API")
18391878
await client.change_presence(status=discord.Status.idle, activity=game)
18401879
18411880
Parameters

discord/gateway.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ def __init__(self, socket: AsyncWebSocket, *, loop: asyncio.AbstractEventLoop) -
334334
self.activities: List[ActivityPayload] = []
335335
self.afk: bool = False
336336
self.idle_since: int = 0
337+
self._has_sent_presence: bool = False
337338

338339
@property
339340
def open(self) -> bool:
@@ -364,6 +365,7 @@ async def from_client(
364365
resume: bool = False,
365366
encoding: str = 'json',
366367
compress: bool = True,
368+
old_ws: Optional[Self] = None,
367369
) -> Self:
368370
"""Creates a main websocket for Discord from a :class:`Client`.
369371
@@ -400,6 +402,15 @@ async def from_client(
400402
ws.afk = client._connection._afk
401403
ws.idle_since = client._connection._idle_since
402404

405+
if old_ws is not None:
406+
# Copy over the presence state from the old websocket
407+
ws.status = old_ws.status
408+
ws.activities = old_ws.activities
409+
ws.afk = old_ws.afk
410+
ws.idle_since = old_ws.idle_since
411+
# Avoids resetting to initial presence on reconnect
412+
ws._has_sent_presence = old_ws._has_sent_presence
413+
403414
if client._enable_debug_events:
404415
ws.send = ws.debug_send
405416
ws.log_receive = ws.debug_log_receive
@@ -452,22 +463,13 @@ async def identify(self) -> None:
452463
# This payload is only sometimes respected; usually the gateway tells
453464
# us our presence through the READY packet's sessions key
454465
# However, when reidentifying, we should send our last known presence
455-
# initial_status and initial_activities could probably also be sent here
456-
# but that needs more testing...
466+
# This is what the client does to ensure RPC is persisted across reconnects
457467
presence = {
458-
'status': 'unknown',
459-
'since': self.idle_since,
460-
'activities': [],
468+
'status': self.status,
469+
'activities': self.activities,
461470
'afk': self.afk,
471+
'since': self.idle_since,
462472
}
463-
existing = self._connection.current_session
464-
if existing is not None:
465-
presence['status'] = str(existing.status) if existing.status is not Status.offline else 'invisible'
466-
presence['activities'] = [a.to_dict() for a in existing.activities]
467-
# else:
468-
# presence['status'] = self._connection._status or 'unknown'
469-
# presence['activities'] = self._connection._activities
470-
471473
properties = self._headers.gateway_properties
472474

473475
payload = {
@@ -744,6 +746,7 @@ async def change_presence(
744746
self.activities = list(activities or [])
745747
self.afk = afk
746748
self.idle_since = since
749+
self._has_sent_presence = True
747750

748751
async def guild_subscribe(
749752
self,

0 commit comments

Comments
 (0)