Update dependencies and copyright year (#2436)

- aiohttp 3.5
- websockets 7
- Rapptz/discord.py@700dbb5
- A few others

Signed-off-by: Toby Harradine <tobyharradine@gmail.com>
This commit is contained in:
Toby Harradine
2019-02-13 10:49:11 +11:00
committed by GitHub
parent c87286d3c6
commit 9869f95bd6
54 changed files with 439 additions and 294 deletions

View File

@@ -3,7 +3,7 @@
"""
The MIT License (MIT)
Copyright (c) 2015-2017 Rapptz
Copyright (c) 2015-2019 Rapptz
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -26,6 +26,7 @@ DEALINGS IN THE SOFTWARE.
import asyncio
from collections import namedtuple
import concurrent.futures
import json
import logging
import struct
@@ -38,6 +39,7 @@ import websockets
from . import utils
from .activity import _ActivityTag
from .enums import SpeakingState
from .errors import ConnectionClosed, InvalidArgument
log = logging.getLogger(__name__)
@@ -72,6 +74,8 @@ class KeepAliveHandler(threading.Thread):
self.daemon = True
self.shard_id = shard_id
self.msg = "Keeping websocket alive with sequence %s."
self.block_msg = "Heartbeat blocked for more than %s seconds."
self.behind_msg = "Can't keep up, websocket is %.1fs behind."
self._stop_ev = threading.Event()
self._last_ack = time.perf_counter()
self._last_send = time.perf_counter()
@@ -102,7 +106,15 @@ class KeepAliveHandler(threading.Thread):
f = asyncio.run_coroutine_threadsafe(coro, loop=self.ws.loop)
try:
# block until sending is complete
f.result()
total = 0
while True:
try:
f.result(5)
break
except concurrent.futures.TimeoutError:
total += 5
log.warning(self.block_msg, total)
except Exception:
self.stop()
else:
@@ -118,12 +130,16 @@ class KeepAliveHandler(threading.Thread):
ack_time = time.perf_counter()
self._last_ack = ack_time
self.latency = ack_time - self._last_send
if self.latency > 10:
log.warning(self.behind_msg, self.latency)
class VoiceKeepAliveHandler(KeepAliveHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.msg = "Keeping voice websocket alive with timestamp %s."
self.block_msg = "Voice heartbeat blocked for more than %s seconds"
self.behind_msg = "Can't keep up, voice websocket is %.1fs behind"
def get_payload(self):
return {"op": self.ws.HEARTBEAT, "d": int(time.time() * 1000)}
@@ -482,7 +498,7 @@ class DiscordWebSocket(websockets.client.WebSocketClientProtocol):
async def send_as_json(self, data):
try:
await super().send(utils.to_json(data))
await self.send(utils.to_json(data))
except websockets.exceptions.ConnectionClosed as exc:
if not self._can_handle_close(exc.code):
raise ConnectionClosed(exc, shard_id=self.shard_id) from exc
@@ -561,6 +577,10 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
Receive only. Tells you that your websocket connection was acknowledged.
INVALIDATE_SESSION
Sent only. Tells you that your RESUME request has failed and to re-IDENTIFY.
CLIENT_CONNECT
Indicates a user has connected to voice.
CLIENT_DISCONNECT
Receive only. Indicates a user has disconnected from voice.
"""
IDENTIFY = 0
@@ -573,6 +593,8 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
RESUME = 7
HELLO = 8
INVALIDATE_SESSION = 9
CLIENT_CONNECT = 12
CLIENT_DISCONNECT = 13
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -611,7 +633,7 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
@classmethod
async def from_client(cls, client, *, resume=False):
"""Creates a voice websocket for the :class:`VoiceClient`."""
gateway = "wss://" + client.endpoint + "/?v=3"
gateway = "wss://" + client.endpoint + "/?v=4"
ws = await websockets.connect(gateway, loop=client.loop, klass=cls, compression=None)
ws.gateway = gateway
ws._connection = client
@@ -624,19 +646,21 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
return ws
async def select_protocol(self, ip, port):
async def select_protocol(self, ip, port, mode):
payload = {
"op": self.SELECT_PROTOCOL,
"d": {
"protocol": "udp",
"data": {"address": ip, "port": port, "mode": "xsalsa20_poly1305"},
},
"d": {"protocol": "udp", "data": {"address": ip, "port": port, "mode": mode}},
}
await self.send_as_json(payload)
async def speak(self, is_speaking=True):
payload = {"op": self.SPEAKING, "d": {"speaking": is_speaking, "delay": 0}}
async def client_connect(self):
payload = {"op": self.CLIENT_CONNECT, "d": {"audio_ssrc": self._connection.ssrc}}
await self.send_as_json(payload)
async def speak(self, state=SpeakingState.voice):
payload = {"op": self.SPEAKING, "d": {"speaking": int(state), "delay": 0}}
await self.send_as_json(payload)
@@ -646,9 +670,6 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
data = msg.get("d")
if op == self.READY:
interval = data["heartbeat_interval"] / 1000.0
self._keep_alive = VoiceKeepAliveHandler(ws=self, interval=interval)
self._keep_alive.start()
await self.initial_connection(data)
elif op == self.HEARTBEAT_ACK:
self._keep_alive.ack()
@@ -656,7 +677,12 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
log.info("Voice RESUME failed.")
await self.identify()
elif op == self.SESSION_DESCRIPTION:
self._connection.mode = data["mode"]
await self.load_secret_key(data)
elif op == self.HELLO:
interval = data["heartbeat_interval"] / 1000.0
self._keep_alive = VoiceKeepAliveHandler(ws=self, interval=interval)
self._keep_alive.start()
async def initial_connection(self, data):
state = self._connection
@@ -677,15 +703,23 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
# the port is a little endian unsigned short in the last two bytes
# yes, this is different endianness from everything else
state.port = struct.unpack_from("<H", recv, len(recv) - 2)[0]
log.debug("detected ip: %s port: %s", state.ip, state.port)
await self.select_protocol(state.ip, state.port)
log.info("selected the voice protocol for use")
# there *should* always be at least one supported mode (xsalsa20_poly1305)
modes = [mode for mode in data["modes"] if mode in self._connection.supported_modes]
log.debug("received supported encryption modes: %s", ", ".join(modes))
mode = modes[0]
await self.select_protocol(state.ip, state.port, mode)
log.info("selected the voice protocol for use (%s)", mode)
await self.client_connect()
async def load_secret_key(self, data):
log.info("received secret key for voice connection")
self._connection.secret_key = data.get("secret_key")
await self.speak()
await self.speak(False)
async def poll_event(self):
try: