Skip to content

Commit

Permalink
Simplify and improve rest lifetime (#1230)
Browse files Browse the repository at this point in the history
Signed-off-by: davfsa <davfsa@gmail.com>
  • Loading branch information
davfsa authored Jan 1, 2023
1 parent 6a6ddf7 commit fe83246
Show file tree
Hide file tree
Showing 14 changed files with 1,038 additions and 999 deletions.
1 change: 1 addition & 0 deletions changes/1230.breaking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`RESTApp` and `RESTBucketManager` now need to be started and stopped by using `.start` and `.close`.
1 change: 1 addition & 0 deletions changes/1230.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Buckets across different authentications are not shared any more, which would lead to incorrect rate limiting.
5 changes: 5 additions & 0 deletions changes/1230.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
`RESTClientImpl` improvements:
- You can now share client sessions and bucket managers across these objects or have them created for you.
- Speedup of request lifetime
- No-ratelimit routes no longer attempt to acquire rate limits
- Just for safety, a check is in place to treat the route as a rate limited route if a bucket is ever received for it and a error log is emitted. If you spot it around, please inform us!
78 changes: 78 additions & 0 deletions examples/oauth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
# Hikari Examples - A collection of examples for Hikari.
#
# To the extent possible under law, the author(s) have dedicated all copyright
# and related and neighboring rights to this software to the public domain worldwide.
# This software is distributed without any warranty.
#
# You should have received a copy of the CC0 Public Domain Dedication along with this software.
# If not, see <https://creativecommons.org/publicdomain/zero/1.0/>.
"""An example OAuth server."""
import logging
import os

from aiohttp import web

import hikari

logging.basicConfig(level=logging.DEBUG)

host = "localhost"
port = 8080
CLIENT_ID = int(os.environ["CLIENT_ID"]) # ID as an int
CLIENT_SECRET = os.environ["CLIENT_SECRET"] # Secret as a str
BOT_TOKEN = os.environ["BOT_TOKEN"] # Token as a str
CHANNEL_ID = int(os.environ["CHANNEL_ID"]) # Channel to post in as an int
REDIRECT_URI = "http://localhost:8080"

route_table = web.RouteTableDef()


@route_table.get("/")
async def oauth(request: web.Request) -> web.Response:
"""Handle an OAuth request."""
code = request.query.get("code")
if not code:
return web.json_response({"error": "'code' is not provided"}, status=400)

discord_rest: hikari.RESTApp = request.app["discord_rest"]

# Exchange code to acquire a Bearer one for the user
async with discord_rest.acquire(None) as r:
auth = await r.authorize_access_token(CLIENT_ID, CLIENT_SECRET, code, REDIRECT_URI)

# Perform a request as the user to get their own user object
async with discord_rest.acquire(auth.access_token, hikari.TokenType.BEARER) as client:
user = await client.fetch_my_user()
# user is a hikari.OwnUser object where we can access attributes on it

# Notify the success
async with discord_rest.acquire(BOT_TOKEN, hikari.TokenType.BOT) as client:
await client.create_message(CHANNEL_ID, f"{user} ({user.id}) just authorized!")

return web.Response(text="Successfully authenticated!")


async def start_discord_rest(app: web.Application) -> None:
"""Start the RESTApp."""
discord_rest = hikari.RESTApp()
await discord_rest.start()

app["discord_rest"] = discord_rest


async def stop_discord_rest(app: web.Application) -> None:
"""Stop the RESTApp."""
discord_rest: hikari.RESTApp = app["discord_rest"]

await discord_rest.close()


if __name__ == "__main__":
server = web.Application()
server.add_routes(route_table)

server.on_startup.append(start_discord_rest)
server.on_cleanup.append(stop_discord_rest)

web.run_app(server, host=host, port=port)
39 changes: 19 additions & 20 deletions hikari/impl/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,21 @@ def _validate_activity(activity: undefined.UndefinedNoneOr[presences.Activity])
)


async def _close_resource(name: str, awaitable: typing.Awaitable[typing.Any]) -> None:
future = asyncio.ensure_future(awaitable)

try:
await future
except Exception as ex:
asyncio.get_running_loop().call_exception_handler(
{
"message": f"{name} raised an exception during shut down",
"future": future,
"exception": ex,
}
)


class GatewayBot(traits.GatewayBotAware):
"""Basic auto-sharding bot implementation.
Expand Down Expand Up @@ -288,7 +303,7 @@ def __init__(
intents: intents_.Intents = intents_.Intents.ALL_UNPRIVILEGED,
auto_chunk_members: bool = True,
logs: typing.Union[None, int, str, typing.Dict[str, typing.Any]] = "INFO",
max_rate_limit: float = 300,
max_rate_limit: float = 300.0,
max_retries: int = 3,
proxy_settings: typing.Optional[config_impl.ProxySettings] = None,
rest_url: typing.Optional[str] = None,
Expand Down Expand Up @@ -426,30 +441,14 @@ async def close(self) -> None:
await self._event_manager.dispatch(self._event_factory.deserialize_stopping_event())
_LOGGER.log(ux.TRACE, "StoppingEvent dispatch completed, now beginning termination")

loop = asyncio.get_running_loop()

async def handle(name: str, awaitable: typing.Awaitable[typing.Any]) -> None:
future = asyncio.ensure_future(awaitable)

try:
await future
except Exception as ex:
loop.call_exception_handler(
{
"message": f"{name} raised an exception during shut down",
"future": future,
"exception": ex,
}
)

await handle("voice handler", self._voice.close())
await _close_resource("voice handler", self._voice.close())

shards = tuple((handle(f"shard {s.id}", s.close()) for s in self._shards.values() if s.is_alive))
shards = tuple(_close_resource(f"shard {s.id}", s.close()) for s in self._shards.values() if s.is_alive)

for coro in asyncio.as_completed(shards):
await coro

await handle("rest", self._rest.close())
await _close_resource("rest", self._rest.close())

# Clear out cache and shard map
self._cache.clear()
Expand Down
Loading

0 comments on commit fe83246

Please sign in to comment.