Skip to content

Commit

Permalink
Add gateway intents (#181)
Browse files Browse the repository at this point in the history
* Add intents calculator

* Add intents to identify payload

* Add intents documentation page

* Add link the dev portal docs to gateway intents doc page

* Build gateway intent doc page

* Link to gateway intent doc page from intro

* Reorder alias

* Add intents tests

* Fix a typo spotted by @jchristgit

* Run mix format

* Grammar check on docs
  • Loading branch information
jb3 authored Oct 13, 2020
1 parent 87a5a9a commit 60767ee
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 3 deletions.
100 changes: 100 additions & 0 deletions docs/static/Gateway Intents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Gateway Intents

The Discord API allows you to fine tune the payloads that are received by your bot through gateway intents.

When connecting to Discord you can instruct Discord on which events you want to receive (i.e. messages, user presences, etc.).

Nostrum allows you to set these intents within your configuration, **by default all intents are enabled, including privileged ones**.

To pass intents you should use the following configuration:
```elixir
config :nostrum,
token: "bot_token",
num_shards: :auto,
gateway_intents: [
:guilds,
# other gateway intents
]
```

Possible intents (and the gateway events they correspond to) are:

```
guilds:
- GUILD_CREATE
- GUILD_UPDATE
- GUILD_DELETE
- GUILD_ROLE_CREATE
- GUILD_ROLE_UPDATE
- GUILD_ROLE_DELETE
- CHANNEL_CREATE
- CHANNEL_UPDATE
- CHANNEL_DELETE
- CHANNEL_PINS_UPDATE
guild_members*:
- GUILD_MEMBER_ADD
- GUILD_MEMBER_UPDATE
- GUILD_MEMBER_REMOVE
guild_bans:
- GUILD_BAN_ADD
- GUILD_BAN_REMOVE
guild_emojis:
- GUILD_EMOJIS_UPDATE
guild_integrations:
- GUILD_INTEGRATIONS_UPDATE
guild_webhooks:
- WEBHOOKS_UPDATE
guild_invites:
- INVITE_CREATE
- INVITE_DELETE
guild_voice_states:
- VOICE_STATE_UPDATE
guild_presences*:
- PRESENCE_UPDATE
guild_messages:
- MESSAGE_CREATE
- MESSAGE_UPDATE
- MESSAGE_DELETE
- MESSAGE_DELETE_BULK
guild_message_reactions:
- MESSAGE_REACTION_ADD
- MESSAGE_REACTION_REMOVE
- MESSAGE_REACTION_REMOVE_ALL
- MESSAGE_REACTION_REMOVE_EMOJI
guild_message_typing:
- TYPING_START
direct_messages:
- MESSAGE_CREATE
- MESSAGE_UPDATE
- MESSAGE_DELETE
- CHANNEL_PINS_UPDATE
direct_message_reactions:
- MESSAGE_REACTION_ADD
- MESSAGE_REACTION_REMOVE
- MESSAGE_REACTION_REMOVE_ALL
- MESSAGE_REACTION_REMOVE_EMOJI
direct_message_typing:
- TYPING_START
```

Note that intents marked with `*` are **privileged** intents. You must enable these intents by visiting the Discord Developer portal.

Once your bot passes 100 servers Discord will force you to **verify your bot**. If you require privileged intents you may need to write additional information on your usage of them.

Be advised that since Nostrum defaults to all intents being enabled you may need to disable these intents by adding everything else in the above list to the `gateway_intents` configuration option.

More information on gateway intents can be found in the [Discord Developer documentation](https://discord.com/developers/docs/topics/gateway#gateway-intents).
1 change: 1 addition & 0 deletions docs/static/Intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ you can omit the field and it will default to 1. You can also set this option to

The following fields are also supported:

- `gateway_intents` - This field takes a list of atoms representing gateway intents for Nostrum to subscribe to from the Discord API. More information can be found in the [gateway intents](gateway-intents.html) documentation page.
- `dev` - This is added to enable Nostrum to be run completely stand alone for
development purposes. `true` will cause Nostrum to spawn its own event consumers.
If you have the dev flag set to true while running Nostrum alongside your
Expand Down
48 changes: 48 additions & 0 deletions lib/nostrum/shard/intents.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
defmodule Nostrum.Shard.Intents do
@moduledoc false

import Bitwise

@spec intent_values :: [{atom, integer()}, ...]
def intent_values do
[
guilds: 1 <<< 0,
guild_members: 1 <<< 1,
guild_bans: 1 <<< 2,
guild_emojis: 1 <<< 3,
guild_integrations: 1 <<< 4,
guild_webhooks: 1 <<< 5,
guild_invites: 1 <<< 6,
guild_voice_states: 1 <<< 7,
guild_presences: 1 <<< 8,
guild_messages: 1 <<< 9,
guild_message_reactions: 1 <<< 10,
guild_message_typing: 1 <<< 11,
direct_messages: 1 <<< 12,
direct_message_reactions: 1 <<< 13,
direct_message_typing: 1 <<< 14
]
end

@spec get_enabled_intents :: integer()
def get_enabled_intents do
enabled_intents = Application.get_env(:nostrum, :gateway_intents)

# If no intents are passed in config, default to all being enabled.
if enabled_intents do
get_intent_value(enabled_intents)
else
get_intent_value(Keyword.keys(intent_values()))
end
end

@spec get_intent_value([atom()]) :: integer
def get_intent_value(enabled_intents) do
Enum.reduce(enabled_intents, 0, fn intent, intents ->
case intent_values()[intent] do
nil -> raise "Invalid intent specified: #{intent}"
value -> intents ||| value
end
end)
end
end
5 changes: 3 additions & 2 deletions lib/nostrum/shard/payload.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Nostrum.Shard.Payload do
@moduledoc false

alias Nostrum.{Constants, Util}
alias Nostrum.{Constants, Shard.Intents, Util}

@large_threshold 250

Expand All @@ -26,7 +26,8 @@ defmodule Nostrum.Shard.Payload do
},
"compress" => false,
"large_threshold" => @large_threshold,
"shard" => [state.shard_num, Util.num_shards()]
"shard" => [state.shard_num, Util.num_shards()],
"intents" => Intents.get_enabled_intents()
}
|> build_payload("IDENTIFY")
end
Expand Down
3 changes: 2 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ defmodule Nostrum.Mixfile do
"docs/static/API.md",
"docs/static/State.md",
"docs/static/Events.md",
"docs/static/Consumers.md"
"docs/static/Consumers.md",
"docs/static/Gateway Intents.md"
]
end

Expand Down
54 changes: 54 additions & 0 deletions test/nostrum/shard/intents_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
defmodule Nostrum.Shard.IntentsTest do
use ExUnit.Case, async: true

alias Nostrum.Shard.Intents

describe "get_enabled_intents/0" do
test "returns all intents enabled when no intents are set" do
Application.put_env(:nostrum, :gateway_intents, nil)

result = Intents.get_enabled_intents()

# Value of all intents
expected = 32767

assert(^result = expected)
end

test "returns 0 when no intents are enabled" do
Application.put_env(:nostrum, :gateway_intents, [])

result = Intents.get_enabled_intents()

expected = 0

assert(^result = expected)
end

test "returns 1 when guild intent is enabled" do
Application.put_env(:nostrum, :gateway_intents, [:guilds])

result = Intents.get_enabled_intents()

expected = 1

assert(^result = expected)
end
end

describe "get_intent_value/1" do
test "returns 1 when guild intent is enabled" do
result = Intents.get_intent_value([:guilds])

expected = 1

assert(^result = expected)
end

test "raises exception when invalid intent is passed" do
assert_raise(RuntimeError, "Invalid intent specified: craig_cat", fn ->
Intents.get_intent_value([:guilds, :craig_cat])
end)
end
end
end

0 comments on commit 60767ee

Please # to comment.