Writing plugins
Plugins in nyxx are a way to create modular functionality that can be easily added or removed from
clients. There are some offical plugins - including logging and cliIntegration in the nyxx
package, but also CommandsPlugin from nyxx_commands or Pagination from nyxx_extensions - but
you can also create your own plugins for your own functionality.
Using plugins
Plugins can be added to a client by passing them to the plugins list in ClientOptions when
creating your client. For example, this client registers the logging plugin, the cliIntegration
plugin, the PluginA() plugin and the PluginB() plugin:
final client = await Nyxx.connectGateway(
  'TOKEN',
  GatewayIntents.allUnprivileged,
  options: GatewayClientOptions(plugins: [
    logging,
    cliIntegration,
    PluginA(),
    PluginB(),
  ]),
);
Plugins can be easily enabled or disabled by adding or removing them from this list, allowing you to quickly enable or disable certain features of your bot.
Some plugins in the official nyxx packages provide a ready-to-use instance. This is the case with
the logging and cliIntegration plugins above. You can always create your own instances of the
Logging or CliIntegation classes instead.
Plugin basics
The easiest way to create a plugin is to extend the NyxxPlugin class. The type argument allows you
to specify which client types your plugin can be added to.
A simple plugin that logs messages received from clients it is added to would look like this:
class LogMessages extends NyxxPlugin<NyxxGateway> {
  
  void afterConnect(NyxxGateway client) {
    client.onMessageCreate.listen((event) {
      final message = event.message;
      // logger is provided by the plugin interface.
      logger.info('${message.id} sent by ${message.author.id} in ${message.channelId}!');
    });
  }
}
Plugins can override the beforeConnect, afterConnect, beforeClose and afterClose methods to
run code at different moments in the client's lifecycle. These methods can be async and will pause
the associated method on the client until the returned future completes.
beforeConnect and afterConnect run during calls to the Nyxx.connectXXX methods.
beforeConnectruns before the client establishes any connections to Discord, so it's a good idea to put any plugin initialisation here.afterConnectruns once the client has opened a connection to Discord. This is the first time your plugin will be able to access the client, so any setup requiring the client (e.g listening to events) should go here.
Putting plugin initialisation in afterConnect will cause any events received during the plugin's
initialisation to be dropped. The client is only returned to the caller after the call to
afterConnect completes.
beforeClose and afterClose run during calls to client.close().
beforeCloseruns before the client has disconnected from Discord. Put any cleanup that requires the client here.afterCloseruns once the client has completely disconnected from Discord. Since the client is disconnected, it can no longer be used and will not be passed to your plugin.
Plugin states
By default, plugins can be added to multiple clients at once, and the same plugin instance will manage multiple client. Plugin states are a way for your plugins to create a state for each client they are attached to.
You can create a state for your plugin by implementing the NyxxPluginState class and overriding
the createState method in your plugin. Any functionality that should be run in a separate instance
for each client should then be moved into the state class, which has the same methods as the main
plugin class: beforeConnect, afterConnect, beforeClose and afterClose.
The methods in the state class should call the super-method to ensure that the main plugin class' methods are also called.
Whether the method is called before or after your own code doesn't matter,
For example, this plugin creates a timer for each client that periodically logs the client's guild cache size:
class LogGuildCache extends NyxxPlugin<NyxxRest> {
  
  NyxxPluginState<NyxxRest, LogGuildCache> createState() => LogGuildCacheState(this);
}
class LogGuildCacheState extends NyxxPluginState<NyxxRest, LogGuildCache> {
  LogGuildCacheState(super.plugin);
  late final Timer timer;
  
  void afterConnect(NyxxRest client) {
    super.afterConnect(client);
    timer = Timer.periodic(const Duration(seconds: 5), (timer) {
      logger.info('Guild cache size: ${client.guilds.cache.length}');
    });
  }
  
  void afterClose() {
    super.afterClose();
    timer.cancel();
  }
}
Each client this plugin is added to will have its own instance of LogGuildCacheState, so different
clients will have a different timer.