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 requires ShardManager.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 requires ShardManager.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:
  • shard_count (int) – The shard count to change to.

  • shard_ids (list[int] | None) – Shards to start. If it is set to None, this will use all shards up to the shard count.

Raises:
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:
Return type:

None

property latency: float#

Time in seconds between a heartbeat being sent and discord acknowledging it.

Raises:
async presence_update(presence)#

Changes the bot’s presence for the current session.

Warning

This will not persist across sessions!

Use the presence parameter to Shard

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 intent

  • presences

    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:

bytes | None

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

exception nextcore.gateway.UnhandledCloseCodeError(code)#

The close code provided is unknown to the library and as such it cannot be handled properly.

Parameters:

code (int) – The close code.

Return type:

None

code#

The close code.

Type:

int