diff options
Diffstat (limited to 'discord/client.py')
-rw-r--r-- | discord/client.py | 91 |
1 files changed, 71 insertions, 20 deletions
diff --git a/discord/client.py b/discord/client.py index d6cfd50..5f5c3b0 100644 --- a/discord/client.py +++ b/discord/client.py @@ -3,42 +3,69 @@ from enum import IntEnum import json import sys import threading +import warnings from typing import Optional, Coroutine, Any, Callable import zlib import aiohttp import websockets -from .utils import EventEmitter -from .utils.rest import RESTClient +from .utils import EventEmitter, RESTClient from .intents import Intents, get_number from .user import User + class GatewayEvents(IntEnum): - DISPATCH = 0 - HEARTBEAT = 1 - IDENTIFY = 2 - PRESENCE = 3 - VOICE_STATE = 4 - VOICE_PING = 5 - RESUME = 6 - RECONNECT = 7 - REQUEST_MEMBERS = 8 + """ + Contains constants for the gateway opcodes. + """ + DISPATCH = 0 + """An event was dispatched.""" + HEARTBEAT = 1 + """Sent at regular intervals by the client to keep the gateway connection alive.""" + IDENTIFY = 2 + """Used to identify yourself with the token during the initial handshake.""" + PRESENCE = 3 + """Used to update the client's presence.""" + VOICE_STATE = 4 + """Used to join and leave voice channels.""" + VOICE_PING = 5 + RESUME = 6 + """Used to resume a disconnected session.""" + RECONNECT = 7 + """Used to reconnect to the session.""" + REQUEST_MEMBERS = 8 + """Used to request information about guild members when there are too many for """ INVALIDATE_SESSION = 9 - HELLO = 10 - HEARTBEAT_ACK = 11 - GUILD_SYNC = 12 + """Means that the session is invalid. When this is received, you must reconnect and re-identify.""" + HELLO = 10 + """Acknowledgement of gateway connection.""" + HEARTBEAT_ACK = 11 + """Acknowledgement of gateway heartbeat.""" + GUILD_SYNC = 12 + class Client: + """ + Represents a Discord client (i.e. a bot). + You need to initialise one of these and then use `run()` with a token to login. + """ _token: str @property async def user(self): + """The `discord.user.User` associated with the client.""" data = await self.rest_client.get('/users/@me') return User(data) def __init__(self, intents: list[Intents]): self.gateway = None self.loop = asyncio.get_event_loop() + if Intents.MESSAGE_CONTENT in intents: + warnings.warn("Message Content will become a privileged intent in August 2022. You must enable it in the " + "Discord developer portal.") + if Intents.GUILD_MEMBERS in intents or Intents.GUILD_PRESENCES in intents: + warnings.warn("You are using one or more privileged intent (Guild Members and/or Guild Presences). You " + "must enable them in the Discord developer portal.") self.code: int = get_number(intents) self.event_emitter = EventEmitter() self.buffer = bytearray() @@ -51,18 +78,29 @@ class Client: })) async def connect(self): + """ + Connects to the Discord gateway and begins sending heartbeats. + This should not be called manually. + + **Parameters:** + - token: Your bot token. + - intent_code: The number which represents the `discord.intents.Intents` being used. + """ async with websockets.connect("wss://gateway.discord.gg/?v=10&encoding=json") as gateway: self.gateway = gateway threading.Thread(target=self.loop.run_forever).start() while True: await self.poll_event() - + async def send(self, data: dict): """ Send data to the gateway. + + **Parameters:** + - data: The data to send to the gateway. """ await self.gateway.send(json.dumps(data)) - + async def recv(self, msg): """ Receive data from the gateway. @@ -91,7 +129,7 @@ class Client: if opcode == GatewayEvents.HEARTBEAT_ACK.value: return await self.heartbeat(self.heartbeat_interval) - + if opcode == GatewayEvents.HEARTBEAT.value: return await self.heartbeat(self.heartbeat_interval) @@ -102,7 +140,6 @@ class Client: self.event_emitter.emit('on_' + event.lower()) - async def close(self): """ Close the client. @@ -113,9 +150,16 @@ class Client: async def poll_event(self): msg = await self.gateway.recv() await self.recv(msg) - async def heartbeat(self, interval: int): + """ + Sends a heartbeat through the gateway to keep the connection active. + This should not be called manually. + + **Parameters:** + - gateway: The gateway to keep open. + - interval: How often to send a heartbeat. This is given by the gateway in a Hello packet. + """ await asyncio.sleep(interval / 1000) heartbeat = { "op": 1, @@ -141,9 +185,13 @@ class Client: } await self.send(identify) - def event(self, coro: Optional[Callable[..., Coroutine[Any, Any, Any]]]=None, /) -> Optional[Callable[..., Coroutine[Any, Any, Any]]]: + def event(self, coro: Optional[Callable[..., Coroutine[Any, Any, Any]]] = None, /) -> Optional[ + Callable[..., Coroutine[Any, Any, Any]]]: """ Registers a coroutine to be called when an event is emitted. + + **Parameters:** + - coro: The coroutine to be registered. """ if not asyncio.iscoroutinefunction(coro): raise TypeError('event registered must be a coroutine function') @@ -153,6 +201,9 @@ class Client: def run(self, token: str): """ Run the client. + + **Parameters:** + - token: Your bot token. Do not share this with anyone! """ self._token = token asyncio.run(self.connect()) |