Browse Source

Revert "Typo corrections, upgrades from Py2 to Py3-compatible formatting, patch yaml loader deprecation warning, Discord media proxy links (allows caching of possibly deleted images, relies less on the CDN)"

This reverts commit 5695eff8
pull/129/head
“elderlabs” 7 years ago
parent
commit
21ac37c54b
  1. 6
      disco/api/http.py
  2. 2
      disco/api/ratelimit.py
  3. 11
      disco/bot/bot.py
  4. 2
      disco/cli.py
  5. 21
      disco/gateway/client.py
  6. 2
      disco/state.py
  7. 2
      disco/types/base.py
  8. 6
      disco/types/channel.py
  9. 8
      disco/types/guild.py
  10. 6
      disco/types/user.py
  11. 44
      disco/voice/client.py
  12. 29
      disco/voice/udp.py
  13. 8
      setup.py

6
disco/api/http.py

@ -264,11 +264,11 @@ class HTTPClient(LoggingClass):
# Possibly wait if we're rate limited # Possibly wait if we're rate limited
response.rate_limited_duration = self.limiter.check(bucket) response.rate_limited_duration = self.limiter.check(bucket)
self.log.debug('KW: {}'.format(kwargs)) self.log.debug('KW: %s', kwargs)
# Make the actual request # Make the actual request
url = self.BASE_URL + route[1].format(**args) url = self.BASE_URL + route[1].format(**args)
self.log.info('{} {} ({})'.format(route[0].value, url, kwargs.get('params'))) self.log.info('%s %s (%s)', route[0].value, url, kwargs.get('params'))
r = self.session.request(route[0].value, url, **kwargs) r = self.session.request(route[0].value, url, **kwargs)
if self.after_request: if self.after_request:
@ -282,7 +282,7 @@ class HTTPClient(LoggingClass):
if r.status_code < 400: if r.status_code < 400:
return r return r
elif r.status_code != 429 and 400 <= r.status_code < 500: elif r.status_code != 429 and 400 <= r.status_code < 500:
self.log.warning('Request failed with code {}: {}'.format(r.status_code, r.content)) self.log.warning('Request failed with code %s: %s', r.status_code, r.content)
response.exception = APIException(r) response.exception = APIException(r)
raise response.exception raise response.exception
else: else:

2
disco/api/ratelimit.py

@ -99,7 +99,7 @@ class RouteState(LoggingClass):
self.event = gevent.event.Event() self.event = gevent.event.Event()
delay = (self.reset_time - time.time()) + .5 delay = (self.reset_time - time.time()) + .5
self.log.debug('Cooling down bucket {} for {} seconds'.format(self, delay)) self.log.debug('Cooling down bucket %s for %s seconds', self, delay)
gevent.sleep(delay) gevent.sleep(delay)
self.event.set() self.event.set()
self.event = None self.event = None

11
disco/bot/bot.py

@ -154,8 +154,7 @@ class Bot(LoggingClass):
except ImportError: except ImportError:
self.log.warning('Failed to enable HTTP server, Flask is not installed') self.log.warning('Failed to enable HTTP server, Flask is not installed')
else: else:
self.log.info('Starting HTTP server bound to {}:{}'.format(self.config.http_host, self.log.info('Starting HTTP server bound to %s:%s', self.config.http_host, self.config.http_port)
self.config.http_port))
self.http = Flask('disco') self.http = Flask('disco')
self.http_server = WSGIServer((self.config.http_host, self.config.http_port), self.http) self.http_server = WSGIServer((self.config.http_host, self.config.http_port), self.http)
self.http_server_greenlet = gevent.spawn(self.http_server.serve_forever) self.http_server_greenlet = gevent.spawn(self.http_server.serve_forever)
@ -245,7 +244,7 @@ class Bot(LoggingClass):
else: else:
possible[current] = group possible[current] = group
# Now, we want to compute the actual shortest abbreviation out of the # Now, we want to compute the actual shortest abbreivation out of the
# possible ones # possible ones
result = {} result = {}
for abbrev, group in six.iteritems(possible): for abbrev, group in six.iteritems(possible):
@ -450,7 +449,7 @@ class Bot(LoggingClass):
inst = inst(self, config) inst = inst(self, config)
if inst.__class__.__name__ in self.plugins: if inst.__class__.__name__ in self.plugins:
self.log.warning('Attempted to add already added plugin {}'.format(inst.__class__.__name__)) self.log.warning('Attempted to add already added plugin %s', inst.__class__.__name__)
raise Exception('Cannot add already added plugin: {}'.format(inst.__class__.__name__)) raise Exception('Cannot add already added plugin: {}'.format(inst.__class__.__name__))
self.ctx['plugin'] = self.plugins[inst.__class__.__name__] = inst self.ctx['plugin'] = self.plugins[inst.__class__.__name__] = inst
@ -468,7 +467,7 @@ class Bot(LoggingClass):
Plugin class to unload and remove. Plugin class to unload and remove.
""" """
if cls.__name__ not in self.plugins: if cls.__name__ not in self.plugins:
raise Exception('Cannot remove non-existent plugin: {}'.format(cls.__name__)) raise Exception('Cannot remove non-existant plugin: {}'.format(cls.__name__))
ctx = {} ctx = {}
self.plugins[cls.__name__].unload(ctx) self.plugins[cls.__name__].unload(ctx)
@ -496,7 +495,7 @@ class Bot(LoggingClass):
""" """
Adds and loads a plugin, based on its module path. Adds and loads a plugin, based on its module path.
""" """
self.log.info('Adding plugin module at path "{}"'.format(path)) self.log.info('Adding plugin module at path "%s"', path)
mod = importlib.import_module(path) mod = importlib.import_module(path)
loaded = False loaded = False

2
disco/cli.py

@ -103,7 +103,7 @@ def disco_main(run=False):
if run: if run:
(bot or client).run_forever() (bot or client).run_forever()
return bot or client return (bot or client)
if __name__ == '__main__': if __name__ == '__main__':

21
disco/gateway/client.py

@ -75,7 +75,7 @@ class GatewayClient(LoggingClass):
return self._send(op, data) return self._send(op, data)
def _send(self, op, data): def _send(self, op, data):
self.log.debug('GatewayClient.send {}'.format(op)) self.log.debug('GatewayClient.send %s', op)
self.packets.emit((SEND, op), data) self.packets.emit((SEND, op), data)
self.ws.send(self.encoder.encode({ self.ws.send(self.encoder.encode({
'op': op.value, 'op': op.value,
@ -96,7 +96,7 @@ class GatewayClient(LoggingClass):
def handle_dispatch(self, packet): def handle_dispatch(self, packet):
obj = GatewayEvent.from_dispatch(self.client, packet) obj = GatewayEvent.from_dispatch(self.client, packet)
self.log.debug('GatewayClient.handle_dispatch {}'.format(obj.__class__.__name__)) self.log.debug('GatewayClient.handle_dispatch %s', obj.__class__.__name__)
self.client.events.emit(obj.__class__.__name__, obj) self.client.events.emit(obj.__class__.__name__, obj)
if self.replaying: if self.replaying:
self.replayed_events += 1 self.replayed_events += 1
@ -119,7 +119,7 @@ class GatewayClient(LoggingClass):
self.ws.close() self.ws.close()
def handle_hello(self, packet): def handle_hello(self, packet):
self.log.info('Received HELLO, starting heartbeat...') self.log.info('Received HELLO, starting heartbeater...')
self._heartbeat_task = gevent.spawn(self.heartbeat_task, packet['d']['heartbeat_interval']) self._heartbeat_task = gevent.spawn(self.heartbeat_task, packet['d']['heartbeat_interval'])
def on_ready(self, ready): def on_ready(self, ready):
@ -128,7 +128,7 @@ class GatewayClient(LoggingClass):
self.reconnects = 0 self.reconnects = 0
def on_resumed(self, _): def on_resumed(self, _):
self.log.info('RESUME completed, replayed {} events'.format(self.replayed_events)) self.log.info('RESUME completed, replayed %s events', self.replayed_events)
self.reconnects = 0 self.reconnects = 0
self.replaying = False self.replaying = False
@ -144,7 +144,7 @@ class GatewayClient(LoggingClass):
if self.zlib_stream_enabled: if self.zlib_stream_enabled:
gateway_url += '&compress=zlib-stream' gateway_url += '&compress=zlib-stream'
self.log.info('Opening websocket connection to URL `{}`'.format(gateway_url)) self.log.info('Opening websocket connection to URL `%s`', gateway_url)
self.ws = Websocket(gateway_url) self.ws = Websocket(gateway_url)
self.ws.emitter.on('on_open', self.on_open) self.ws.emitter.on('on_open', self.on_open)
self.ws.emitter.on('on_error', self.on_error) self.ws.emitter.on('on_error', self.on_error)
@ -194,14 +194,14 @@ class GatewayClient(LoggingClass):
if isinstance(error, KeyboardInterrupt): if isinstance(error, KeyboardInterrupt):
self.shutting_down = True self.shutting_down = True
self.ws_event.set() self.ws_event.set()
raise Exception('WS received error: {}'.format(error)) raise Exception('WS recieved error: %s', error)
def on_open(self): def on_open(self):
if self.zlib_stream_enabled: if self.zlib_stream_enabled:
self._zlib = zlib.decompressobj() self._zlib = zlib.decompressobj()
if self.seq and self.session_id: if self.seq and self.session_id:
self.log.info('WS Opened: attempting resume w/ SID: {} SEQ: {}'.format(self.session_id, self.seq)) self.log.info('WS Opened: attempting resume w/ SID: %s SEQ: %s', self.session_id, self.seq)
self.replaying = True self.replaying = True
self.send(OPCode.RESUME, { self.send(OPCode.RESUME, {
'token': self.client.config.token, 'token': self.client.config.token,
@ -230,7 +230,7 @@ class GatewayClient(LoggingClass):
# Make sure we cleanup any old data # Make sure we cleanup any old data
self._buffer = None self._buffer = None
# Kill heartbeat, a reconnect/resume will trigger a HELLO which will # Kill heartbeater, a reconnect/resume will trigger a HELLO which will
# respawn it # respawn it
if self._heartbeat_task: if self._heartbeat_task:
self._heartbeat_task.kill() self._heartbeat_task.kill()
@ -244,7 +244,7 @@ class GatewayClient(LoggingClass):
# Track reconnect attempts # Track reconnect attempts
self.reconnects += 1 self.reconnects += 1
self.log.info('WS Closed: [{}] {} ({})'.format(code, reason, self.reconnects)) self.log.info('WS Closed: [%s] %s (%s)', code, reason, self.reconnects)
if self.max_reconnects and self.reconnects > self.max_reconnects: if self.max_reconnects and self.reconnects > self.max_reconnects:
raise Exception('Failed to reconnect after {} attempts, giving up'.format(self.max_reconnects)) raise Exception('Failed to reconnect after {} attempts, giving up'.format(self.max_reconnects))
@ -254,8 +254,7 @@ class GatewayClient(LoggingClass):
self.session_id = None self.session_id = None
wait_time = self.reconnects * 5 wait_time = self.reconnects * 5
self.log.info('Will attempt to {} after {} seconds'.format('resume' if self.session_id else 'reconnect', self.log.info('Will attempt to %s after %s seconds', 'resume' if self.session_id else 'reconnect', wait_time)
wait_time))
gevent.sleep(wait_time) gevent.sleep(wait_time)
# Reconnect # Reconnect

2
disco/state.py

@ -214,7 +214,7 @@ class State(object):
def on_guild_delete(self, event): def on_guild_delete(self, event):
if event.id in self.guilds: if event.id in self.guilds:
# Just delete the guild, channel references will fail # Just delete the guild, channel references will fall
del self.guilds[event.id] del self.guilds[event.id]
if event.id in self.voice_clients: if event.id in self.voice_clients:

2
disco/types/base.py

@ -215,7 +215,7 @@ def datetime(data):
except (ValueError, TypeError): except (ValueError, TypeError):
continue continue
raise ValueError('Failed to convert `{}` to datetime'.format(data)) raise ValueError('Failed to conver `{}` to datetime'.format(data))
def text(obj): def text(obj):

6
disco/types/channel.py

@ -457,21 +457,21 @@ class Channel(SlottedModel, Permissible):
""" """
Sets the channels bitrate. Sets the channels bitrate.
""" """
assert self.is_voice assert (self.is_voice)
return self.client.api.channels_modify(self.id, bitrate=bitrate, reason=reason) return self.client.api.channels_modify(self.id, bitrate=bitrate, reason=reason)
def set_user_limit(self, user_limit, reason=None): def set_user_limit(self, user_limit, reason=None):
""" """
Sets the channels user limit. Sets the channels user limit.
""" """
assert self.is_voice assert (self.is_voice)
return self.client.api.channels_modify(self.id, user_limit=user_limit, reason=reason) return self.client.api.channels_modify(self.id, user_limit=user_limit, reason=reason)
def set_parent(self, parent, reason=None): def set_parent(self, parent, reason=None):
""" """
Sets the channels parent. Sets the channels parent.
""" """
assert self.is_guild assert (self.is_guild)
return self.client.api.channels_modify( return self.client.api.channels_modify(
self.id, self.id,
parent_id=to_snowflake(parent) if parent else parent, parent_id=to_snowflake(parent) if parent else parent,

8
disco/types/guild.py

@ -75,7 +75,7 @@ class GuildEmoji(Emoji):
@property @property
def url(self): def url(self):
return 'https://media.discordapp.net/emojis/{}.{}'.format(self.id, 'gif' if self.animated else 'png') return 'https://discordapp.com/api/emojis/{}.{}'.format(self.id, 'gif' if self.animated else 'png')
@cached_property @cached_property
def guild(self): def guild(self):
@ -505,19 +505,19 @@ class Guild(SlottedModel, Permissible):
if not self.icon: if not self.icon:
return '' return ''
return 'https://media.discordapp.net/icons/{}/{}.{}?size={}'.format(self.id, self.icon, fmt, size) return 'https://cdn.discordapp.com/icons/{}/{}.{}?size={}'.format(self.id, self.icon, fmt, size)
def get_splash_url(self, fmt='webp', size=1024): def get_splash_url(self, fmt='webp', size=1024):
if not self.splash: if not self.splash:
return '' return ''
return 'https://media.discordapp.net/splashes/{}/{}.{}?size={}'.format(self.id, self.splash, fmt, size) return 'https://cdn.discordapp.com/splashes/{}/{}.{}?size={}'.format(self.id, self.splash, fmt, size)
def get_banner_url(self, fmt='webp', size=1024): def get_banner_url(self, fmt='webp', size=1024):
if not self.banner: if not self.banner:
return '' return ''
return 'https://media.discordapp.net/banners/{}/{}.{}?size={}'.format(self.id, self.banner, fmt, size) return 'https://cdn.discordapp.com/banners/{}/{}.{}?size={}'.format(self.id, self.banner, fmt, size)
@property @property
def icon_url(self): def icon_url(self):

6
disco/types/user.py

@ -26,11 +26,11 @@ class User(SlottedModel, with_equality('id'), with_hash('id')):
if not self.avatar: if not self.avatar:
return 'https://cdn.discordapp.com/embed/avatars/{}.png'.format(self.default_avatar.value) return 'https://cdn.discordapp.com/embed/avatars/{}.png'.format(self.default_avatar.value)
if fmt is not None: if fmt is not None:
return 'https://media.discordapp.net/avatars/{}/{}.{}?size={}'.format(self.id, self.avatar, fmt, size) return 'https://cdn.discordapp.com/avatars/{}/{}.{}?size={}'.format(self.id, self.avatar, fmt, size)
if self.avatar.startswith('a_'): if self.avatar.startswith('a_'):
return 'https://media.discordapp.net/avatars/{}/{}.gif?size={}'.format(self.id, self.avatar, size) return 'https://cdn.discordapp.com/avatars/{}/{}.gif?size={}'.format(self.id, self.avatar, size)
else: else:
return 'https://media.discordapp.net/avatars/{}/{}.webp?size={}'.format(self.id, self.avatar, size) return 'https://cdn.discordapp.com/avatars/{}/{}.webp?size={}'.format(self.id, self.avatar, size)
@property @property
def default_avatar(self): def default_avatar(self):

44
disco/voice/client.py

@ -143,7 +143,7 @@ class VoiceClient(LoggingClass):
return self.ssrc + 3 return self.ssrc + 3
def set_state(self, state): def set_state(self, state):
self.log.debug('[{}] state {} -> {}'.format(self, self.state, state)) self.log.debug('[%s] state %s -> %s', self, self.state, state)
prev_state = self.state prev_state = self.state
self.state = state self.state = state
self.state_emitter.emit(state, prev_state) self.state_emitter.emit(state, prev_state)
@ -154,8 +154,7 @@ class VoiceClient(LoggingClass):
return return
self.log.info( self.log.info(
'[{}] Set endpoint from VOICE_SERVER_UPDATE (state = {} / endpoint = {})'.format(self, self.state, '[%s] Set endpoint from VOICE_SERVER_UPDATE (state = %s / endpoint = %s)', self, self.state, endpoint)
endpoint))
self.endpoint = endpoint self.endpoint = endpoint
@ -211,13 +210,13 @@ class VoiceClient(LoggingClass):
def send(self, op, data): def send(self, op, data):
if self.ws and self.ws.sock and self.ws.sock.connected: if self.ws and self.ws.sock and self.ws.sock.connected:
self.log.debug('[{}] sending OP {} (data = {})'.format(self, op, data)) self.log.debug('[%s] sending OP %s (data = %s)', self, op, data)
self.ws.send(self.encoder.encode({ self.ws.send(self.encoder.encode({
'op': op.value, 'op': op.value,
'd': data, 'd': data,
}), self.encoder.OPCODE) }), self.encoder.OPCODE)
else: else:
self.log.debug('[{}] dropping because ws is closed OP {} (data = {})'.format(self, op, data)) self.log.debug('[%s] dropping because ws is closed OP %s (data = %s)', self, op, data)
def on_voice_client_connect(self, data): def on_voice_client_connect(self, data):
user_id = int(data['user_id']) user_id = int(data['user_id'])
@ -242,13 +241,12 @@ class VoiceClient(LoggingClass):
self.udp.set_audio_codec(data['audio_codec']) self.udp.set_audio_codec(data['audio_codec'])
def on_voice_hello(self, data): def on_voice_hello(self, data):
self.log.info('[{}] Received Voice HELLO payload, starting heartbeat'.format(self)) self.log.info('[%s] Received Voice HELLO payload, starting heartbeater', self)
self._heartbeat_task = gevent.spawn(self._heartbeat, data['heartbeat_interval']) self._heartbeat_task = gevent.spawn(self._heartbeat, data['heartbeat_interval'])
self.set_state(VoiceState.AUTHENTICATED) self.set_state(VoiceState.AUTHENTICATED)
def on_voice_ready(self, data): def on_voice_ready(self, data):
self.log.info('[{}] Received Voice READY payload, attempting to negotiate voice connection w/ remote'.format( self.log.info('[%s] Received Voice READY payload, attempting to negotiate voice connection w/ remote', self)
self))
self.set_state(VoiceState.CONNECTING) self.set_state(VoiceState.CONNECTING)
self.ssrc = data['ssrc'] self.ssrc = data['ssrc']
self.ip = data['ip'] self.ip = data['ip']
@ -258,12 +256,12 @@ class VoiceClient(LoggingClass):
for mode in self.SUPPORTED_MODES: for mode in self.SUPPORTED_MODES:
if mode in data['modes']: if mode in data['modes']:
self.mode = mode self.mode = mode
self.log.debug('[{}] Selected mode {}'.format(self, mode)) self.log.debug('[%s] Selected mode %s', self, mode)
break break
else: else:
raise Exception('Failed to find a supported voice mode') raise Exception('Failed to find a supported voice mode')
self.log.debug('[{}] Attempting IP discovery over UDP to {}:{}'.format(self, self.ip, self.port)) self.log.debug('[%s] Attempting IP discovery over UDP to %s:%s', self, self.ip, self.port)
self.udp = UDPVoiceClient(self) self.udp = UDPVoiceClient(self)
ip, port = self.udp.connect(self.ip, self.port) ip, port = self.udp.connect(self.ip, self.port)
@ -283,8 +281,7 @@ class VoiceClient(LoggingClass):
'payload_type': RTPPayloadTypes.get(codec).value, 'payload_type': RTPPayloadTypes.get(codec).value,
}) })
self.log.debug('[{}] IP discovery completed (ip = {}, port = {}), sending SELECT_PROTOCOL'.format(self, ip, self.log.debug('[%s] IP discovery completed (ip = %s, port = %s), sending SELECT_PROTOCOL', self, ip, port)
port))
self.send(VoiceOPCode.SELECT_PROTOCOL, { self.send(VoiceOPCode.SELECT_PROTOCOL, {
'protocol': 'udp', 'protocol': 'udp',
'data': { 'data': {
@ -301,11 +298,11 @@ class VoiceClient(LoggingClass):
}) })
def on_voice_resumed(self, data): def on_voice_resumed(self, data):
self.log.info('[{}] Received resumed'.format(self)) self.log.info('[%s] Received resumed', self)
self.set_state(VoiceState.CONNECTED) self.set_state(VoiceState.CONNECTED)
def on_voice_sdp(self, sdp): def on_voice_sdp(self, sdp):
self.log.info('[{}] Received session description, connection completed'.format(self)) self.log.info('[%s] Received session description, connection completed', self)
self.mode = sdp['mode'] self.mode = sdp['mode']
self.audio_codec = sdp['audio_codec'] self.audio_codec = sdp['audio_codec']
@ -344,7 +341,7 @@ class VoiceClient(LoggingClass):
self.log.exception('Failed to parse voice gateway message: ') self.log.exception('Failed to parse voice gateway message: ')
def on_error(self, err): def on_error(self, err):
self.log.error('[{}] Voice websocket error: {}'.format(self, err)) self.log.error('[%s] Voice websocket error: %s', self, err)
def on_open(self): def on_open(self):
if self._identified: if self._identified:
@ -363,7 +360,7 @@ class VoiceClient(LoggingClass):
}) })
def on_close(self, code, reason): def on_close(self, code, reason):
self.log.warning('[{}] Voice websocket closed: [{}] {} ({})'.format(self, code, reason, self._reconnects)) self.log.warning('[%s] Voice websocket closed: [%s] %s (%s)', self, code, reason, self._reconnects)
if self._heartbeat_task: if self._heartbeat_task:
self._heartbeat_task.kill() self._heartbeat_task.kill()
@ -375,7 +372,7 @@ class VoiceClient(LoggingClass):
if self.state == VoiceState.DISCONNECTED: if self.state == VoiceState.DISCONNECTED:
return return
self.log.info('[{}] Attempting Websocket Resumption'.format(self)) self.log.info('[%s] Attempting Websocket Resumption', self)
self.set_state(VoiceState.RECONNECTING) self.set_state(VoiceState.RECONNECTING)
@ -399,8 +396,7 @@ class VoiceClient(LoggingClass):
wait_time = 1 wait_time = 1
self.log.info( self.log.info(
'[{}] Will attempt to {} after {} seconds'.format(self, 'resume' if self._identified else 'reconnect', '[%s] Will attempt to %s after %s seconds', self, 'resume' if self._identified else 'reconnect', wait_time)
wait_time))
gevent.sleep(wait_time) gevent.sleep(wait_time)
self._connect_and_run() self._connect_and_run()
@ -410,17 +406,17 @@ class VoiceClient(LoggingClass):
channel_id = self.server_id channel_id = self.server_id
if not channel_id: if not channel_id:
raise VoiceException('[{}] cannot connect to an empty channel id'.format(self)) raise VoiceException('[%s] cannot connect to an empty channel id', self)
if self.channel_id == channel_id: if self.channel_id == channel_id:
if self.state == VoiceState.CONNECTED: if self.state == VoiceState.CONNECTED:
self.log.debug('[{}] Already connected to {}, returning'.format(self, self.channel)) self.log.debug('[%s] Already connected to %s, returning', self, self.channel)
return self return self
else: else:
if self.state == VoiceState.CONNECTED: if self.state == VoiceState.CONNECTED:
self.log.debug('[{}] Moving to channel {}'.format(self, channel_id)) self.log.debug('[%s] Moving to channel %s', self, channel_id)
else: else:
self.log.debug('[{}] Attempting connection to channel id {}'.format(self, channel_id)) self.log.debug('[%s] Attempting connection to channel id %s', self, channel_id)
self.set_state(VoiceState.AWAITING_ENDPOINT) self.set_state(VoiceState.AWAITING_ENDPOINT)
self.set_voice_state(channel_id, **kwargs) self.set_voice_state(channel_id, **kwargs)
@ -435,7 +431,7 @@ class VoiceClient(LoggingClass):
if self.state == VoiceState.DISCONNECTED: if self.state == VoiceState.DISCONNECTED:
return return
self.log.debug('[{}] disconnect called'.format(self)) self.log.debug('[%s] disconnect called', self)
self.set_state(VoiceState.DISCONNECTED) self.set_state(VoiceState.DISCONNECTED)
del self.client.state.voice_clients[self.server_id] del self.client.state.voice_clients[self.server_id]

29
disco/voice/udp.py

@ -7,7 +7,7 @@ from collections import namedtuple
try: try:
import nacl.secret import nacl.secret
except ImportError: except ImportError:
print('WARNING: PyNaCl is not installed, voice support is disabled') print('WARNING: nacl is not installed, voice support is disabled')
from holster.enum import Enum from holster.enum import Enum
@ -103,8 +103,7 @@ class UDPVoiceClient(LoggingClass):
ptype = RTPPayloadTypes.get(codec) ptype = RTPPayloadTypes.get(codec)
self._rtp_audio_header[1] = ptype.value self._rtp_audio_header[1] = ptype.value
self.log.debug('[{}] Set UDP\'s Audio Codec to {}, RTP payload type {}'.format(self.vc, ptype.name, self.log.debug('[%s] Set UDP\'s Audio Codec to %s, RTP payload type %s', self.vc, ptype.name, ptype.value)
ptype.value))
def increment_timestamp(self, by): def increment_timestamp(self, by):
self.timestamp += by self.timestamp += by
@ -169,7 +168,7 @@ class UDPVoiceClient(LoggingClass):
# Data cannot be less than the bare minimum, just ignore # Data cannot be less than the bare minimum, just ignore
if len(data) <= 12: if len(data) <= 12:
self.log.debug('[{}] [VoiceData] Received voice data under 13 bytes'.format(self.vc)) self.log.debug('[%s] [VoiceData] Received voice data under 13 bytes', self.vc)
continue continue
first, second = struct.unpack_from('>BB', data) first, second = struct.unpack_from('>BB', data)
@ -221,16 +220,14 @@ class UDPVoiceClient(LoggingClass):
# Check if rtp version is 2 # Check if rtp version is 2
if rtp.version != 2: if rtp.version != 2:
self.log.debug('[{}] [VoiceData] Received an invalid RTP packet version, {}'.format(self.vc, self.log.debug('[%s] [VoiceData] Received an invalid RTP packet version, %s', self.vc, rtp.version)
rtp.version))
continue continue
payload_type = RTPPayloadTypes.get(rtp.payload_type) payload_type = RTPPayloadTypes.get(rtp.payload_type)
# Unsupported payload type received # Unsupported payload type received
if not payload_type: if not payload_type:
self.log.debug('[{}] [VoiceData] Received unsupported payload type, {}'.format(self.vc, self.log.debug('[%s] [VoiceData] Received unsupported payload type, %s', self.vc, rtp.payload_type)
rtp.payload_type))
continue continue
nonce = bytearray(24) nonce = bytearray(24)
@ -243,13 +240,13 @@ class UDPVoiceClient(LoggingClass):
elif self.vc.mode == 'xsalsa20_poly1305': elif self.vc.mode == 'xsalsa20_poly1305':
nonce[:12] = data[:12] nonce[:12] = data[:12]
else: else:
self.log.debug('[{}] [VoiceData] Unsupported Encryption Mode, {}'.format(self.vc, self.vc.mode)) self.log.debug('[%s] [VoiceData] Unsupported Encryption Mode, %s', self.vc, self.vc.mode)
continue continue
try: try:
data = self._secret_box.decrypt(bytes(data[12:]), bytes(nonce)) data = self._secret_box.decrypt(bytes(data[12:]), bytes(nonce))
except Exception: except Exception:
self.log.debug('[{}] [VoiceData] Failed to decode data from ssrc {}'.format(self.vc, rtp.ssrc)) self.log.debug('[%s] [VoiceData] Failed to decode data from ssrc %s', self.vc, rtp.ssrc)
continue continue
# RFC3550 Section 5.1 (Padding) # RFC3550 Section 5.1 (Padding)
@ -271,11 +268,11 @@ class UDPVoiceClient(LoggingClass):
first_byte, = struct.unpack_from('>B', data[:offset]) first_byte, = struct.unpack_from('>B', data[:offset])
offset += 1 offset += 1
rtp_extension_identifier = first_byte & 0xF rtp_extension_identifer = first_byte & 0xF
rtp_extension_len = ((first_byte >> 4) & 0xF) + 1 rtp_extension_len = ((first_byte >> 4) & 0xF) + 1
# Ignore data if identifier == 15, so skip if this is set as 0 # Ignore data if identifer == 15, so skip if this is set as 0
if rtp_extension_identifier: if rtp_extension_identifer:
fields.append(data[offset:offset + rtp_extension_len]) fields.append(data[offset:offset + rtp_extension_len])
offset += rtp_extension_len offset += rtp_extension_len
@ -293,7 +290,7 @@ class UDPVoiceClient(LoggingClass):
# RFC3550 Section 5.3: Profile-Specific Modifications to the RTP Header # RFC3550 Section 5.3: Profile-Specific Modifications to the RTP Header
# clients send it sometimes, definitely on fresh connects to a server, dunno what to do here # clients send it sometimes, definitely on fresh connects to a server, dunno what to do here
if rtp.marker: if rtp.marker:
self.log.debug('[{}] [VoiceData] Received RTP data with the marker set, skipping'.format(self.vc)) self.log.debug('[%s] [VoiceData] Received RTP data with the marker set, skipping', self.vc)
continue continue
payload = VoiceData( payload = VoiceData(
@ -331,7 +328,7 @@ class UDPVoiceClient(LoggingClass):
try: try:
data, addr = gevent.spawn(lambda: self.conn.recvfrom(70)).get(timeout=timeout) data, addr = gevent.spawn(lambda: self.conn.recvfrom(70)).get(timeout=timeout)
except gevent.Timeout: except gevent.Timeout:
return None, None return (None, None)
# Read IP and port # Read IP and port
ip = str(data[4:]).split('\x00', 1)[0] ip = str(data[4:]).split('\x00', 1)[0]
@ -341,4 +338,4 @@ class UDPVoiceClient(LoggingClass):
self.connected = True self.connected = True
self._run_task = gevent.spawn(self.run) self._run_task = gevent.spawn(self.run)
return ip, port return (ip, port)

8
setup.py

@ -10,16 +10,16 @@ with open('README.md') as f:
readme = f.read() readme = f.read()
extras_require = { extras_require = {
'voice': ['pynacl>=1.2.1'], 'voice': ['pynacl==1.2.1'],
'http': ['flask>=0.12.2'], 'http': ['flask==0.12.2'],
'yaml': ['pyyaml>=3.12'], 'yaml': ['pyyaml==3.12'],
'music': ['youtube_dl>=2018.1.21'], 'music': ['youtube_dl>=2018.1.21'],
'performance': [ 'performance': [
'erlpack==0.3.2' if sys.version_info.major == 2 else 'earl-etf==2.1.2', 'erlpack==0.3.2' if sys.version_info.major == 2 else 'earl-etf==2.1.2',
'ujson==1.35', 'ujson==1.35',
'wsaccel==0.6.2', 'wsaccel==0.6.2',
], ],
'sharding': ['gipc>=0.6.0'], 'sharding': ['gipc==0.6.0'],
'docs': ['biblio==0.0.4'], 'docs': ['biblio==0.0.4'],
} }

Loading…
Cancel
Save