Skip to content

Commit 52d74df

Browse files
committed
Merge
1 parent caaeaad commit 52d74df

File tree

2 files changed

+36
-16
lines changed

2 files changed

+36
-16
lines changed

discord/gateway.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ class DiscordWebSocket:
267267
shard_count: Optional[int]
268268
gateway: yarl.URL
269269
_max_heartbeat_timeout: float
270-
_super_properties: Dict[str, Any]
270+
_headers: utils.Headers
271271
_transport_compression: bool
272272

273273
# fmt: off
@@ -315,6 +315,7 @@ def __init__(self, socket: WebSocket, *, loop: asyncio.AbstractEventLoop) -> Non
315315
self._hello_trace: List[str] = []
316316
self._session_trace: List[str] = []
317317
self._resume_trace: List[str] = []
318+
self._initial_identify: bool = False
318319

319320
# Presence state tracking
320321
self.afk: bool = False
@@ -380,7 +381,7 @@ async def from_client(
380381
ws.session_id = session
381382
ws.sequence = sequence
382383
ws._max_heartbeat_timeout = client._connection.heartbeat_timeout
383-
ws._super_properties = client.http.headers.super_properties
384+
ws._headers = client.http.headers
384385
ws._transport_compression = compress
385386
ws.afk = client._connection._afk
386387
ws.idle_since = client._connection._idle_since
@@ -454,31 +455,30 @@ async def identify(self) -> None:
454455
# presence['status'] = self._connection._status or 'unknown'
455456
# presence['activities'] = self._connection._activities
456457

457-
# TODO: Implement client state
458+
properties = self._headers.gateway_properties
459+
if not self._initial_identify:
460+
# As of right now, the first IDENTIFY in the client is missing
461+
# client_heartbeat_session_id because of weird codepaths
462+
properties.pop('client_heartbeat_session_id', None)
463+
458464
payload = {
459465
'op': self.IDENTIFY,
460466
'd': {
461467
'token': self.token,
462468
'capabilities': self.capabilities.value,
463-
'properties': self._super_properties,
469+
'properties': properties,
464470
'presence': presence,
465471
'compress': not self._transport_compression, # We require at least one form of compression
466472
'client_state': {
467-
'api_code_version': 0,
468473
'guild_versions': {},
469-
# 'highest_last_message_id': '0',
470-
# 'initial_guild_id': None,
471-
# 'private_channels_version': '0',
472-
# 'read_state_version': 0,
473-
# 'user_guild_settings_version': -1,
474-
# 'user_settings_version': -1,
475474
},
476475
},
477476
}
478477

479478
await self.call_hooks('before_identify', initial=self._initial_identify)
480479
await self.send_as_json(payload)
481480
_log.debug('Gateway has sent the IDENTIFY payload.')
481+
self._initial_identify = True
482482

483483
async def resume(self) -> None:
484484
"""Sends the RESUME packet."""

discord/utils.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
import struct
8080
import time
8181
import yarl
82+
import uuid
8283

8384
try:
8485
import orjson # type: ignore
@@ -1740,27 +1741,30 @@ class Headers:
17401741
"""
17411742

17421743
FALLBACK_BUILD_NUMBER = 9999
1743-
FALLBACK_BROWSER_VERSION = 135
1744+
FALLBACK_BROWSER_VERSION = 136
17441745

17451746
def __init__(
17461747
self,
1748+
*,
17471749
platform: Literal['Windows', 'macOS', 'Linux', 'Android', 'iOS'],
17481750
major_version: int,
17491751
super_properties: Dict[str, Any],
17501752
encoded_super_properties: str,
1753+
extra_gateway_properties: Optional[Dict[str, Any]] = None,
17511754
) -> None:
17521755
self.platform = platform
17531756
self.major_version = major_version
17541757
self.super_properties = super_properties
17551758
self.encoded_super_properties = encoded_super_properties
1759+
self.extra_gateway_properties = extra_gateway_properties or {}
17561760

17571761
@classmethod
17581762
async def default(
17591763
cls: type[Self], session: ClientSession
17601764
) -> Self:
17611765
"""Creates a new :class:`Headers` instance using the default fetching mechanisms."""
17621766
try:
1763-
properties, encoded = await asyncio.wait_for(
1767+
properties, extra, encoded = await asyncio.wait_for(
17641768
cls.get_api_properties(session, 'web'), timeout=3
17651769
)
17661770
except Exception:
@@ -1771,6 +1775,7 @@ async def default(
17711775
major_version=int(properties['browser_version'].split('.')[0]),
17721776
super_properties=properties,
17731777
encoded_super_properties=encoded,
1778+
extra_gateway_properties=extra,
17741779
)
17751780

17761781
try:
@@ -1789,6 +1794,7 @@ async def default(
17891794
'os': 'Windows',
17901795
'browser': 'Chrome',
17911796
'device': '',
1797+
'system_locale': 'en-US',
17921798
'browser_user_agent': cls._get_user_agent(bv),
17931799
'browser_version': f'{bv}.0.0.0',
17941800
'os_version': '10',
@@ -1797,42 +1803,56 @@ async def default(
17971803
'referrer_current': '',
17981804
'referring_domain_current': '',
17991805
'release_channel': 'stable',
1800-
'system_locale': 'en-US',
18011806
'client_build_number': bn,
18021807
'client_event_source': None,
18031808
'has_client_mods': False,
1809+
'client_heartbeat_session_id': str(uuid.uuid4()),
18041810
}
18051811

18061812
return cls(
18071813
platform='Windows',
18081814
major_version=bv,
18091815
super_properties=properties,
18101816
encoded_super_properties=b64encode(_to_json(properties).encode()).decode('utf-8'),
1817+
extra_gateway_properties={
1818+
'client_app_state': None,
1819+
'is_fast_connect': False,
1820+
},
18111821
)
18121822

18131823
@cached_property
18141824
def user_agent(self) -> str:
1825+
"""Returns the user agent to be used for HTTP requests."""
18151826
return self.super_properties['browser_user_agent']
18161827

18171828
@cached_property
18181829
def client_hints(self) -> Dict[str, str]:
1830+
"""Returns the client hints to be used for HTTP requests."""
18191831
return {
18201832
'Sec-CH-UA': ', '.join([f'"{brand}";v="{version}"' for brand, version in self.generate_brand_version_list()]),
18211833
'Sec-CH-UA-Mobile': '?1' if self.platform in ('Android', 'iOS') else '?0',
18221834
'Sec-CH-UA-Platform': f'"{self.platform}"',
18231835
}
18241836

1837+
@property
1838+
def gateway_properties(self) -> Dict[str, Any]:
1839+
"""Returns the properties to be used for the Gateway."""
1840+
return {
1841+
**self.super_properties,
1842+
**self.extra_gateway_properties,
1843+
}
1844+
18251845
@staticmethod
18261846
async def get_api_properties(
18271847
session: ClientSession, type: str
1828-
) -> Tuple[Dict[str, Any], str]:
1848+
) -> Tuple[Dict[str, Any], Dict[str, Any], str]:
18291849
"""Fetches client properties from the API."""
18301850
async with session.post(
18311851
f'https://cordapi.dolfi.es/api/v2/properties/{type}'
18321852
) as resp:
18331853
resp.raise_for_status()
18341854
json = await resp.json()
1835-
return json['properties'], json['encoded']
1855+
return json['properties'], json['extra_gateway_properties'], json['encoded']
18361856

18371857
@staticmethod
18381858
async def _get_build_number(

0 commit comments

Comments
 (0)