Abstract plugins from main codebase#4
Conversation
motorlatitude
commented
Apr 21, 2026
- Abstracted plugin logic to tidy up codebase
- Add error handling in a new error module
- Abstracted plugin logic to tidy up codebase - Add error handling in a new error module
There was a problem hiding this comment.
Pull request overview
This PR refactors the bot into a plugin-based architecture, moving most command/event logic out of main.rs into discrete plugins, and introduces centralized error types for storage and plugins.
Changes:
- Introduces a
MotorbotPlugintrait +PluginContext, and updates the runtime to dispatch Discord events to loaded plugins. - Adds new plugins (ping/time/dice/coin-toss/debug/points/jokes/patches) and reworks the patches logic to fit the plugin system.
- Replaces the storage error module and wires storage errors into the crate-wide error type.
Reviewed changes
Copilot reviewed 23 out of 24 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/storage/errors.rs | Removed legacy storage error module. |
| src/storage/error.rs | New storage error type (StorageError) with Display and conversions. |
| src/storage/database.rs | Updates DB layer to wrap/propagate the new crate-wide error + expands guild config keys/values. |
| src/storage.rs | Exposes storage::error module and re-exports StorageError. |
| src/plugins/time.rs | Adds TimePlugin slash command implementation. |
| src/plugins/points.rs | Adds points/voting plugin, including channel configuration and reaction handlers. |
| src/plugins/ping.rs | Adds PingPlugin slash command implementation. |
| src/plugins/patches/platforms/platform.rs | Adds Default derive for Platform (using Unknown). |
| src/plugins/patches/patches_plugin.rs | Removes old patches plugin implementation (pre-plugin-architecture). |
| src/plugins/patches/mod.rs | Removes old patches module root in favor of patches.rs. |
| src/plugins/patches.rs | New patches plugin implementation + scheduled update loop and slash commands. |
| src/plugins/mod.rs | Registers all plugin modules. |
| src/plugins/jokes.rs | Adds daily jokes plugin + channel configuration and scheduled posting. |
| src/plugins/dice.rs | Adds dice roll slash command plugin. |
| src/plugins/debug.rs | Adds debug plugin (whoami/version/plugins/events config). |
| src/plugins/coin_toss.rs | Adds coin toss slash command plugin. |
| src/plugin/plugin_info.rs | Adds PluginInfo struct used by the plugin system. |
| src/plugin/plugin_context.rs | Adds plugin context + event reporting to configured channels. |
| src/plugin/error.rs | Adds plugin-specific error enum (PluginError). |
| src/plugin.rs | Adds core plugin trait and the option! helper macro. |
| src/main.rs | Refactors main event handler to dispatch to plugins and emit startup/error events via PluginContext. |
| src/error.rs | Adds crate-wide Error + Result types and conversions. |
| Cargo.toml | Adds async-trait and derive_more; removes unused OpenAI dependency. |
| Cargo.lock | Dependency updates aligned with Cargo.toml changes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
…downvote to avoid potential panics Co-authored-by: Copilot <copilot@github.com>
…improve error handling in update method for patches plugin Co-authored-by: Copilot <copilot@github.com>
…er-compose for plugin abstraction AI command has been deprecated during this abstraction as it wasn't being used any way.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 25 out of 26 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…n a hardcoded constant
Co-authored-by: Copilot <copilot@github.com>
Carries out input sanitisation to ensure dice side is between 2 and 100 inclusive
…array case Co-authored-by: Copilot <copilot@github.com>
…red all open database instances are closed Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
…plugin; replace PluginError usage with custom error variants Co-authored-by: Copilot <copilot@github.com>
motorlatitude
left a comment
There was a problem hiding this comment.
Some improvements
| use crate::plugin::PluginError; | ||
| use crate::{Error, Result}; | ||
|
|
||
| use crate::plugin::{MotorbotPlugin, PluginContext, PluginInfo}; |
There was a problem hiding this comment.
Consider combining these
| CreateInteractionResponse::Message( | ||
| CreateInteractionResponseMessage::new().content( | ||
| format!( | ||
| ":alarm_clock: The current time is: {}", |
There was a problem hiding this comment.
Consider using one of the custom pixel emojis instead of the standard alarm clock. Maybe the moon emoji?
| command | ||
| .create_response( | ||
| &p_ctx.ctx.http, | ||
| CreateInteractionResponse::Message( | ||
| CreateInteractionResponseMessage::new().content( | ||
| format!( | ||
| ":alarm_clock: The current time is: {}", | ||
| current_time | ||
| ), | ||
| ), | ||
| ), | ||
| ) | ||
| .await | ||
| .map_err(|err| { | ||
| Error::Plugin(PluginError::FailedToRespond { err }) | ||
| })?; |
There was a problem hiding this comment.
Maybe create a macro for this to standardise the response process for most plugins
| use crate::plugin::PluginError; | ||
| use crate::{Error, Result}; | ||
|
|
||
| use crate::plugin::{MotorbotPlugin, PluginContext, PluginInfo}; |
There was a problem hiding this comment.
Consider combining these
| async fn on_ready(&self, p_ctx: &PluginContext) -> Result<()> { | ||
| info!("Ping Plugin is ready!"); | ||
|
|
||
| let _ = Command::create_global_command( |
There was a problem hiding this comment.
No need for let _ here, prefer using question mark notation
| } | ||
| } | ||
|
|
||
| pub struct GuildConfig { |
| /// not found, it returns None. | ||
| /// * `Err(Error)` - If there is an error during the database query, it | ||
| /// returns a [Error] variant with details about the failure. | ||
| pub async fn get_guild_config( |
There was a problem hiding this comment.
Rename to match other methods, remove "get". Should be guild_config
|
|
||
| mod plugin; | ||
| use plugin::MotorbotPlugin; | ||
| struct Handler { |
| let subscriber = FmtSubscriber::builder().with_max_level(level).finish(); | ||
| tracing::subscriber::set_global_default(subscriber) | ||
| .expect("setting default subscriber failed"); |
There was a problem hiding this comment.
Check if something other than local can used here to separate MotorBot logging from Serenity logging
| pub mod plugin_context; | ||
| pub mod plugin_info; |
There was a problem hiding this comment.
Rename to context and info respectively.