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