Drop support for Python 3.4 and make minimum version 3.5.2.
This commit is contained in:
@ -43,7 +43,7 @@ class Shard:
|
||||
self.ws = ws
|
||||
self._client = client
|
||||
self.loop = self._client.loop
|
||||
self._current = compat.create_future(self.loop)
|
||||
self._current = self.loop.create_future()
|
||||
self._current.set_result(None) # we just need an already done future
|
||||
self._pending = asyncio.Event(loop=self.loop)
|
||||
self._pending_task = None
|
||||
@ -58,47 +58,36 @@ class Shard:
|
||||
def complete_pending_reads(self):
|
||||
self._pending.set()
|
||||
|
||||
def _pending_reads(self):
|
||||
async def _pending_reads(self):
|
||||
try:
|
||||
while self.is_pending():
|
||||
yield from self.poll()
|
||||
await self.poll()
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
def launch_pending_reads(self):
|
||||
self._pending_task = compat.create_task(self._pending_reads(), loop=self.loop)
|
||||
self._pending_task = asyncio.ensure_future(self._pending_reads(), loop=self.loop)
|
||||
|
||||
def wait(self):
|
||||
return self._pending_task
|
||||
|
||||
@asyncio.coroutine
|
||||
def poll(self):
|
||||
async def poll(self):
|
||||
try:
|
||||
yield from self.ws.poll_event()
|
||||
await self.ws.poll_event()
|
||||
except ResumeWebSocket as e:
|
||||
log.info('Got a request to RESUME the websocket at Shard ID %s.', self.id)
|
||||
coro = DiscordWebSocket.from_client(self._client, resume=True,
|
||||
shard_id=self.id,
|
||||
session=self.ws.session_id,
|
||||
sequence=self.ws.sequence)
|
||||
self.ws = yield from asyncio.wait_for(coro, timeout=180.0, loop=self.loop)
|
||||
self.ws = await asyncio.wait_for(coro, timeout=180.0, loop=self.loop)
|
||||
|
||||
def get_future(self):
|
||||
if self._current.done():
|
||||
self._current = compat.create_task(self.poll(), loop=self.loop)
|
||||
self._current = asyncio.ensure_future(self.poll(), loop=self.loop)
|
||||
|
||||
return self._current
|
||||
|
||||
@asyncio.coroutine
|
||||
def _ensure_coroutine_connect(gateway, loop):
|
||||
# In 3.5+ websockets.connect does not return a coroutine, but an awaitable.
|
||||
# The problem is that in 3.5.0 and in some cases 3.5.1, asyncio.ensure_future and
|
||||
# by proxy, asyncio.wait_for, do not accept awaitables, but rather futures or coroutines.
|
||||
# By wrapping it up into this function we ensure that it's in a coroutine and not an awaitable
|
||||
# even for 3.5.0 users.
|
||||
ws = yield from websockets.connect(gateway, loop=loop, klass=DiscordWebSocket)
|
||||
return ws
|
||||
|
||||
class AutoShardedClient(Client):
|
||||
"""A client similar to :class:`Client` except it handles the complications
|
||||
of sharding for the user into a more manageable and transparent single
|
||||
@ -149,8 +138,7 @@ class AutoShardedClient(Client):
|
||||
|
||||
self._connection._get_websocket = _get_websocket
|
||||
|
||||
@asyncio.coroutine
|
||||
def _chunker(self, guild, *, shard_id=None):
|
||||
async def _chunker(self, guild, *, shard_id=None):
|
||||
try:
|
||||
guild_id = guild.id
|
||||
shard_id = shard_id or guild.shard_id
|
||||
@ -167,7 +155,7 @@ class AutoShardedClient(Client):
|
||||
}
|
||||
|
||||
ws = self.shards[shard_id].ws
|
||||
yield from ws.send_as_json(payload)
|
||||
await ws.send_as_json(payload)
|
||||
|
||||
@property
|
||||
def latency(self):
|
||||
@ -189,8 +177,7 @@ class AutoShardedClient(Client):
|
||||
"""
|
||||
return [(shard_id, shard.ws.latency) for shard_id, shard in self.shards.items()]
|
||||
|
||||
@asyncio.coroutine
|
||||
def request_offline_members(self, *guilds):
|
||||
async def request_offline_members(self, *guilds):
|
||||
"""|coro|
|
||||
|
||||
Requests previously offline members from the guild to be filled up
|
||||
@ -219,16 +206,16 @@ class AutoShardedClient(Client):
|
||||
_guilds = sorted(guilds, key=lambda g: g.shard_id)
|
||||
for shard_id, sub_guilds in itertools.groupby(_guilds, key=lambda g: g.shard_id):
|
||||
sub_guilds = list(sub_guilds)
|
||||
yield from self._connection.request_offline_members(sub_guilds, shard_id=shard_id)
|
||||
await self._connection.request_offline_members(sub_guilds, shard_id=shard_id)
|
||||
|
||||
@asyncio.coroutine
|
||||
def launch_shard(self, gateway, shard_id):
|
||||
async def launch_shard(self, gateway, shard_id):
|
||||
try:
|
||||
ws = yield from asyncio.wait_for(_ensure_coroutine_connect(gateway, self.loop), loop=self.loop, timeout=180.0)
|
||||
coro = websockets.connect(gateway, loop=self.loop, klass=DiscordWebSocket)
|
||||
ws = await asyncio.wait_for(coro, loop=self.loop, timeout=180.0)
|
||||
except Exception as e:
|
||||
log.info('Failed to connect for shard_id: %s. Retrying...', shard_id)
|
||||
yield from asyncio.sleep(5.0, loop=self.loop)
|
||||
return (yield from self.launch_shard(gateway, shard_id))
|
||||
await asyncio.sleep(5.0, loop=self.loop)
|
||||
return (await self.launch_shard(gateway, shard_id))
|
||||
|
||||
ws.token = self.http.token
|
||||
ws._connection = self._connection
|
||||
@ -240,31 +227,30 @@ class AutoShardedClient(Client):
|
||||
|
||||
try:
|
||||
# OP HELLO
|
||||
yield from asyncio.wait_for(ws.poll_event(), loop=self.loop, timeout=180.0)
|
||||
yield from asyncio.wait_for(ws.identify(), loop=self.loop, timeout=180.0)
|
||||
await asyncio.wait_for(ws.poll_event(), loop=self.loop, timeout=180.0)
|
||||
await asyncio.wait_for(ws.identify(), loop=self.loop, timeout=180.0)
|
||||
except asyncio.TimeoutError:
|
||||
log.info('Timed out when connecting for shard_id: %s. Retrying...', shard_id)
|
||||
yield from asyncio.sleep(5.0, loop=self.loop)
|
||||
return (yield from self.launch_shard(gateway, shard_id))
|
||||
await asyncio.sleep(5.0, loop=self.loop)
|
||||
return (await self.launch_shard(gateway, shard_id))
|
||||
|
||||
# keep reading the shard while others connect
|
||||
self.shards[shard_id] = ret = Shard(ws, self)
|
||||
ret.launch_pending_reads()
|
||||
yield from asyncio.sleep(5.0, loop=self.loop)
|
||||
await asyncio.sleep(5.0, loop=self.loop)
|
||||
|
||||
@asyncio.coroutine
|
||||
def launch_shards(self):
|
||||
async def launch_shards(self):
|
||||
if self.shard_count is None:
|
||||
self.shard_count, gateway = yield from self.http.get_bot_gateway()
|
||||
self.shard_count, gateway = await self.http.get_bot_gateway()
|
||||
else:
|
||||
gateway = yield from self.http.get_gateway()
|
||||
gateway = await self.http.get_gateway()
|
||||
|
||||
self._connection.shard_count = self.shard_count
|
||||
|
||||
shard_ids = self.shard_ids if self.shard_ids else range(self.shard_count)
|
||||
|
||||
for shard_id in shard_ids:
|
||||
yield from self.launch_shard(gateway, shard_id)
|
||||
await self.launch_shard(gateway, shard_id)
|
||||
|
||||
shards_to_wait_for = []
|
||||
for shard in self.shards.values():
|
||||
@ -272,21 +258,19 @@ class AutoShardedClient(Client):
|
||||
shards_to_wait_for.append(shard.wait())
|
||||
|
||||
# wait for all pending tasks to finish
|
||||
yield from utils.sane_wait_for(shards_to_wait_for, timeout=300.0, loop=self.loop)
|
||||
await utils.sane_wait_for(shards_to_wait_for, timeout=300.0, loop=self.loop)
|
||||
|
||||
@asyncio.coroutine
|
||||
def _connect(self):
|
||||
yield from self.launch_shards()
|
||||
async def _connect(self):
|
||||
await self.launch_shards()
|
||||
|
||||
while True:
|
||||
pollers = [shard.get_future() for shard in self.shards.values()]
|
||||
done, pending = yield from asyncio.wait(pollers, loop=self.loop, return_when=asyncio.FIRST_COMPLETED)
|
||||
done, pending = await asyncio.wait(pollers, loop=self.loop, return_when=asyncio.FIRST_COMPLETED)
|
||||
for f in done:
|
||||
# we wanna re-raise to the main Client.connect handler if applicable
|
||||
f.result()
|
||||
|
||||
@asyncio.coroutine
|
||||
def close(self):
|
||||
async def close(self):
|
||||
"""|coro|
|
||||
|
||||
Closes the connection to discord.
|
||||
@ -298,16 +282,15 @@ class AutoShardedClient(Client):
|
||||
|
||||
for vc in self.voice_clients:
|
||||
try:
|
||||
yield from vc.disconnect()
|
||||
await vc.disconnect()
|
||||
except:
|
||||
pass
|
||||
|
||||
to_close = [shard.ws.close() for shard in self.shards.values()]
|
||||
yield from asyncio.wait(to_close, loop=self.loop)
|
||||
yield from self.http.close()
|
||||
await asyncio.wait(to_close, loop=self.loop)
|
||||
await self.http.close()
|
||||
|
||||
@asyncio.coroutine
|
||||
def change_presence(self, *, activity=None, status=None, afk=False, shard_id=None):
|
||||
async def change_presence(self, *, activity=None, status=None, afk=False, shard_id=None):
|
||||
"""|coro|
|
||||
|
||||
Changes the client's presence.
|
||||
@ -355,12 +338,12 @@ class AutoShardedClient(Client):
|
||||
|
||||
if shard_id is None:
|
||||
for shard in self.shards.values():
|
||||
yield from shard.ws.change_presence(activity=activity, status=status, afk=afk)
|
||||
await shard.ws.change_presence(activity=activity, status=status, afk=afk)
|
||||
|
||||
guilds = self._connection.guilds
|
||||
else:
|
||||
shard = self.shards[shard_id]
|
||||
yield from shard.ws.change_presence(activity=activity, status=status, afk=afk)
|
||||
await shard.ws.change_presence(activity=activity, status=status, afk=afk)
|
||||
guilds = [g for g in self._connection.guilds if g.shard_id == shard_id]
|
||||
|
||||
for guild in guilds:
|
||||
|
Reference in New Issue
Block a user