Releases: Kraigie/nostrum
0.10.0 - Orbital Insertion
Welcome to Nostrum 0.10.0, codenamed "Orbital Insertion".
"Orbital Insertion" is a testament to our commitment to continuous improvement
and our vision of providing a robust and reliable Discord library for the Elixir
community. We extend our gratitude to all contributors and users who have
supported us on this journey. Your feedback and collaboration are invaluable.
Breaking Changes
- Message cache by @Th3-M4jor in #595
-
The introduction of the message cache changes the signature of the message update event callback.
Previously, as messages were not cached, the signature was
handle_event({:MESSAGE_UPDATE, new_msg, _ws_state})
, with these changes the signature is nowhandle_event({:MESSAGE_UPDATE, {old_msg, new_msg}, _ws_state})
, whereold_msg
may be null if the message is not present in the cache.If the message is present, the
old_msg
value will be the previous version of the message as found in cache. Nostrum will handle the updating of the cache such that further cache requests will fetch the new message. -
Note this is breaking EVEN IF you use a no-op cache.
-
New Features
- The aforementioned message cache is newly introduced in #595.
- By default, the cache is disabled (
Noop
) meaning no messages will be cached. - Optionally, you can use the pre-built Mnesia backed cache or write your own adapter. Read more in the related documentation
Nostrum.Cache.MessageCache
.
- By default, the cache is disabled (
- We support Discord's new
zstd-stream
compression version- This compression method produces considerably smaller payload sizes at the expense of slightly increased memory usage for lookup tables.
- See documentation here on how to enable the new compression method. It is not enabled by default as it requires additional dependencies and some compiled modules.
- Relevant PR: Support zstd-stream gateway compression by @jb3 in #598
- We have increased the amount of the API that we support, stickers and previously missing guild attributes have been added:
- Support all voice encryption modes by @BrandtHill in #599
- feat(shard): manually shard connect and reconnect by @tignear in #596
- See more in this documentation guide
Quality of Life
- Remove blob of zlib data from state machine errors by @jb3 in #583
- Add resume_gateway_url to Nostrum.Struct.Event.Ready by @jb3 in #588
- Refactor executable checks and add version check for non-forked youtube-dl by @BrandtHill in #594
- Add flag to disable HTTP 2 by @jb3 in #608
Fixes
- Fix the error caused by trying to cast a datetime to datetime by @jb3 in #582
- fix key error in ratelimiter by @Th3-M4jor in #606
- Handle case of non matching gun conn pids when receiving a gun_down message by @Th3-M4jor in #611
- Ensure user struct is casted properly before updating ets cache by @Th3-M4jor in #610
Documentation
- Cheatsheets
- add top n guilds to qlc cheatsheet by @Leastrio in #586
- Add voice cheat sheet and fix docs typos by @BrandtHill in #590
- Fix broken link in documentation by @RocketRace in #587
- Fix Doc Arg Mismatch: Rename "options" to "response" by @njwest in #589
- Docs update: manual sharding by @jb3 in #603
- Add since 0.10.0 tags to changes since 0.9.1 by @Th3-M4jor in #604
- Publish docs on Elixir 1.17 by @jchristgit in #609
Miscellaneous
- Reduce binary copies in salsa crypto by @BrandtHill in #602
- Remove Application.get_env call from Nostrum.Api.Base by @jchristgit in #593
- Add soviet propaganda by @jchristgit in #605
- Enable -Wunmatched_return in dialyzer by @jchristgit in #508
- Bump CI to OTP 27 by @jb3 in #601
New Contributors
- @RocketRace made their first contribution in #587
- @njwest made their first contribution in #589
- @tignear made their first contribution in #596
Full Changelog: v0.9.1...v0.10.0
0.9.1 - Trajectory Correction
Welcome to Nostrum 0.9.1, code-named "Trajectory Correction".
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 #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.
- As Nostrum moves to support multiple bots / library usage functionality like
- Implement memory optimizations in user struct by @jchristgit in #567
- Removes automatic parsing of the
flags
attribute ofUser
structs, but
theNostrum.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
andemail
attributes
that would only be set with OAuth2. We do not expect anyone writing regular
bots to have any dependence on these properties.
- Removes automatic parsing of the
Features
- Add missing fields from member API object by @jb3 in #573
- Adds the
pending
,flags
andavatar
(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.
- Adds the
Fixes
- Re-support uploading files from memory by @jb3 in #560
- Don't attempt to convert integers to atoms in map casting by @jb3 in #572
- Only attempt resume if the gateway says we can by @jchristgit in #566
- Drop session on invalid and unresumable session by @jchristgit in #580
Documentation and Debug
- Add admonition documenting lack of DM channel caching by @jb3 in #561
- Change
command
tocomponent
in documentation by @Awlexus in #568 - Improve messages on shard resume by @jchristgit in #565
- Update state docs with new QLC examples by @jb3 in #574
- Add sample bot linked in issue #564 by @jchristgit in #575
- Fix referenced function in example for
create_global_application_command
by @jchristgit in #577 - Remove obsolete handle_event clause from example consumer by @jchristgit in #576
- Log at INFO level when shard connection is up by @jchristgit in #581
- Add cheat sheets by @jb3 in #559
Miscellaneous
- Add OTP 27.0-rc3 to our test matrix by @jb3 in #562
- In preparation of the release of OTP 27, we have added the latest release
candidate to our test matrix in this PR to spot any potential teething
issues with the upcoming release.
- In preparation of the release of OTP 27, we have added the latest release
- Update GitHub Action versions by @jb3 in #578
- Stops a handful of node.js errors from appearing under the CI tab of all
contributions to Nostrum
- Stops a handful of node.js errors from appearing under the CI tab of all
- Version 0.9.1 Preparation by @jb3 in #579
Full Changelog: v0.9.0...v0.9.1
v0.9.0 - Return to Flight
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)
.
- Requests are now automatically dispatched as soon as possible, and no longer
- 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.
- Instead of retrying indefinitely on connection issues, the new shard session
Breaking Changes
- Removal of the following functions, deprecated in 0.8.0:
GuildCache.all/0
GuildCache.select_by/1
GuildCache.select/2
alongGuildCache.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
- Check OTP version on startup and update deprecated Logger.warn/2 calls by @BrandtHill in #528
- New icon on documentation pages (introduced in #544)
- Fix typos in intro.md by @dawedawe in #532
- Add missing word to state documentation by @jchristgit in #535
- Document StateMachineTranslator as internal by @jchristgit in #541
- 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. - New propaganda added to the assets folder
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
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
- All channels types are now stored in the guild channels cache (not just text and voice)
- 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
Documentation and debugging
- Check OTP version on startup and update deprecated Logger.warn/2 calls by @BrandtHill in #528
- Fix typos in intro.md by @dawedawe in #532
- Add missing word to state documentation by @jchristgit in #535
- Document StateMachineTranslator as internal by @jchristgit in #541
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: v0.9.0-alpha2...v0.9.0-rc1
0.9.0-alpha2
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 withGuildCache.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)
.
- Requests are now automatically dispatched as soon as possible, and no longer
- 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.
- Instead of retrying indefinitely on connection issues, the new shard session
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
0.9.0-alpha1
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)
.
- Requests are now automatically dispatched as soon as possible, and no longer
Fixes
Documentation
- Document hot code upgrades via nostrum's
.appup
files.
Internal changes
0.8.0
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 callsafe_fixtable
for safe traversal and Mnesia needs to wrap calls in:mnesia.activity
.
- Functions affected:
- 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 theGuildCache
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 nowPresenceCache.get(guild_id, user_id)
, the same forPresenceCache.get!/2
.- The reason behind this is that all "nested" caches use this form already,
and having the arguments reversed may be confusing.
- The reason behind this is that all "nested" caches use this form already,
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 theguild_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 startlowest..highest
shards and inform Discord you havetotal
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.
- Previously, you could either start a set number of shards, or tell nostrum
- 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.
- All
- Distributed state.
- As with distributed caching, Nostrum's internal state now also ships with
Mnesia-based distributed adapters.
- As with distributed caching, Nostrum's internal state now also ships with
- Do not require pluggable caches to implement multiple supervisor callbacks.
Implementingchild_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.
- This is enough to prevent any legitimate requests from being dropped, whilst
- 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.
- As this feature won't be needed by most bots, we don't need it to clutter up
- 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.
0.8.0-beta1
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 callsafe_fixtable
for safe traversal and Mnesia needs to wrap calls in:mnesia.activity
.
- Functions affected:
- 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 theGuildCache
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 nowPresenceCache.get(guild_id, user_id)
, the same forPresenceCache.get!/2
.- The reason behind this is that all "nested" caches use this form already,
and having the arguments reversed may be confusing.
- The reason behind this is that all "nested" caches use this form already,
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 theguild_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 startlowest..highest
shards and inform Discord you havetotal
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.
- Previously, you could either start a set number of shards, or tell nostrum
- 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.
- All
- Distributed state.
- As with distributed caching, Nostrum's internal state now also ships with
Mnesia-based distributed adapters.
- As with distributed caching, Nostrum's internal state now also ships with
- Do not require pluggable caches to implement multiple supervisor callbacks.
Implementingchild_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.
- This is enough to prevent any legitimate requests from being dropped, whilst
- 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.
- As this feature won't be needed by most bots, we don't need it to clutter up
- 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.
0.8.0-alpha1
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 callsafe_fixtable
for safe traversal and Mnesia needs to wrap calls in:mnesia.activity
.
- Functions affected:
- 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 theGuildCache
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 nowPresenceCache.get(guild_id, user_id)
, the same forPresenceCache.get!/2
.- The reason behind this is that all "nested" caches use this form already,
and having the arguments reversed may be confusing.
- The reason behind this is that all "nested" caches use this form already,
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 theguild_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 startlowest..highest
shards and inform Discord you havetotal
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.
- Previously, you could either start a set number of shards, or tell nostrum
- 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.
- All
- Distributed state.
- As with distributed caching, Nostrum's internal state now also ships with
Mnesia-based distributed adapters.
- As with distributed caching, Nostrum's internal state now also ships with
- Do not require pluggable caches to implement multiple supervisor callbacks.
Implementingchild_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.
- This is enough to prevent any legitimate requests from being dropped, whilst
- 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.
- As this feature won't be needed by most bots, we don't need it to clutter up
- 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.
0.7.0
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 newNostrum.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, ...)
, useMemberCache.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
andMemberCache.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 fromNostrum.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
- These are now stored separately in
- Added the following callbacks to
Nostrum.Cache.UserCache
c:qlc_handle/1
- Remove the
:user
field fromNostrum.Struct.Guild.Member
- The
:user_id
field can be used to find the matching user
- The
- 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
- This means that setups that deployed multiple replicas of their consumer
- See
Nostrum.ConsumerGroup
for detailed information
- Code with
- 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
- See
Functionality
- Added a dedicated member cache
- See
Nostrum.Cache.MemberCache
- More details can be found in the breaking changes above
- See
- 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 be15
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
- The
- 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
- The following modules have been added:
- 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
- The following struct has been added:
- Added support for retrieving webhook messages (Awlex)
- See
Nostrum.Api.get_webhook_message/2
- See
- Added support for role icons (Joe Sweeney)
- See
t:Nostrum.Struct.Guild.Role.icon/0
- See
- Add attachments to interaction data (Jakob Bowyer)
- See
t:Nostrum.Struct.ApplicationCommandInteractionDataResolved.attachments/0
- See
- Added support for retrieving the original interaction response (Awlex)
- See
Nostrum.Api.get_original_interaction_response/1
- See
- Add param support for emoji API calls (Brandt Hill)
- See
Nostrum.Api.get_reactions/3-4
- See
- Added support for role icon emojis (Joe Sweeney)
- See
t:Nostrum.Struct.Guild.Role.unicode_emoji/0
- See
- Support inline event awaiting
- See
Nostrum.ConsumerGroup
for details
- See
- Implement gateway websocket message flow control
- This prevents overwhelming the shard process with messages before we can
process them
- This prevents overwhelming the shard process with messages before we can
- Log
READY
event atINFO
log level as well- Previously, only
IDENTIFYING
was logged, which could lead to believe that
the bot is stuck in startup
- Previously, only
Changes
- Sleep out ratelimiter buckets on t...