|
53 | 53 |
|
54 | 54 |
|
55 | 55 | class AiohttpAdapter(BaseAdapter, web.Application): |
| 56 | + """The AiohttpAdapter for OAuth and Webhook based EventSub. |
| 57 | +
|
| 58 | + This adapter uses ``aiohttp`` which is a base dependency and should be installed and available with Twitchio. |
| 59 | +
|
| 60 | + Optionally you can use `Starlette <https://www.starlette.io/>`_ with `Uvicorn <https://www.uvicorn.org/>`_ by using the |
| 61 | + :class:`StarletteAdapter`. This will require additional dependencies. |
| 62 | +
|
| 63 | + An adapter will always be started and is ran alongside the :class:`~twitchio.Client` or |
| 64 | + :class:`~twitchio.ext.commands.Bot` by default. You can disable starting the adapter by passing ``with_adapter=False`` |
| 65 | + to :meth:`twitchio.Client.start` or :meth:`twitchio.Client.run`. |
| 66 | +
|
| 67 | + The adapter can be used to authenticate users via OAuth, and supports webhooks for EventSub, with in-built event |
| 68 | + dispatching to the :class:`~twitchio.Client`. |
| 69 | +
|
| 70 | + The default callbacks for OAuth are: |
| 71 | +
|
| 72 | + - ``/oauth`` E.g. ``http://localhost:4343/oauth`` or ``https://mydomain.org/oauth``. |
| 73 | + - Should be used with the ``?scopes=`` query parameter to pass a URL encoded list of scopes. |
| 74 | + See: :class:`~twitchio.Scopes` for a helper class for generating scopes. |
| 75 | +
|
| 76 | + - ``/oauth/callback`` E.g. ``http://localhost:4343/oauth/callback`` or ``https://mydomain.org/oauth/callback``. |
| 77 | + - The redirect URL for OAuth request. This should be set in the developer console of your application on Twitch. |
| 78 | +
|
| 79 | + The default callbacks for EventSub are: |
| 80 | +
|
| 81 | + - ``/callback`` E.g. ``http://localhost:4343/callback`` or ``https://mydomain.org/callback``. |
| 82 | +
|
| 83 | +
|
| 84 | + This class handles processing and validating EventSub requests for you, and dispatches any events identical to |
| 85 | + the websocket equivalent. |
| 86 | +
|
| 87 | + Parameters |
| 88 | + ---------- |
| 89 | + host: str | None |
| 90 | + An optional :class:`str` passed to bind as the host address. Defaults to ``localhost``. |
| 91 | + port: int | None |
| 92 | + An optional :class:`int` passed to bind as the port for the host address. Defaults to ``4343``. |
| 93 | + domain: str | None |
| 94 | + An optional :class:`str` passed used to identify the external domain used, if any. If passed, the domain will be used |
| 95 | + for the redirect URL in OAuth and for validation in EventSub. It must be publicly accessible and support HTTPS. |
| 96 | + eventsub_path: str | None |
| 97 | + An optional :class:`str` passed to use as the path to the eventsub callback. Defaults to ``/callback``. E.g. |
| 98 | + ``http://localhost:4343/callback`` or ``https://mydomain.org/callback``. |
| 99 | + eventsub_secret: str | None |
| 100 | + An optional :class:`str` passed to use as the EventSub secret. It is recommended you pass this parameter when using |
| 101 | + an adapter for EventSub, as it will reset upon restarting otherwise. You can generate token safe secrets with the |
| 102 | + :mod:`secrets` module. |
| 103 | +
|
| 104 | + Examples |
| 105 | + -------- |
| 106 | +
|
| 107 | + .. code-block:: python3 |
| 108 | +
|
| 109 | + import twitchio |
| 110 | + from twitchio import web |
| 111 | + from twitchio.ext import commands |
| 112 | +
|
| 113 | +
|
| 114 | + class Bot(commands.Bot): |
| 115 | +
|
| 116 | + def __init__(self) -> None: |
| 117 | + # Requests will be sent to, as an example: |
| 118 | + # http://bot.twitchio.dev |
| 119 | + # You DO NOT need to pass a domain, however not passing a domain will mean only you can authenticate |
| 120 | + # via OAuth and Webhooks will not be supported... |
| 121 | + # The domain should support HTTPS and be publicly accessible... |
| 122 | + # An easy way to do this is add your domain to a CDN like Cloudflare and set SSL to Flexible. |
| 123 | + # |
| 124 | + # Visit: http://localhost:8080/oauth?scopes=channel:bot as the broadcaster as an example. |
| 125 | + # Visit: https://bot.twitchio.dev?scopes=channel:bot as the broadcaster as an example. |
| 126 | +
|
| 127 | + adapter = web.AiohttpAdapter(domain="bot.twitchio.dev", port=8080) |
| 128 | + super().__init__(adapter=adapter) |
| 129 | + """ |
| 130 | + |
56 | 131 | client: Client |
57 | 132 |
|
58 | 133 | def __init__( |
@@ -99,10 +174,12 @@ def __init_subclass__(cls: type[AiohttpAdapter]) -> None: |
99 | 174 |
|
100 | 175 | @property |
101 | 176 | def eventsub_url(self) -> str: |
| 177 | + """Property returning the fully qualified URL to the EventSub callback.""" |
102 | 178 | return f"{self._domain}{self._eventsub_path}" |
103 | 179 |
|
104 | 180 | @property |
105 | 181 | def redirect_url(self) -> str: |
| 182 | + """Property returning the fully qualified URL to the OAuth callback.""" |
106 | 183 | return f"{self._domain}/oauth/callback" |
107 | 184 |
|
108 | 185 | async def event_startup(self) -> None: |
@@ -165,7 +242,6 @@ async def eventsub_callback(self, request: web.Request) -> web.Response: |
165 | 242 | except Exception as e: |
166 | 243 | return web.Response(text=f"Challenge Failed. Failed to verify the integrity of the message: {e}", status=400) |
167 | 244 |
|
168 | | - # TODO: Types... |
169 | 245 | data: Any = _from_json(resp) # type: ignore |
170 | 246 | sent: datetime.datetime = parse_timestamp(timestamp) |
171 | 247 | now: datetime.datetime = datetime.datetime.now(tz=datetime.UTC) |
|
0 commit comments