26
26
from __future__ import annotations
27
27
28
28
import asyncio
29
- from collections import deque
30
- from collections .abc import Callable , Coroutine
31
29
import logging
32
30
import struct
33
31
import time
32
+ from collections import deque
33
+ from collections .abc import Callable , Coroutine
34
34
from typing import TYPE_CHECKING , Any
35
35
36
36
import aiohttp
37
37
38
38
from discord import utils
39
39
from discord .enums import SpeakingState
40
40
from discord .errors import ConnectionClosed
41
- from discord .gateway import DiscordWebSocket , KeepAliveHandler as KeepAliveHandlerBase
41
+ from discord .gateway import DiscordWebSocket
42
+ from discord .gateway import KeepAliveHandler as KeepAliveHandlerBase
42
43
43
44
from .enums import OpCodes
44
45
@@ -56,8 +57,8 @@ def __init__(
56
57
interval : float | None = None ,
57
58
** kwargs : Any ,
58
59
) -> None :
59
- daemon : bool = kwargs .pop (' daemon' , True )
60
- name : str = kwargs .pop (' name' , f' voice-keep-alive-handler:{ id (self ):#x} ' )
60
+ daemon : bool = kwargs .pop (" daemon" , True )
61
+ name : str = kwargs .pop (" name" , f" voice-keep-alive-handler:{ id (self ):#x} " )
61
62
super ().__init__ (
62
63
* args ,
63
64
** kwargs ,
@@ -67,17 +68,21 @@ def __init__(
67
68
68
69
self .ws : VoiceWebSocket = ws
69
70
self .interval : float | None = interval
70
- self .msg : str = 'Keeping shard ID %s voice websocket alive with timestamp %s.'
71
- self .block_msg : str = 'Shard ID %s voice heartbeat blocked for more than %s seconds.'
72
- self .behing_msg : str = 'High socket latency, shard ID %s heartbeat is %.1fs behind.'
71
+ self .msg : str = "Keeping shard ID %s voice websocket alive with timestamp %s."
72
+ self .block_msg : str = (
73
+ "Shard ID %s voice heartbeat blocked for more than %s seconds."
74
+ )
75
+ self .behing_msg : str = (
76
+ "High socket latency, shard ID %s heartbeat is %.1fs behind."
77
+ )
73
78
self .recent_ack_latencies : deque [float ] = deque (maxlen = 20 )
74
79
75
80
def get_payload (self ) -> dict [str , Any ]:
76
81
return {
77
- 'op' : int (OpCodes .heartbeat ),
78
- 'd' : {
79
- 't' : int (time .time () * 1000 ),
80
- ' seq_ack' : self .ws .seq_ack ,
82
+ "op" : int (OpCodes .heartbeat ),
83
+ "d" : {
84
+ "t" : int (time .time () * 1000 ),
85
+ " seq_ack" : self .ws .seq_ack ,
81
86
},
82
87
}
83
88
@@ -115,47 +120,47 @@ async def _hook(self, *args: Any) -> Any:
115
120
pass
116
121
117
122
async def send_as_json (self , data : Any ) -> None :
118
- _log .debug (' Sending voice websocket frame: %s.' , data )
123
+ _log .debug (" Sending voice websocket frame: %s." , data )
119
124
await self .ws .send_str (utils ._to_json (data ))
120
125
121
126
send_heartbeat = send_as_json
122
127
123
128
async def resume (self ) -> None :
124
129
payload = {
125
- 'op' : int (OpCodes .resume ),
126
- 'd' : {
127
- ' token' : self .token ,
128
- ' server_id' : str (self .state .server_id ),
129
- ' session_id' : self .session_id ,
130
- ' seq_ack' : self .seq_ack ,
130
+ "op" : int (OpCodes .resume ),
131
+ "d" : {
132
+ " token" : self .token ,
133
+ " server_id" : str (self .state .server_id ),
134
+ " session_id" : self .session_id ,
135
+ " seq_ack" : self .seq_ack ,
131
136
},
132
137
}
133
138
await self .send_as_json (payload )
134
139
135
140
async def received_message (self , msg : Any , / ):
136
- _log .debug (' Voice websocket frame received: %s' , msg )
137
- op = msg ['op' ]
138
- data = msg .get (' data' , {}) # this key should ALWAYS be given, but guard anyways
139
- self .seq_ack = data .get (' seq' , self .seq_ack ) # keep the seq_ack updated
141
+ _log .debug (" Voice websocket frame received: %s" , msg )
142
+ op = msg ["op" ]
143
+ data = msg .get (" data" , {}) # this key should ALWAYS be given, but guard anyways
144
+ self .seq_ack = data .get (" seq" , self .seq_ack ) # keep the seq_ack updated
140
145
141
146
if op == OpCodes .ready :
142
147
await self .ready (data )
143
148
elif op == OpCodes .heartbeat_ack :
144
149
if not self ._keep_alive :
145
150
_log .error (
146
- ' Received a heartbeat ACK but no keep alive handler was set.' ,
151
+ " Received a heartbeat ACK but no keep alive handler was set." ,
147
152
)
148
153
return
149
154
self ._keep_alive .ack ()
150
155
elif op == OpCodes .resumed :
151
156
_log .info (
152
- f' Voice connection on channel ID { self .state .channel_id } (guild { self .state .guild_id } ) was '
153
- ' successfully RESUMED.' ,
157
+ f" Voice connection on channel ID { self .state .channel_id } (guild { self .state .guild_id } ) was "
158
+ " successfully RESUMED." ,
154
159
)
155
160
elif op == OpCodes .session_description :
156
161
self .state .update_session_description (data )
157
162
elif op == OpCodes .hello :
158
- interval = data [' heartbeat_interval' ] / 1000.0
163
+ interval = data [" heartbeat_interval" ] / 1000.0
159
164
self ._keep_alive = KeepAliveHandler (
160
165
ws = self ,
161
166
interval = min (interval , 5 ),
@@ -167,12 +172,12 @@ async def received_message(self, msg: Any, /):
167
172
async def ready (self , data : dict [str , Any ]) -> None :
168
173
state = self .state
169
174
170
- state .ssrc = data [' ssrc' ]
171
- state .voice_port = data [' port' ]
172
- state .endpoint_ip = data ['ip' ]
175
+ state .ssrc = data [" ssrc" ]
176
+ state .voice_port = data [" port" ]
177
+ state .endpoint_ip = data ["ip" ]
173
178
174
179
_log .debug (
175
- f' Connecting to { state .endpoint_ip } (port { state .voice_port } ).' ,
180
+ f" Connecting to { state .endpoint_ip } (port { state .voice_port } )." ,
176
181
)
177
182
178
183
await self .loop .sock_connect (
@@ -185,11 +190,13 @@ async def ready(self, data: dict[str, Any]) -> None:
185
190
async def get_ip (self ) -> tuple [str , int ]:
186
191
state = self .state
187
192
packet = bytearray (75 )
188
- struct .pack_into ('>H' , packet , 0 , 1 ) # 1 = Send
189
- struct .pack_into ('>H' , packet , 2 , 70 ) # 70 = Length
190
- struct .pack_into ('>I' , packet , 4 , state .ssrc )
193
+ struct .pack_into (">H" , packet , 0 , 1 ) # 1 = Send
194
+ struct .pack_into (">H" , packet , 2 , 70 ) # 70 = Length
195
+ struct .pack_into (">I" , packet , 4 , state .ssrc )
191
196
192
- _log .debug (f'Sending IP discovery packet for voice in channel { state .channel_id } (guild { state .guild_id } )' )
197
+ _log .debug (
198
+ f"Sending IP discovery packet for voice in channel { state .channel_id } (guild { state .guild_id } )"
199
+ )
193
200
await self .loop .sock_sendall (state .socket , packet )
194
201
195
202
fut : asyncio .Future [bytes ] = self .loop .create_future ()
@@ -202,31 +209,33 @@ def get_ip_packet(data: bytes) -> None:
202
209
state .add_socket_listener (get_ip_packet )
203
210
recv = await fut
204
211
205
- _log .debug (' Received IP discovery packet with data %s' , recv )
212
+ _log .debug (" Received IP discovery packet with data %s" , recv )
206
213
207
214
ip_start = 8
208
215
ip_end = recv .index (0 , ip_start )
209
- ip = recv [ip_start :ip_end ].decode (' ascii' )
210
- port = struct .unpack_from ('>H' , recv , len (recv ) - 2 )[0 ]
211
- _log .debug (' Detected IP %s with port %s' , ip , port )
216
+ ip = recv [ip_start :ip_end ].decode (" ascii" )
217
+ port = struct .unpack_from (">H" , recv , len (recv ) - 2 )[0 ]
218
+ _log .debug (" Detected IP %s with port %s" , ip , port )
212
219
213
220
return ip , port
214
221
215
222
@property
216
223
def latency (self ) -> float :
217
224
heartbeat = self ._keep_alive
218
- return float (' inf' ) if heartbeat is None else heartbeat .latency
225
+ return float (" inf" ) if heartbeat is None else heartbeat .latency
219
226
220
227
@property
221
228
def average_latency (self ) -> float :
222
229
heartbeat = self ._keep_alive
223
230
if heartbeat is None or not heartbeat .recent_ack_latencies :
224
- return float (' inf' )
231
+ return float (" inf" )
225
232
return sum (heartbeat .recent_ack_latencies ) / len (heartbeat .recent_ack_latencies )
226
233
227
234
async def load_secret_key (self , data : dict [str , Any ]) -> None :
228
- _log .debug (f'Received secret key for voice connection in channel { self .state .channel_id } (guild { self .state .guild_id } )' )
229
- self .secret_key = self .state .secret_key = data ['secret_key' ]
235
+ _log .debug (
236
+ f"Received secret key for voice connection in channel { self .state .channel_id } (guild { self .state .guild_id } )"
237
+ )
238
+ self .secret_key = self .state .secret_key = data ["secret_key" ]
230
239
await self .speak (SpeakingState .none )
231
240
232
241
async def poll_event (self ) -> None :
@@ -235,10 +244,14 @@ async def poll_event(self) -> None:
235
244
if msg .type is aiohttp .WSMsgType .TEXT :
236
245
await self .received_message (utils ._from_json (msg .data ))
237
246
elif msg .type is aiohttp .WSMsgType .ERROR :
238
- _log .debug (' Received %s' , msg )
247
+ _log .debug (" Received %s" , msg )
239
248
raise ConnectionClosed (self .ws , shard_id = None ) from msg .data
240
- elif msg .type in (aiohttp .WSMsgType .CLOSED , aiohttp .WSMsgType .CLOSE , aiohttp .WSMsgType .CLOSING ):
241
- _log .debug ('Received %s' , msg )
249
+ elif msg .type in (
250
+ aiohttp .WSMsgType .CLOSED ,
251
+ aiohttp .WSMsgType .CLOSE ,
252
+ aiohttp .WSMsgType .CLOSING ,
253
+ ):
254
+ _log .debug ("Received %s" , msg )
242
255
raise ConnectionClosed (self .ws , shard_id = None , code = self ._close_code )
243
256
244
257
async def close (self , code : int = 1000 ) -> None :
0 commit comments