Gateway#
Gateway quickstart#
Hint
We recommend that you read the Making requests tutorial before this, as we will not explain HTTP concepts here.
Hint
The finished example can be found here
Note
We will use await at the top level here as it’s easier to explain. For your own code, please use an async function.
If you want a example of how it can be done in an async function, see the full example.
Setting up#
import asyncio
from os import environ
from typing import cast
from discord_typings import MessageData
from nextcore.gateway import ShardManager
from nextcore.http import BotAuthentication, HTTPClient, Route
# Constants
AUTHENTICATION = BotAuthentication(environ["TOKEN"])
Intents#
Discord uses intents to select what you want to be received from the gateway to reduce wasted resources. This is done via bitflags.
A list of intents can be found on the intents page
In this example we want the message intent, and the message content intent.
GUILD_MESSAGES_INTENT = 1 << 9
MESSAGE_CONTENT_INTENT = 1 << 15
Note
This can also be stored in binary representation.
GUILD_MESSAGES_INTENT = 0b1000000000
MESSAGE_CONTENT_INTENT = 0b1000000000000000
If you want to use multiple intents, you can combine them using bitwise or (|
).
INTENTS = GUILD_MESSAGES_INTENT | MESSAGE_CONTENT_INTENT
Now just give it to the ShardManager
.
http_client = HTTPClient()
shard_manager = ShardManager(AUTHENTICATION, INTENTS, http_client)
Note
Discord marks the MESSAGE_CONTENT_INTENT
as “privileged”, meaning you have to turn on a switch in the developer portal
Creating a listener#
Lets create a listener for whenever someone sends a message
A list of events can be found on the Receive events page
@shard_manager.event_dispatcher.listen("MESSAGE_CREATE")
async def on_message(message: MessageData):
# This function will be called every time a message is sent.
Now just check if someone said ping
and respond with pong
if message["content"] == "ping":
# Send a pong message to respond.
route = Route("POST", "/channels/{channel_id}/messages", channel_id=message["channel_id"])
await http_client.request(
route,
rate_limit_key=AUTHENTICATION.rate_limit_key,
json={"content": "pong"},
headers=AUTHENTICATION.headers,
)
Hint
Confused by this? Check out the Making requests tutorial!
Connecting to Discord#
await http_client.setup()
await shard_manager.connect()
Warning
HTTPClient.setup()
needs to be called before ShardManager.connect()
Note
ShardManager.connect()
will return once every shard has started to connect
Stopping the script from stopping#
Since the ShardManager.connect()
function returns once every shard has started to connect, the script closes as the main thread has nothing to do.
We can wait for a critical error before closing to fix this.
(error,) = await shard_manager.dispatcher.wait_for(lambda: True, "critical")
raise cast(Exception, error)
Note
The weird (error, )
thing is to extract the first element out of the tuple.
Continuing#
We suggest that you look into interactions & application commands as your next topic. They allow you to add buttons and slash commands and other cool stuff!
Gateway reference#
- class nextcore.gateway.ShardManager(authentication, intents, http_client, *, shard_count=None, shard_ids=None, presence=None)#
A automatic sharder implementation
- Parameters:
authentication (BotAuthentication) – Authentication info.
intents (int) – The intents the bot should connect with. See the documentation.
http_client (HTTPClient) – The HTTP client to use for fetching info to connect to the gateway.
shard_count (int | None) – The amount of shards the bot should spawn. If this is not set, the bot will automatically decide and keep the shard count up to date.
shard_ids (list[int] | None) – The shard ids the bot should spawn. If this is not set, the bot will use all shard ids possible with the
ShardManager.shard_count
. This requiresShardManager.shard_count
to be set.presence (UpdatePresenceData | None) – The initial presence the bot should connect with.
- token#
The bot’s token
- intents#
The intents the bot should connect with. See the documentation.
- shard_count#
The amount of shards the bot should spawn. If this is not set, the bot will automatically decide and keep the shard count up to date.
- shard_ids#
The shard ids the bot should spawn. If this is not set, the bot will use all shard ids possible with the
ShardManager.shard_count
. This requiresShardManager.shard_count
to be set.
- presence#
The initial presence the bot should connect with.
- active_shards#
A list of all shards that are currently connected.
- raw_dispatcher#
A dispatcher with raw payloads sent by discord. The event name is the opcode, and the value is the raw data.
- event_dispatcher#
A dispatcher for DISPATCH events sent by discord. The event name is the event name, and the value is the inner payload.
- max_concurrency#
The maximum amount of concurrent IDENTIFY’s the bot can make.
- async connect()#
Connect all the shards to the gateway.
Note
This will return once all shards have started connecting.
Note
This will do a request to
GET /gateway/bot
- Raises:
RuntimeError – Already connected.
- Return type:
None
- async rescale_shards(shard_count, shard_ids=None)#
Change the shard count without restarting
This slowly changes the shard count.
Warning
You can only change the shard count once at a time
- Parameters:
- Raises:
RuntimeError – You can only run rescale_shards once at a time.
RuntimeError – You need to use
ShardManager.connect()
first.
- Return type:
None
- class nextcore.gateway.Shard(shard_id, shard_count, intents, token, identify_rate_limiter, http_client, *, presence=None, large_threshold=None, library_name='nextcore')#
A shard connection to the Discord gateway
- Parameters:
shard_id (int) – The ID of this shard.
shard_count (int) – How many shards is in this shard set. Used for splitting events on Discord’s side.
intents (int) – The intents to connect with.
token (str) – The bot’s token to connect with.
identify_rate_limiter (TimesPer) – The rate limiter for IDENTIFYing the bot.
http_client (HTTPClient) – HTTP client used to connect to Discord’s gateway.
presence (UpdatePresenceData | None) – The initial presence info to send when connecting.
large_threshold (int | None) – A value between 50 and 250 that determines how many members a guild needs for the gateway to stop sending offline members in the guild member list.
library_name (str) – The name of the library that is using this gateway. This should be set if you are making your own library on top of nextcore.
- shard_id#
The ID of this shard.
- shard_count#
How many shards are in this shard set. Used for splitting events on Discord’s side.
- intents#
The intents to connect with.
- token#
The bot’s token to connect with. If this is changed, the session will be invalidated.
- presence#
The initial presence info to send when connecting.
- large_threshold#
A value between 50 and 250 that determines how many members a guild needs for the gateway to stop sending offline members in the guild member list.
- library_name#
The name of the library that is using this gateway. This should be set if you are making your own library on top of nextcore.
- connected#
When this shard is connected to the gateway, but not identified yet.
This also requires the gateway to send the HELLO <https://discord.dev/topics/gateway-events#hello> event, as rate-limiters are not setup yet.
- ready#
Fires when the gateway has connected and received the READY event.
- raw_dispatcher#
A dispatcher with raw payloads sent by discord. The event name is the opcode, and the value is the raw data.
- event_dispatcher#
A dispatcher for DISPATCH events sent by discord. The event name is the event name, and the value is the inner payload.
- dispatcher#
A dispatcher for internal events.
- session_id#
The ID of the current session.
- session_sequence_number#
The last sequence number of the current session.
- should_reconnect#
Whether the gateway should reconnect or not.
- async close(*, cleanup=True)#
Close the connection to the gateway and destroy the session.
Note
This will dispatch a
client_disconnect
event.- Parameters:
cleanup (bool) – Whether to close the Discord session. This will stop you from being able to resume, but also remove the bots status faster.
- Return type:
None
- async connect()#
Connect to the gateway
Note
This will try to automatically resume if a session is set.
Warning
This might not have fully completed at the end of this call as re-connects will be done in the background.
- Raises:
ReconnectCheckFailedError –
Shard.should_reconnect
was set toFalse
and aShard.identify()
call was needed.RuntimeError – We are already reconnecting.
- Return type:
None
- property latency: float#
Time in seconds between a heartbeat being sent and discord acknowledging it.
- Raises:
RuntimeError – Not connected to the gateway.
RuntimeError – Not heartbeated yet.
- async presence_update(presence)#
Changes the bot’s presence for the current session.
- Parameters:
presence (UpdatePresenceData) –
- Return type:
None
- async request_guild_members(guild_id: str | int, *, query: str, limit: int, presences: bool | nextcore.common.undefined.UndefinedType = UNDEFINED, user_ids: str | int | list[str | int] | nextcore.common.undefined.UndefinedType = UNDEFINED, nonce: str | nextcore.common.undefined.UndefinedType = UNDEFINED) None #
- async request_guild_members(guild_id: str | int, *, limit: int | nextcore.common.undefined.UndefinedType = UNDEFINED, presences: bool | nextcore.common.undefined.UndefinedType = UNDEFINED, user_ids: str | int | list[str | int], nonce: str | nextcore.common.undefined.UndefinedType = UNDEFINED) None
Request info about the members in this guild.
Note
This will dispatch
GUILD_MEMBERS_CHUNK
events as a response.Warning
This may be cancelled if the shard disconnects while chunking.
- Parameters:
guild_id – The guild to request members from
query –
What the members username have to start with to be returned
Note
If this is not empty limit will be max 100.
limit –
The max amount of members to return.
Note
This can be 0 when used with a empty query.
If this is 0, this would require the
GUILD_MEMBERS
intentpresences –
Whether to include presences for members requested.
Note
This requires the
GUILD_PRESENCES
intent.user_ids –
The ID of the members to query.
Note
This has a limit of 100 members.
nonce –
A string which will be provided in the
guild members chunk
response to identify this request.Note
This is max 32 characters.
If it is longer it will be ignored.
- async voice_state_update(update)#
Updates the voice state of the logged in user.
This is per guild.
- Parameters:
update (UpdateVoiceStateData) –
- class nextcore.gateway.GatewayOpcode(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)#
Enum of all opcodes that can be sent/received to/from the gateway.
- DISPATCH = 0#
Can be received
- HEARTBEAT = 1#
Can be sent/received
- HEARTBEAT_ACK = 11#
Can be received
- HELLO = 10#
Can be received
- IDENTIFY = 2#
Can be sent
- INVALID_SESSION = 9#
Can be received
- PRESENCE_UPDATE = 3#
Can be sent
- RECONNECT = 7#
Can be received
- REQUEST_GUILD_MEMBERS = 8#
Can be sent
- RESUME = 6#
Can be sent
- VOICE_STATE_UPDATE = 4#
Can be sent
- class nextcore.gateway.Decompressor#
A wrapper around zlib to handle partial payloads
Example usage
from nextcore.gateway import Decompressor decompressor = Decompressor() data = decompressor.decompress(zlib_data) # bytes from the Discord gateway print(data.decode("utf-8"))
- decompress(data)#
Decompress zlib data.
Example usage:
from nextcore.gateway import Decompressor decompressor = Decompressor() data = decompressor.decompress(zlib_data) # bytes from the Discord gateway print(data.decode("utf-8"))
- Parameters:
data (bytes) – The zlib compressed bytes.
- Returns:
The decompressed data.
This is
None
if this is a partial payload.- Return type:
- Raises:
ValueError – This is not zlib compressed data. The data could also be corrupted.
Gateway errors#
- exception nextcore.gateway.ReconnectCheckFailedError#
Error for when auto reconnect is set to False and the shard needs to IDENTIFY
- Return type:
None
- exception nextcore.gateway.DisconnectError#
A unexpected disconnect from the gateway happened.
- exception nextcore.gateway.InvalidIntentsError#
The intents provided are invalid.
- Return type:
None
- exception nextcore.gateway.DisallowedIntentsError#
The intents provided are disallowed.
- Return type:
None
- exception nextcore.gateway.InvalidTokenError#
The token provided is invalid.
- Return type:
None
- exception nextcore.gateway.InvalidApiVersionError#
The api version provided is invalid.
- Return type:
None
- exception nextcore.gateway.InvalidShardCountError#
The shard count provided is invalid.
- Return type:
None