-
-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Forwarding into Beta [1.0.0-BETA] #8
Conversation
…sage). This adds baseline new features and improvements for the beta release of Nexus which includes many breaking changes to introduce much better functionality. As part of this change, the entire NexusSynchronizer and its default methods have been modified to create indexes on-the-go on anything that effects command additions. Nexus' EngineX has new methods such as `queue(predicate, event)`, `await(shard)`, `await(server)`, `awaitAvailable()` and `failFutureOnExpire(event, future)` which are explained deeper in the pull request (#8). All references to a writeable record store in Nexus EngineX have been removed because it has no clear purpose. Nexus Shard Manager now has a conveience method for the shard id calculation `((server >> 22) % totalShards)` which is called `shardOf(server, totalShards)` Nexus Command Manager can now support importing indexes from the database and exporting its current in-memory indexes, more details on PR (#8). `Nexus.start()` has been removed and methods related to creating shards and login with shards in `NexusBuilder` has been removed.
…sEngineEventCore.
…rtFor(serverIds)` in NexusCommand. This change is correlated with making Nexus a bit more clearer to understand. It's more preferred to use the word disassociate and associate when it comes to servers.
a83042b
to
ebcf3b9
Compare
…verId)` and `synchronize`.
Additional breaking changes were included to have better support for multiple shards, especially in multi-cluster environments. 🧷 Nexus SynchronizerA new breaking change was introduced to the synchronizer to better optimize the synchronizer for multi-cluster environments wherein the server shard may not be in the current cluster. The following changes have been applied: - CompletableFuture<Void> synchronize(int totalShards)
+ CompletableFuture<Void> synchronize()
- CompletableFuture<Void> batchUpdate(long serverId, DiscordApi shard)
+ CompletableFuture<Void> batchUpdate(long serverId)
- CompletableFuture<Void> batchUpdate(long serverId, int totalShards) In summary, the changes are as follows:
|
Additional changes were implemented onto the command events themselves to make life easier for the developers. 💬 Command EventsMore ways to send a response over to Discord has been added for commands which should help sending responses so much easier. The following methods have been added: fun respondNowWith(contents: String): CompletableFuture<InteractionOriginalResponseUpdater>
fun respondNowWith(vararg embeds: EmbedBuilder): CompletableFuture<InteractionOriginalResponseUpdater>
fun respondNowEphemerallyWith(contents: String): CompletableFuture<InteractionOriginalResponseUpdater>
fun respondNowEphemerallyWith(vararg embeds: EmbedBuilder): CompletableFuture<InteractionOriginalResponseUpdater> And the following methods were removed since there is no real use for the following: - fun getOptions(): List<SlashCommandInteractionOption>
- fun getSubcommandOptions(name: String): List<SlashCommandInteractionOption> You can do now the following: override fun onEvent(event: NexusCommandEvent) {
event.respondNowWith("Pong!").exceptionally(ExceptionLogger.get())
} It looks more verbose and cleaner than the following: override fun onEvent(event: NexusCommandEvent) {
event.respondNow().setContent("Pong!").respond().exceptionally(ExceptionLogger.get())
} |
As Javacord v3.6.0 is now released, this PR needs to be fast-forwarded a bit more. To outline the final changes we need:
An optimistic deadline for this change will be by November when I will be more free. |
Nexus has officially transitioned into a Kotlin-first framework with majority of its functionality written in Kotlin. You can read the full changes of the Kotlin-first here. An additional change that was implemented is Index Stores which is how we operate the Nexus Command Manager's Indexes from hereon as a move to flexibility with the framework. You can now customize the Index Store to collect indexes from the database, etc. View IndexStore interfaceinterface IndexStore {
/**
* Adds the [NexusMetaIndex] into the store which can be retrieved later on by methods such as
* [get] when needed.
* @param metaIndex the index to add into the index store.
*/
fun add(metaIndex: NexusMetaIndex)
/**
* Gets the [NexusMetaIndex] from the store or an in-memory cache by the application command identifier.
* @param applicationCommandId the application command identifier from Discord's side.
* @return the [NexusMetaIndex] that was caught otherwise none.
*/
operator fun get(applicationCommandId: Long): NexusMetaIndex?
/**
* Gets the [NexusMetaIndex] from the store or an in-memory cache by the Nexus unique identifier.
* @param command the unique identifier of the command, tends to be of the same value always unless the name changed or
* the unique identifier was changed via the [IdentifiableAs] annotation.
* @return the [NexusMetaIndex] that was caught otherwise none.
*/
operator fun get(command: String): NexusMetaIndex?
/**
* Adds one or more [NexusMetaIndex] into the store, this is used in scenarios such as mass-synchronization which
* offers more than one indexes at the same time.
*
* @param metaIndexes the indexes to add into the store.
*/
fun addAll(metaIndexes: List<NexusMetaIndex>)
/**
* Gets all the [NexusMetaIndex] available in the store, this is used more when the command manager's indexes are
* exported somewhere.
*
* @return all the [NexusMetaIndex] known in the store.
*/
fun all(): List<NexusMetaIndex>
/**
* Clears all the known indexes in the database. This happens when the command manager performs a re-indexing which
* happens when the developer themselves has called for it.
*/
fun clear()
} A meta index is simply a data class that contains the following properties: data class NexusMetaIndex(val command: String, val applicationCommandId: Long, val server: Long?) Properties:
To understand how persistent indexes work, we have to understand a new key component in indexing and that is the unique identifier of a command. In Discord, there can be commands with the same name (one global, one per server) and that's fine until it is designed in a framework. Nexus has been designed to assign the command name as the unique identifier of the command, but this has a problem, when two commands have the same name but different scopes, both have an index identifier conflict. It may seem like an issue at first, but there is a simpler fix to this and that is assigning a different unique identifier for the command. The framework has been designed to identify potential index-identifier conflicts at runtime (when you add commands at Nexus), if Nexus finds that a command has the same unique identifier then it will throw an To resolve the issue, all you need to do is add the class PingCommand {
val name = "ping"
}
class PingCommandServer {
val name = "ping"
} Nexus will complain that the two commands have the same unique identifier which leads to a class PingCommand {
val name = "ping"
}
@IdentifiableAs("ping-server")
class PingCommandServer {
val name = "ping"
...
} And that resolves the conflict, the two commands will operate as usual. (in terms of hierarchy, server commands take more priority than global commands). |
…hods and uses JVM annotations to make JVM use better, removes unused Pair class and resolves a possible memory leak.
…en inheritance system
As part of compatibility changes for v3.6.0 of Javacord, Nexus is introducing a step forward into beta release, including a magnitude of breaking changes and improvements that will help shape your bot and allow for further scaling.
🧭 Changes
This pull request may not contain the full magnitude of changes but will include as many of the breaking changes as possible and provide a way to resolve the differences.
📟 Synchronizer
The Nexus Synchronizer has been rewritten from the bottom up once more to be better and simpler. It's major change has to do with how the new synchronization methods are written and also with its behavior where it will now use the return values from Discord to create an in-memory index map (contrary to the prior version which did nothing and discarded the result).
All public APIs in regard to the synchronizer have not been changed but the synchronize methods have undergone quite some change with the interface being rewritten to look like the following:
The previous version looked a lot more like this:
The changes in how the synchronize methods are created reflect the new behavior of the synchronizer which now utilizes the return values. You can check the default synchronize methods to have a guide over how to write the methods.
Another particular breaking change with the synchronizer involves how you change the synchronize methods, previously it used to be like this:
In the beta version, it has been simplified to look like this:
🚒 EngineX
For all the people who have been using EngineX, these new changes will definitely be a major improvement, especially for people who are using sharding. Nexus EngineX (coincidentally named how NGINX is called) now has better support for CompletableFutures with the following new methods introduced:
All
await
methods use the queue feature of EngineX internally while also using the newfailFutureOnExpire
which will listen to expiration changes to fail the CompletableFuture if no shard has taken the request after the expiration time has been reached (default: 15 minutes).An example of how this is being used is:
It's a simple example that demonstrates how to create Nexus and how to use EngineX at the same time. EngineX is more of a shard router that routes "events" onto shards to process them without creating an entire messy logic to wait for the shards themselves.
EngineX listens to this line (
nexus.getShardManager().put(shard)
) to know when a shard is available.The example given simply prints out "Shard X is processing this one" to console with
X
being the shard that announces their presence first to Nexus.Another breaking change with EngineX's existing APIs has to do with the store that had no real purpose. I don't really remember what the store was added for but for all the bots that I've written with Nexus, the store has been unused and the internals also doesn't use it. Therefore, the store has been removed. The new signature of EngineX events looks like this:
(shard) -> ...
In an example method, it would look like this:
Additionally, the EngineX should now be more safer against thread issues (e.g. deadlocks or race conditions).
📦 Command Manager
The command manager has been extended to include support methods for people who want to export their in-memory index map that was created by Nexus into their data stores (e.g. Redis or any database), it will also support importing the stored indexes to save time processing.
In particular, the following methods were added:
To export the in-memory index, you can use the following:
The
NexusCommandIndex
is composed of two properties:command()
which returns theNexusCommand
itself.applicationCommandId()
which returns the stored application command identifier from Discord.You can then store those two properties in any data store that you like e.g. Redis then import them with the indexer method or the other methods (if you prefer, the synchronizer should already index all commands though):
Alternatively without the indexer method:
Other than those changes, the command manager has been changed internally to be more verbose and is now being used by the synchronizer actively.
🌏 Core Changes
The Nexus Core itself has been changed minorly but might be breaking for some. In particular, all properties related to
Nexus.start()
like theonShardLogin
andDiscordApiBuilder
from the Nexus Builder have been removed as there is no real purpose for using those methods.Nexus shouldn't be responsible for creating your shards or booting them up as this leaves little control for the developers to create their own clustering system which is important for larger bots.
If you followed the examples on the README.md and other related examples which never used the following methods then you should be fine ⚡.
📄 Installation
You can install this version of Nexus ahead of time by using Jitpack: 1.0.0-beta-SNAPSHOT