Nostrum Versions Save

Elixir Discord Library

v0.9.1

1 week ago

Welcome to Nostrum 0.9.1, code-named "Trajectory Correction".

image

We're proud to announce the latest all-American release of Nostrum 0.9.1, a bugfix bonanza built with the spirit of liberty in mind. Covering bugfixes to new features to countless documentation improvements, upgrade today to harness the power of the American dream in your Discord applications.

Breaking Changes

  • Remove Nostrum.Api.get_token by @jchristgit in https://github.com/Kraigie/nostrum/pull/569
    • As Nostrum moves to support multiple bots / library usage functionality like this is not desirable and as such as are removing features like this.
    • This field is set by the user anyway, so there are other methods to fetch this without depending on library functionality.
  • Implement memory optimizations in user struct by @jchristgit in https://github.com/Kraigie/nostrum/pull/567
    • Removes automatic parsing of the flags attribute of User structs, but the Nostrum.Struct.User.Flags struct still exists to allow users to optionally parse this value themselves.
    • This change saves considerable storage in cache as we are now able to store the flags as the integer we receive them as from Discord instead of in a custom struct with a large number of attributes.
    • This PR also removes the mfa_enabled, verified and email attributes that would only be set with OAuth2. We do not expect anyone writing regular bots to have any dependence on these properties.

Features

  • Add missing fields from member API object by @jb3 in https://github.com/Kraigie/nostrum/pull/573
    • Adds the pending, flags and avatar (custom guild avatar) attributes to Member struct
    • Also adds a helper method avatar_url/3 to the Member struct for fetching guild member custom avatars.
    • Adds a helper module Nostrum.Struct.Guild.Member.Flags for parsing flag values related to member onboarding.

Fixes

Documentation and Debug

Miscellaneous

Full Changelog: https://github.com/Kraigie/nostrum/compare/v0.9.0...v0.9.1

v0.9.0

3 weeks ago

image

Welcome to Nostrum 0.9.0, code-named "Return to Flight"!

This update isn't just another runway hop; it's a potential moon mission for bot functionality. Expect smoother performance than a high-end sports car on a freshly paved racetrack, and features so innovative they'll make even the most jaded bot user do a happy dance. Alchemists, you have my assurance that with Nostrum 0.9.0, "return to flight" isn't just a codename, it's a promise of soaring possibilities.

After a 324 day hiatus since the release of Nostrum 0.8.0, the new latest release ships with new features, performance improvements and much more, all of which are broken down below.

A full changelog of the changes since v0.8.0 and v0.9.0 can be found here.

Highlights

External

  • Support for Discord Polls, documentation here
  • All channels types are now stored in the guild channels cache (not just text and voice)
  • Add NoOp implementations for the rest of the caches

Internal

  • The ratelimiter has been turned into a state machine, yielding the following benefits:
    • Requests are now automatically dispatched as soon as possible, and no longer block the ratelimiter from running other requests.
    • The client need not concern itself with retrying later anymore, the ratelimiter will queue them up and schedule them when it can.
    • Every response is delivered incrementally in chunks, preventing blocking the ratelimiter there as well.
    • If the ratelimiter's connection to the API goes down, clients are informed that their requests went bust via the {:error, {:connection_died, reason}} return.
    • Tracing the ratelimiter's inner doings is now straightforward via :sys.trace(Nostrum.Api.Ratelimiter, true).
  • The shard session has been turnt into a state machine, yielding the following benefits:
    • Instead of retrying indefinitely on connection issues, the new shard session will provide more direct errors on network failure.

Breaking Changes

  • Removal of the following functions, deprecated in 0.8.0:
    • GuildCache.all/0
    • GuildCache.select_by/1
    • GuildCache.select/2 along GuildCache.select!/2
  • Removal of the non-functional Nostrum.Cache.ChannelCache module (see #555 for details)
  • Removal of support for Elixir 1.13 (#544)

Deprecations

Features

  • nostrum now ships an .appup file to allow upgrading it in environments requiring hot code upgrade.
    • The code_change/3-4 callbacks have been introduced to support this.

Documentation & Debug

Bug Fixes

  • No longer crash if Discord leaks a struct to us over the ETF gateway, by @Th3-M4jor in #512
  • Reconnect requests fixed by @Th3-M4jor in #510
  • Util.get_all_shard_latencies is fixed by @Th3-M4jor in #507

Dedications

To my new cats, Benjamin and Olive, Daddy loves you -- Craig

(Premptively) in loving memory of Jeremiah Boby -- Johannes

To my many loving fans in the Discord API #general channel -- Joe

v0.9.0-rc1

3 weeks ago

image

Welcome to the release candidate for Nostrum 0.9, code-named "Return to Flight".

NOTE: There is not an appup instruction for this release, there will be for Nostrum 0.9.

Breaking changes

  • Removal of the non-functional Nostrum.Cache.ChannelCache module (see #555 for details)
  • Removal of support for Elixir 1.13 (#544)

Deprecations

Features

  • Support for Discord Polls
    • Landed by @jb3 in #534
  • All channels types are now stored in the guild channels cache (not just text and voice)
    • Landed by @jb3 in #556
  • Extra handling of user errors for lacking consumers
    • Landed by @jchristgit in #525
  • Allow fallback to HTTP/1.1 if Discord needs to disable in future
    • Landed by @Th3-M4jor #522
  • Add NoOp implementations for the rest of the caches
    • Landed by @Leastrio in #513

Documentation and debugging

Fixes

  • No longer crash if Discord leaks a struct to us over the ETF gateway, by @Th3-M4jor in #512
  • Reconnect requests fixed by @Th3-M4jor in #510
  • Util.get_all_shard_latencies is fixed by @Th3-M4jor in #507

New Contributors

Full Changelog: https://github.com/Kraigie/nostrum/compare/v0.9.0-alpha2...v0.9.0-rc1

v0.9.0-alpha2

11 months ago

Welcome to nostrum 0.9.0, codenamed "T - 5".

Breaking changes

The following functions, deprecated in nostrum 0.8, have been removed:

  • GuildCache.all/0
  • GuildCache.select_by/1
  • GuildCache.select/2 along with GuildCache.select!/2

Deprecations

Features

  • nostrum now ships an .appup file to allow upgrading it in environments requiring hot code upgrade.
    • The code_change/3-4 callbacks have been introduced to support this.
  • The ratelimiter has been turnt into a state machine, yielding the following benefits:
    • Requests are now automatically dispatched as soon as possible, and no longer block the ratelimiter from running other requests.
    • The client need not concern itself with retrying later anymore, the ratelimiter will queue them up and schedule them when it can.
    • Every response is delivered incrementally in chunks, preventing blocking the ratelimiter there as well.
    • If the ratelimiter's connection to the API goes down, clients are informed that their requests went bust via the {:error, {:connection_died, reason}} return.
    • Tracing the ratelimiter's inner doings is now straightforward via :sys.trace(Nostrum.Api.Ratelimiter, true).
  • The shard session has been turnt into a state machine, yielding the following benefits:
    • Instead of retrying indefinitely on connection issues, the new shard session will provide more direct errors on network failure.

Fixes

Documentation

  • Document hot code upgrades via nostrum's .appup files.
  • Document optional contribution of appup changes.
  • Remove default handle_event. use Nostrum.Consumer manages this now.

Internal changes

v0.9.0-alpha1

11 months ago

nostrum 0.9.0-alpha1

Welcome to nostrum 0.9.0, codenamed "T - 5".

Breaking changes

The following functions, deprecated in nostrum 0.8, have bene removed:

  • GuildCache.all/0
  • GuildCache.select_by/1
  • GuildCache.select/2

Deprecations

Features

  • nostrum now ships an .appup file to allow upgrading it in environments requiring hot code upgrade.
  • The ratelimiter has been turnt into a state machine, yielding the following benefits:
    • Requests are now automatically dispatched as soon as possible, and no longer block the ratelimiter from running other requests.
    • The client need not concern itself with retrying later anymore, the ratelimiter will queue them up and schedule them when it can.
    • Every response is delivered incrementally in chunks, preventing blocking the ratelimiter there as well.
    • If the ratelimiter's connection to the API goes down, clients are informed that their requests went bust via the {:error, {:connection_died, reason}} return.
    • Tracing the ratelimiter's inner doings is now straightforward via :sys.trace(Nostrum.Api.Ratelimiter, true).

Fixes

Documentation

  • Document hot code upgrades via nostrum's .appup files.

Internal changes

v0.8.0

11 months ago

Welcome to nostrum 0.8.0, codenamed "ignition on".

0_8_0_release

This release introduces full support for distributed caching and state, and simplifies the existing cache behaviours by using a single shared interface for reading the cache using Erlang's QLC module. Simply put, instead of having to implement callbacks for every combination of functions that nostrum exposes (and will expose) to the cache, a pluggable cache only needs to implement the c:query_handle/0 callback. To fulfill this move, a few smaller breaking changes have been performed. It is expected that these will be the last bigger breaking changes done before the proper 1.0 release (at which point we will follow semantic versioning).

Note that cache distribution was not the only missing piece to allow distributing nostrum across multiple nodes (albeit the largest one). Gateway event handling must be updated to prevent duplicate gateway connections, proper distribution of shards over nodes must be implemented, and some other improvements in regards to gateway connections with many shards must be implemented, including support for persistent resume seq tokens.

Breaking changes

  • The current family of functions to read from the MemberCache have been replaced.
    • Functions affected:
      • MemberCache.get/1 -> MemberCache.fold/3-4
      • MemberCache.get_with_users/1 -> MemberCache.fold_with_users/3-4
      • MemberCache.by_user/1 -> MemberCache.fold_by_user/3-4
    • These changes were performed to support caches that need to perform some form of resource acquisition and release: ETS needs to call safe_fixtable for safe traversal and Mnesia needs to wrap calls in :mnesia.activity.
  • The following error returns have been renamed to a more generic version:
    • :channel_not_found -> :not_found
    • :presence_not_found -> :not_found
    • :id_not_found -> :not_found
    • :id_not_found_on_guild_lookup -> :not_found
    • :channel_not_found -> :not_found
  • The ChannelCache will no longer look up channels in the GuildCache if they were not found in the channel cache itself. A convenience function to fetch a channel from a guild (they are stored together) can be introduced to GuildCache if needed.
  • PresenceCache.get(user_id, guild_id) is now PresenceCache.get(guild_id, user_id), the same for PresenceCache.get!/2.
    • The reason behind this is that all "nested" caches use this form already, and having the arguments reversed may be confusing.

Deprecations

The following functions have been deprecated and will be removed in either nostrum 0.9 or 1.0:

  • GuildCache.all/0
  • GuildCache.select_by/1
  • GuildCache.select/2

Features

  • Heavily improved support for querying the cache, via Erlang's QLC. This allows you to express strong queries in native Erlang list comprehension syntax without having to enumerate the entire cache by yourself, with the added bonus that it can automatically, at compile time, optimize your query to use indices and other improved traversal mechanisms on the backend you're using. For instance, the Mnesia member cache places an index on the guild_id field: queries involving this field are automatically optimized at compile time to utilize the index to provide for fast lookups. As an example, the following query is used in nosedrum as part of the member converter:
    find_by(RequestedGuildId, Name, Discriminator, MemberCache, UserCache) ->
      qlc:q([Member || {{GuildId, MemberId}, Member} <- MemberCache:query_handle(),
                       GuildId =:= RequestedGuildId,
                       {UserId, User} <- UserCache:query_handle(),
                       MemberId =:= UserId,
                       map_get(username, User)  =:= Name,
                       map_get(discriminator, User) =:= Discriminator]).
    
  • Support specifying a shard range to start.
    • Previously, you could either start a set number of shards, or tell nostrum to use the amount that Discord asked you to use.
    • A new third option is introduced, which expects a tuple in the form {lowest, highest, total}, where nostrum will start lowest..highest shards and inform Discord you have total shards in total.
    • This is useful for bots that have outgrown a single server and need to split their shards across multiple servers. However, see the changes below as well.
  • Distributed caching.
    • All Nostrum.Cache modules now have an Mnesia-based cache adapter that allows you to replicate and distribute the data across hosts, with the full power of Mnesia.
    • Larger bots can fragment their cache tables into smaller replicated cache tables and can thus distribute their bot without having to implement their own distributed caching system.
  • Distributed state.
    • As with distributed caching, Nostrum's internal state now also ships with Mnesia-based distributed adapters.
  • Do not require pluggable caches to implement multiple supervisor callbacks. Implementing child_spec is sufficient.

Fixes

  • Requeue requests that ran into a "retry later" up to 50 times.
    • This is enough to prevent any legitimate requests from being dropped, whilst still guarding against somebody going haywire on the ratelimiter.
  • Prevent a crash when retry_after was 0.

Documentation

  • Create documentation on how to use nostrum in a multi-node cluster.
  • Restructure the Pages tab to be more inline with which features you want to use.
  • Move pluggable cache modules down on the API reference list to not take up space from the regular cache APIs.
    • As this feature won't be needed by most bots, we don't need it to clutter up space for everybody.
  • Embed the consumer example into the Nostrum.Consumer moduledoc.
  • Add an "Internal modules" section on the API documentation for modules that are highly unlikely to be used by the regular user, but are still documented for completeness.

Internal changes

  • Add caching benchmarks.
  • Add propaganda assets to the VCS tree.

v0.8.0-beta1

11 months ago

nostrum 0.8.0-beta1

Welcome to nostrum 0.8.0, codenamed "ignition on".

This release introduces full support for distributed caching and state, and simplifies the existing cache behaviours by using a single shared interface for reading the cache using Erlang's QLC module. Simply put, instead of having to implement callbacks for every combination of functions that nostrum exposes (and will expose) to the cache, a pluggable cache only needs to implement the c:query_handle/0 callback. To fulfill this move, a few smaller breaking changes have been performed. It is expected that these will be the last bigger breaking changes done before the proper 1.0 release (at which point we will follow semantic versioning).

Note that cache distribution was not the only missing piece to allow distributing nostrum across multiple nodes (albeit the largest one). Gateway event handling must be updated to prevent duplicate gateway connections, proper distribution of shards over nodes must be implemented, and some other improvements in regards to gateway connections with many shards must be implemented, including support for persistent resume seq tokens.

Breaking changes

  • The current family of functions to read from the MemberCache have been replaced.
    • Functions affected:
      • MemberCache.get/1 -> MemberCache.fold/3-4
      • MemberCache.get_with_users/1 -> MemberCache.fold_with_users/3-4
      • MemberCache.by_user/1 -> MemberCache.fold_by_user/3-4
    • These changes were performed to support caches that need to perform some form of resource acquisition and release: ETS needs to call safe_fixtable for safe traversal and Mnesia needs to wrap calls in :mnesia.activity.
  • The following error returns have been renamed to a more generic version:
    • :channel_not_found -> :not_found
    • :presence_not_found -> :not_found
    • :id_not_found -> :not_found
    • :id_not_found_on_guild_lookup -> :not_found
    • :channel_not_found -> :not_found
  • The ChannelCache will no longer look up channels in the GuildCache if they were not found in the channel cache itself. A convenience function to fetch a channel from a guild (they are stored together) can be introduced to GuildCache if needed.
  • PresenceCache.get(user_id, guild_id) is now PresenceCache.get(guild_id, user_id), the same for PresenceCache.get!/2.
    • The reason behind this is that all "nested" caches use this form already, and having the arguments reversed may be confusing.

Deprecations

The following functions have been deprecated and will be removed in either nostrum 0.9 or 1.0:

  • GuildCache.all/0
  • GuildCache.select_by/1
  • GuildCache.select/2

Features

  • Heavily improved support for querying the cache, via Erlang's QLC. This allows you to express strong queries in native Erlang list comprehension syntax without having to enumerate the entire cache by yourself, with the added bonus that it can automatically, at compile time, optimize your query to use indices and other improved traversal mechanisms on the backend you're using. For instance, the Mnesia member cache places an index on the guild_id field: queries involving this field are automatically optimized at compile time to utilize the index to provide for fast lookups. As an example, the following query is used in nosedrum as part of the member converter:
    find_by(RequestedGuildId, Name, Discriminator, MemberCache, UserCache) ->
      qlc:q([Member || {{GuildId, MemberId}, Member} <- MemberCache:query_handle(),
                       GuildId =:= RequestedGuildId,
                       {UserId, User} <- UserCache:query_handle(),
                       MemberId =:= UserId,
                       map_get(username, User)  =:= Name,
                       map_get(discriminator, User) =:= Discriminator]).
    
  • Support specifying a shard range to start.
    • Previously, you could either start a set number of shards, or tell nostrum to use the amount that Discord asked you to use.
    • A new third option is introduced, which expects a tuple in the form {lowest, highest, total}, where nostrum will start lowest..highest shards and inform Discord you have total shards in total.
    • This is useful for bots that have outgrown a single server and need to split their shards across multiple servers. However, see the changes below as well.
  • Distributed caching.
    • All Nostrum.Cache modules now have an Mnesia-based cache adapter that allows you to replicate and distribute the data across hosts, with the full power of Mnesia.
    • Larger bots can fragment their cache tables into smaller replicated cache tables and can thus distribute their bot without having to implement their own distributed caching system.
  • Distributed state.
    • As with distributed caching, Nostrum's internal state now also ships with Mnesia-based distributed adapters.
  • Do not require pluggable caches to implement multiple supervisor callbacks. Implementing child_spec is sufficient.

Fixes

  • Requeue requests that ran into a "retry later" up to 50 times.
    • This is enough to prevent any legitimate requests from being dropped, whilst still guarding against somebody going haywire on the ratelimiter.
  • Prevent a crash when retry_after was 0.

Documentation

  • Create documentation on how to use nostrum in a multi-node cluster.
  • Restructure the Pages tab to be more inline with which features you want to use.
  • Move pluggable cache modules down on the API reference list to not take up space from the regular cache APIs.
    • As this feature won't be needed by most bots, we don't need it to clutter up space for everybody.
  • Embed the consumer example into the Nostrum.Consumer moduledoc.
  • Add an "Internal modules" section on the API documentation for modules that are highly unlikely to be used by the regular user, but are still documented for completeness.

Internal changes

  • Add caching benchmarks.
  • Add propaganda assets to the VCS tree.

v0.8.0-alpha1

11 months ago

nostrum 0.8.0-alpha1

Welcome to nostrum 0.8.0, codenamed "ignition on".

This release introduces full support for distributed caching and state, and simplifies the existing cache behaviours by using a single shared interface for reading the cache using Erlang's QLC module. Simply put, instead of having to implement callbacks for every combination of functions that nostrum exposes (and will expose) to the cache, a pluggable cache only needs to implement the c:query_handle/0 callback. To fulfill this move, a few smaller breaking changes have been performed. It is expected that these will be the last bigger breaking changes done before the proper 1.0 release (at which point we will follow semantic versioning).

Note that cache distribution was not the only missing piece to allow distributing nostrum across multiple nodes (albeit the largest one). Gateway event handling must be updated to prevent duplicate gateway connections, proper distribution of shards over nodes must be implemented, and some other improvements in regards to gateway connections with many shards must be implemented, including support for persistent resume seq tokens.

Breaking changes

  • The current family of functions to read from the MemberCache have been replaced.
    • Functions affected:
      • MemberCache.get/1 -> MemberCache.fold/3-4
      • MemberCache.get_with_users/1 -> MemberCache.fold_with_users/3-4
      • MemberCache.by_user/1 -> MemberCache.fold_by_user/3-4
    • These changes were performed to support caches that need to perform some form of resource acquisition and release: ETS needs to call safe_fixtable for safe traversal and Mnesia needs to wrap calls in :mnesia.activity.
  • The following error returns have been renamed to a more generic version:
    • :channel_not_found -> :not_found
    • :presence_not_found -> :not_found
    • :id_not_found -> :not_found
    • :id_not_found_on_guild_lookup -> :not_found
    • :channel_not_found -> :not_found
  • The ChannelCache will no longer look up channels in the GuildCache if they were not found in the channel cache itself. A convenience function to fetch a channel from a guild (they are stored together) can be introduced to GuildCache if needed.
  • PresenceCache.get(user_id, guild_id) is now PresenceCache.get(guild_id, user_id), the same for PresenceCache.get!/2.
    • The reason behind this is that all "nested" caches use this form already, and having the arguments reversed may be confusing.

Deprecations

The following functions have been deprecated and will be removed in either nostrum 0.9 or 1.0:

  • GuildCache.all/0
  • GuildCache.select_by/1
  • GuildCache.select/2

Features

  • Heavily improved support for querying the cache, via Erlang's QLC. This allows you to express strong queries in native Erlang list comprehension syntax without having to enumerate the entire cache by yourself, with the added bonus that it can automatically, at compile time, optimize your query to use indices and other improved traversal mechanisms on the backend you're using. For instance, the Mnesia member cache places an index on the guild_id field: queries involving this field are automatically optimized at compile time to utilize the index to provide for fast lookups. As an example, the following query is used in nosedrum as part of the member converter:
    find_by(RequestedGuildId, Name, Discriminator, MemberCache, UserCache) ->
      qlc:q([Member || {{GuildId, MemberId}, Member} <- MemberCache:query_handle(),
                       GuildId =:= RequestedGuildId,
                       {UserId, User} <- UserCache:query_handle(),
                       MemberId =:= UserId,
                       map_get(username, User)  =:= Name,
                       map_get(discriminator, User) =:= Discriminator]).
    
  • Support specifying a shard range to start.
    • Previously, you could either start a set number of shards, or tell nostrum to use the amount that Discord asked you to use.
    • A new third option is introduced, which expects a tuple in the form {lowest, highest, total}, where nostrum will start lowest..highest shards and inform Discord you have total shards in total.
    • This is useful for bots that have outgrown a single server and need to split their shards across multiple servers. However, see the changes below as well.
  • Distributed caching.
    • All Nostrum.Cache modules now have an Mnesia-based cache adapter that allows you to replicate and distribute the data across hosts, with the full power of Mnesia.
    • Larger bots can fragment their cache tables into smaller replicated cache tables and can thus distribute their bot without having to implement their own distributed caching system.
  • Distributed state.
    • As with distributed caching, Nostrum's internal state now also ships with Mnesia-based distributed adapters.
  • Do not require pluggable caches to implement multiple supervisor callbacks. Implementing child_spec is sufficient.

Fixes

  • Requeue requests that ran into a "retry later" up to 50 times.
    • This is enough to prevent any legitimate requests from being dropped, whilst still guarding against somebody going haywire on the ratelimiter.
  • Prevent a crash when retry_after was 0.

Documentation

  • Create documentation on how to use nostrum in a multi-node cluster.
  • Restructure the Pages tab to be more inline with which features you want to use.
  • Move pluggable cache modules down on the API reference list to not take up space from the regular cache APIs.
    • As this feature won't be needed by most bots, we don't need it to clutter up space for everybody.
  • Embed the consumer example into the Nostrum.Consumer moduledoc.
  • Add an "Internal modules" section on the API documentation for modules that are highly unlikely to be used by the regular user, but are still documented for completeness.

Internal changes

  • Add caching benchmarks.
  • Add propaganda assets to the VCS tree.

v0.7.0

1 year ago

Welcome to nostrum 0.7.0, codenamed "launch preparations".

nostrum_0_7

This release brings you support for automod and forum channels, helps you with navigating through Discord's numbering schemes with the new modules under Nostrum.Constants, allows you to retrieve audit log entries over the gateway, and much more. For the full list of features and bugfixes, see below.

This release contains breaking changes in regards to member caching. If you want the short version, scroll down to the "Breaking changes" section. This part will document the changes and their reasoning.

Two main breaking changes have been performed, that are almost guaranteed to cause breakage on your bot:

  • Members are no longer stored on the guild struct, and by extension, the guild cache. The new Nostrum.Cache.MemberCache handles caching guild members, and has functions that allow you to easily retrieve members for a guild.
  • Users are no longer stored on the member struct. The MemberCache contains a convenience function, Nostrum.Cache.MemberCache.get_with_users/1, that will perform a :qlc join between the member and user cache.

For the join function to work, the callback c:qlc_handle/0 has been added to both Nostrum.Cache.MemberCache and Nostrum.Cache.UserCache. It is expected that more functionality will be built on top of :qlc in the future, especially as nostrum approaches its 1.0 release, so it's heavily recommended to add this callback for any custom consumers. The Erlang documentation explains how to implement a QLC table for any custom caches you may have.

Why were these changes done? Nostrum previously struggled when working with large guilds. With the ETS-based guild cache, updating a member would mean fetching the entire guild object from the cache, for ETS, this means making a full copy of the entire struct. While probably unproblematic for most usecases, running Nostrum with request_guild_members: true on large guilds would cause memory usage to skyrocket for a brief period at the start while Nostrum struggled to gobble all of the users into the cache. Unfortunately, fixing this was not possible without breaking the API. The :user field was removed as the members change will already require changes on your side, and nostrum previously did not update users on members properly, causing stale data. We want the caches to work independently from each other, so this seemed the proper solution. If you want to have some rough idea of how to change it, see this commit on bolt.

Due to the new separation and removal of duplicated user data, nostrum is now lighter on memory. The "Breaking changes" section below contains a complete listing of these changes. If you use a third-party command library such as :nosedrum, you will likely need to upgrade those as well.

Migration guide

For the breaking changes mentioned above, the following should serve as a guideline to the full list of breaking changes in the section below:

  • When retrieving a member from a guild, instead of using GuildCache.get(guild_id) or friends and then looking it up from there, use MemberCache.get(guild_id, user_id).
  • When searching guild members, instead of using Enum.find(guild.members, ...), use MemberCache.get(guild.id) |> Enum.find. The new cache functions are implemented as streams and are very light on memory.
  • If you absolutely need the user object of a member (and not just the ID), use UserCache.get(member.user_id) to retrieve it.
  • If you want the full rocket-engine power for searching members, use Erlang's :qlc and MemberCache.qlc_handle(). Note that the current ETS cache is optimized for lookup by user and guild ID. You can also use this for the UserCache.

If you had some previous functionality in your bot that is problematic to implement with these new changes, please open an issue.

Breaking changes

  • Introduce the new Nostrum.Cache.MemberCache
    • Nostrum ships an ETS-based member cache and uses it by default
  • Remove the :members field from Nostrum.Struct.Guild
    • These are now stored separately in Nostrum.Cache.MemberCache
    • Use Nostrum.Cache.MemberCache.get(guild_id) to retrieve guild members
    • The following Nostrum.Cache.GuildCache callbacks have been removed:
      • c:member_add/2
      • c:member_remove/2
      • c:member_update/2
      • c:member_chunk/2
    • The following Nostrum.Cache.GuildCache callbacks have been added:
      • c:member_count_up/1
      • c:member_count_down/1
  • Added the following callbacks to Nostrum.Cache.UserCache
    • c:qlc_handle/1
  • Remove the :user field from Nostrum.Struct.Guild.Member
    • The :user_id field can be used to find the matching user
  • Replace GenStage with :pg
    • Code with use Nostrum.Consumer can remain unchanged
    • Events are now distributed to all subscribers instead of round-robin fashion
      • This means that setups that deployed multiple replicas of their consumer per scheduler or similar must be updated to only start a single consumer
      • Nostrum.Consumer will automatically handle events in spawned processes for parallelism
    • See Nostrum.ConsumerGroup for detailed information
  • The :joined_at member field is now a unix timestamp instead of a raw string
    • See t:Nostrum.Struct.Guild.Member.joined_at/0
    • If this field was unset, it will continue to be nil

Functionality

  • Added a dedicated member cache
    • See Nostrum.Cache.MemberCache
    • More details can be found in the breaking changes above
  • Added support for AutoMod (The Major)
    • Update and receive events for Discord's Great Spam Wall.
    • The following functions have been added:
      • Nostrum.Api.get_guild_auto_moderation_rules/1
      • Nostrum.Api.get_guild_auto_moderation_rule/2
      • Nostrum.Api.create_guild_auto_moderation_rule/2
      • Nostrum.Api.modify_guild_auto_moderation_rule/3
      • Nostrum.Api.delete_guild_auto_moderation_rule/2
    • The following events can now be received in your consumer:
      • t:Nostrum.Consumer.auto_moderation_rule_create/0
      • t:Nostrum.Consumer.auto_moderation_rule_delete/0
      • t:Nostrum.Consumer.auto_moderation_rule_update/0
      • t:Nostrum.Consumer.auto_moderation_rule_execute/0
    • The following event structs have been added:
      • Nostrum.Struct.Event.AutoModerationRuleExecute
    • The following shard intents have been added:
      • :auto_moderation_configuration
      • :auto_moderation_execution
    • The following structs have been added:
      • Nostrum.Struct.AutoModerationRule
      • Nostrum.Struct.AutoModerationRule.Action
      • Nostrum.Struct.AutoModerationRule.ActionMetadata
      • Nostrum.Struct.AutoModerationRule.TriggerMetadata
  • Added support for forum channels (The Major)
    • Build your own forum and keep it tidy.
    • The following functions have been added:
      • Nostrum.Api.start_thread_in_forum_channel/2-3
    • The following changes were performed on Nostrum.Struct.Channel:
      • The :type may now be 15 to represent a forum channel
      • The following types and associated fields were added:
        • t:Nostrum.Struct.Channel.default_thread_rate_limit_per_user/0
        • t:Nostrum.Struct.Channel.forum_tag/0
        • t:Nostrum.Struct.Channel.applied_tags/0
        • t:Nostrum.Struct.Channel.default_reaction_emoji/0
      • The :thread_metadata field has been extended by the following fields:
        • :invitable
        • :create_timestamp
      • The type t:Nostrum.Struct.Channel.guild_forum_channel/0 has been added
  • Added constants for Discord's arbitrary numbers (Jiří Vrba)
    • The following modules have been added:
      • Nostrum.Constants.ApplicationCommandOptionType
      • Nostrum.Constants.ApplicationCommandPermissionType
      • Nostrum.Constants.ApplicationCommandType
      • Nostrum.Constants.ButtonStyle
      • Nostrum.Constants.ChannelType
      • Nostrum.Constants.ComponentType
      • Nostrum.Constants.InteractionCallbackType
      • Nostrum.Constants.InteractionType
      • Nostrum.Constants.TextInputStyle
      • Nostrum.Constants.WebhookType
  • Added the audit log entry gateway event (Leastrio)
    • The following struct has been added:
      • Nostrum.Struct.Guild.AuditLogEntry
    • The following consumer event has been added:
      • t:Nostrum.Consumer.guild_audit_log_entry_create/0
  • Added support for retrieving webhook messages (Awlex)
    • See Nostrum.Api.get_webhook_message/2
  • Added support for role icons (Joe Sweeney)
    • See t:Nostrum.Struct.Guild.Role.icon/0
  • Add attachments to interaction data (Jakob Bowyer)
    • See t:Nostrum.Struct.ApplicationCommandInteractionDataResolved.attachments/0
  • Added support for retrieving the original interaction response (Awlex)
    • See Nostrum.Api.get_original_interaction_response/1
  • Add param support for emoji API calls (Brandt Hill)
    • See Nostrum.Api.get_reactions/3-4
  • Added support for role icon emojis (Joe Sweeney)
    • See t:Nostrum.Struct.Guild.Role.unicode_emoji/0
  • Support inline event awaiting
    • See Nostrum.ConsumerGroup for details
  • Implement gateway websocket message flow control
    • This prevents overwhelming the shard process with messages before we can process them
  • Log READY event at INFO log level as well
    • Previously, only IDENTIFYING was logged, which could lead to believe that the bot is stuck in startup

Changes

  • Sleep out ratelimiter buckets on the client instead of spawning tasks
  • Make allowed mentions a proper type
    • See t:Nostrum.Api.allowed_mentions/0
  • Add a few more unused atoms to prevent casting warnings
  • Simplify the Nostrum.Cache.ChannelCache behaviour
    • Implement get/1 with a message directly in the dispatcher
    • Implement bangified get!/1 directly in the dispatcher
    • Deprecate c:lookup/1 and its dispatch function

Bugfixes

  • Accept voice RTP packets without header (Ushitora Anqou)
  • Fix voice session not closing error (Brandt Hill)
  • Handle unknown voice session close & reorganize voice code (Brandt Hill)
  • Fix button component status (Awlex)
  • Fix crash when trying to connect to voice when session pid isn't alive (Brandt Hill)
  • Correct typecasting in list_guild_threads/1 (Zach Daniel)
  • Fix throwing up for undocumented voice gateway events (Brandt Hill)
  • Stop crashing on receiving API responses after timeout
  • Prevent crashing the guild cache without the guilds intent

Documentation

  • Emphasize message content intent warning in README (Matthew Villwock)
  • Document new constants for Discord's arbitrary numbers (Jiří Vrba)
  • Improve grammar for application command documentation (Roy Li)
  • Fix broken syntax highlighting in some examples
  • Correct documentation for allowed mentions in webhook messages
  • Document attachment editing quirk in API v10
  • Clarify that the ChannelCache is only for off-guild channels
  • Document that the README is for the master branch
    • Link both release and development documentations
  • Build master branch documentation on Erlang/OTP 25 and Elixir 1.14
  • Improve sidebar sections

Internal changes

  • Refactor voice session close (Brandt Hill)
  • Silence warnings from youtube-dl (aukuste)
  • Replace blocking voice port close call with cast (Brandt Hill)
  • Refactor voice session restart on invalid session (Brandt Hill)
  • Use DynamicSupervisor for voice sessions (Brandt Hill)
  • Cleanly separate the doc build and source file folders
  • Update :gun to the official stable 2.0 release
    • Yes, really.
    • Thanks to bdanklin for publishing :remedy_gun and :remedy_cowlib allowing us to make releases with :gun before.
  • Add Erlang/OTP 25 and Elixir 1.14 to our test matrix
  • Remove the unused Nostrum.Cache.Mapping.ShardPidNum module
  • Lint on the latest and greatest Elixir and OTP only
  • Simplify await_up logic
  • Run dialyzer in CI
  • Fix deprecation warning associated with use Bitwise

v0.7.0-rc2

1 year ago

Changes since 0.7.0-rc1:

  • Add MemberCache.get_with_user/2
  • Handle unknown voice session close & reorganize voice code
  • Fix crash when trying to connect to voice when session pid isn't alive

Full release notes follow.


Welcome to nostrum 0.7.0, codenamed "launch preparations".

This release brings you support for automod and forum channels, helps you with navigating through Discord's numbering schemes with the new modules under Nostrum.Constants, allows you to retrieve audit log entries over the gateway, and much more. For the full list of features and bugfixes, see below.

This release contains breaking changes in regards to member caching. If you want the short version, scroll down to the "Breaking changes" section. This part will document the changes and their reasoning.

Two main breaking changes have been performed, that are almost guaranteed to cause breakage on your bot:

  • Members are no longer stored on the guild struct, and by extension, the guild cache. The new Nostrum.Cache.MemberCache handles caching guild members, and has functions that allow you to easily retrieve members for a guild.
  • Users are no longer stored on the member struct. The MemberCache contains a convenience function, Nostrum.Cache.MemberCache.get_with_users/1, that will perform a :qlc join between the member and user cache.

For the join function to work, the callback c:qlc_handle/0 has been added to both Nostrum.Cache.MemberCache and Nostrum.Cache.UserCache. It is expected that more functionality will be built on top of :qlc in the future, especially as nostrum approaches its 1.0 release, so it's heavily recommended to add this callback for any custom consumers. The Erlang documentation explains how to implement a QLC table for any custom caches you may have.

Why were these changes done? Nostrum previously struggled when working with large guilds. With the ETS-based guild cache, updating a member would mean fetching the entire guild object from the cache, for ETS, this means making a full copy of the entire struct. While probably unproblematic for most usecases, running Nostrum with request_guild_members: true on large guilds would cause memory usage to skyrocket for a brief period at the start while Nostrum struggled to gobble all of the users into the cache. Unfortunately, fixing this was not possible without breaking the API. The :user field was removed as the members change will already require changes on your side, and nostrum previously did not update users on members properly, causing stale data. We want the caches to work independently from each other, so this seemed the proper solution. If you want to have some rough idea of how to change it, see this commit on bolt.

Due to the new separation and removal of duplicated user data, nostrum is now lighter on memory. The "Breaking changes" section below contains a complete listing of these changes. If you use a third-party command library such as :nosedrum, you will likely need to upgrade those as well.

Migration guide

For the breaking changes mentioned above, the following should serve as a guideline to the full list of breaking changes in the section below:

  • When retrieving a member from a guild, instead of using GuildCache.get(guild_id) or friends and then looking it up from there, use MemberCache.get(guild_id, user_id).
  • When searching guild members, instead of using Enum.find(guild.members, ...), use MemberCache.get(guild.id) |> Enum.find. The new cache functions are implemented as streams and are very light on memory.
  • If you absolutely need the user object of a member (and not just the ID), use UserCache.get(member.user_id) to retrieve it.
  • If you want the full rocket-engine power for searching members, use Erlang's :qlc and MemberCache.qlc_handle(). Note that the current ETS cache is optimized for lookup by user and guild ID. You can also use this for the UserCache.

If you had some previous functionality in your bot that is problematic to implement with these new changes, please open an issue.

Breaking changes

  • Introduce the new Nostrum.Cache.MemberCache
    • Nostrum ships an ETS-based member cache and uses it by default
  • Remove the :members field from Nostrum.Struct.Guild
    • These are now stored separately in Nostrum.Cache.MemberCache
    • Use Nostrum.Cache.MemberCache.get(guild_id) to retrieve guild members
    • The following Nostrum.Cache.GuildCache callbacks have been removed:
      • c:member_add/2
      • c:member_remove/2
      • c:member_update/2
      • c:member_chunk/2
    • The following Nostrum.Cache.GuildCache callbacks have been added:
      • c:member_count_up/1
      • c:member_count_down/1
  • Added the following callbacks to Nostrum.Cache.UserCache
    • c:qlc_handle/1
  • Remove the :user field from Nostrum.Struct.Guild.Member
    • The :user_id field can be used to find the matching user
  • Replace GenStage with :pg
    • Code with use Nostrum.Consumer can remain unchanged
    • Events are now distributed to all subscribers instead of round-robin fashion
      • This means that setups that deployed multiple replicas of their consumer per scheduler or similar must be updated to only start a single consumer
      • Nostrum.Consumer will automatically handle events in spawned processes for parallelism
    • See Nostrum.ConsumerGroup for detailed information
  • The :joined_at member field is now a unix timestamp instead of a raw string
    • See t:Nostrum.Struct.Guild.Member.joined_at/0
    • If this field was unset, it will continue to be nil

Functionality

  • Added a dedicated member cache
    • See Nostrum.Cache.MemberCache
    • More details can be found in the breaking changes above
  • Added support for AutoMod (The Major)
    • Update and receive events for Discord's Great Spam Wall.
    • The following functions have been added:
      • Nostrum.Api.get_guild_auto_moderation_rules/1
      • Nostrum.Api.get_guild_auto_moderation_rule/2
      • Nostrum.Api.create_guild_auto_moderation_rule/2
      • Nostrum.Api.modify_guild_auto_moderation_rule/3
      • Nostrum.Api.delete_guild_auto_moderation_rule/2
    • The following events can now be received in your consumer:
      • t:Nostrum.Consumer.auto_moderation_rule_create/0
      • t:Nostrum.Consumer.auto_moderation_rule_delete/0
      • t:Nostrum.Consumer.auto_moderation_rule_update/0
      • t:Nostrum.Consumer.auto_moderation_rule_execute/0
    • The following event structs have been added:
      • Nostrum.Struct.Event.AutoModerationRuleExecute
    • The following shard intents have been added:
      • :auto_moderation_configuration
      • :auto_moderation_execution
    • The following structs have been added:
      • Nostrum.Struct.AutoModerationRule
      • Nostrum.Struct.AutoModerationRule.Action
      • Nostrum.Struct.AutoModerationRule.ActionMetadata
      • Nostrum.Struct.AutoModerationRule.TriggerMetadata
  • Added support for forum channels (The Major)
    • Build your own forum and keep it tidy.
    • The following functions have been added:
      • Nostrum.Api.start_thread_in_forum_channel/2-3
    • The following changes were performed on Nostrum.Struct.Channel:
      • The :type may now be 15 to represent a forum channel
      • The following types and associated fields were added:
        • t:Nostrum.Struct.Channel.default_thread_rate_limit_per_user/0
        • t:Nostrum.Struct.Channel.forum_tag/0
        • t:Nostrum.Struct.Channel.applied_tags/0
        • t:Nostrum.Struct.Channel.default_reaction_emoji/0
      • The :thread_metadata field has been extended by the following fields:
        • :invitable
        • :create_timestamp
      • The type t:Nostrum.Struct.Channel.guild_forum_channel/0 has been added
  • Added constants for Discord's arbitrary numbers (Jiří Vrba)
    • The following modules have been added:
      • Nostrum.Constants.ApplicationCommandOptionType
      • Nostrum.Constants.ApplicationCommandPermissionType
      • Nostrum.Constants.ApplicationCommandType
      • Nostrum.Constants.ButtonStyle
      • Nostrum.Constants.ChannelType
      • Nostrum.Constants.ComponentType
      • Nostrum.Constants.InteractionCallbackType
      • Nostrum.Constants.InteractionType
      • Nostrum.Constants.TextInputStyle
      • Nostrum.Constants.WebhookType
  • Added the audit log entry gateway event (Leastrio)
    • The following struct has been added:
      • Nostrum.Struct.Guild.AuditLogEntry
    • The following consumer event has been added:
      • t:Nostrum.Consumer.guild_audit_log_entry_create/0
  • Added support for retrieving webhook messages (Awlex)
    • See Nostrum.Api.get_webhook_message/2
  • Added support for role icons (Joe Sweeney)
    • See t:Nostrum.Struct.Guild.Role.icon/0
  • Add attachments to interaction data (Jakob Bowyer)
    • See t:Nostrum.Struct.ApplicationCommandInteractionDataResolved.attachments/0
  • Added support for retrieving the original interaction response (Awlex)
    • See Nostrum.Api.get_original_interaction_response/1
  • Add param support for emoji API calls (Brandt Hill)
    • See Nostrum.Api.get_reactions/3-4
  • Added support for role icon emojis (Joe Sweeney)
    • See t:Nostrum.Struct.Guild.Role.unicode_emoji/0
  • Support inline event awaiting
    • See Nostrum.ConsumerGroup for details
  • Implement gateway websocket message flow control
    • This prevents overwhelming the shard process with messages before we can process them
  • Log READY event at INFO log level as well
    • Previously, only IDENTIFYING was logged, which could lead to believe that the bot is stuck in startup

Changes

  • Sleep out ratelimiter buckets on the client instead of spawning tasks
  • Make allowed mentions a proper type
    • See t:Nostrum.Api.allowed_mentions/0
  • Add a few more unused atoms to prevent casting warnings
  • Simplify the Nostrum.Cache.ChannelCache behaviour
    • Implement get/1 with a message directly in the dispatcher
    • Implement bangified get!/1 directly in the dispatcher
    • Deprecate c:lookup/1 and its dispatch function

Bugfixes

  • Accept voice RTP packets without header (Ushitora Anqou)
  • Fix voice session not closing error (Brandt Hill)
  • Fix button component status (Awlex)
  • Correct typecasting in list_guild_threads/1 (Zach Daniel)
  • Fix throwing up for undocumented voice gateway events (Brandt Hill)
  • Stop crashing on receiving API responses after timeout
  • Prevent crashing the guild cache without the guilds intent

Documentation

  • Emphasize message content intent warning in README (Matthew Villwock)
  • Document new constants for Discord's arbitrary numbers (Jiří Vrba)
  • Improve grammar for application command documentation (Roy Li)
  • Fix broken syntax highlighting in some examples
  • Correct documentation for allowed mentions in webhook messages
  • Document attachment editing quirk in API v10
  • Clarify that the ChannelCache is only for off-guild channels
  • Document that the README is for the master branch
    • Link both release and development documentations
  • Build master branch documentation on Erlang/OTP 25 and Elixir 1.14
  • Improve sidebar sections

Internal changes

  • Refactor voice session close (Brandt Hill)
  • Silence warnings from youtube-dl (aukuste)
  • Replace blocking voice port close call with cast (Brandt Hill)
  • Refactor voice session restart on invalid session (Brandt Hill)
  • Use DynamicSupervisor for voice sessions (Brandt Hill)
  • Cleanly separate the doc build and source file folders
  • Update :gun to the official stable 2.0 release
    • Yes, really.
    • Thanks to bdanklin for publishing :remedy_gun and :remedy_cowlib allowing us to make releases with :gun before.
  • Add Erlang/OTP 25 and Elixir 1.14 to our test matrix
  • Remove the unused Nostrum.Cache.Mapping.ShardPidNum module
  • Lint on the latest and greatest Elixir and OTP only
  • Simplify await_up logic
  • Run dialyzer in CI
  • Fix deprecation warning associated with use Bitwise