A flexible and easy-to-use plugin management system for Rust applications. It provides a robust foundation for building plugin-based architectures in Rust applications.
The Plugin Manager library allows dynamic loading, registration, and management of plugins at runtime. It supports individual plugins and grouped plugins, making it suitable for various application architectures.
- Dynamic loading of plugins from shared object files (
.soLinux,.dllWindows,.dylibMacOS) - Support for individual and grouped plugins
- Plugin registration and deregistration
- Execution of plugin functionality
- Metadata-driven plugin configuration
The package can either be installed via cargo add or the Cargo.toml file.
cargo add
cargo add plugin-manageror
Cargo.toml file
[dependencies]
plugin-manager = "0.1.0"To create a plugin, implement the Plugin trait and export a create_plugins function:
The as_any method is required to allow access to the methods not
mentioned in the Plugin trait, and needs to be set up to return self.
use plugin_manager::Plugin;
use std::any::Any;
#[derive(Debug)]
struct MyPlugin;
impl Plugin for MyPlugin {
fn name(&self) -> String {
"my_plugin".to_string()
}
fn execute(&self, _context: &dyn Any) -> Result<(), Box<dyn std::error::Error>> {
println!("Executing MyPlugin");
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[unsafe(no_mangle)]
pub fn create_plugins() -> Vec<Box<dyn Plugin>> {
vec![Box::new(MyPlugin)]
}When creating a plugin, you need to set up your Cargo.toml file correctly:
- Add the
plugin_manageras a dependency:
[dependencies]
plugin_manager = "0.1.0"- Configure the library to be both a Rust library and a dynamic library:
[lib]
name = "your_plugin_name"
crate-type = ["lib", "cdylib"]This configuration allows your plugin to be compiled as both a Rust library and a dynamic library, which is necessary for the PluginManager to load it at runtime.
To build your plugin for use with the main project:
-
Navigate to your plugin's directory.
-
Run the following command to build the plugin as a dynamic library:
cargo build --release
-
The compiled dynamic library will be in the
target/releasedirectory with a name likelibyour_plugin_name.so(on Linux),libyour_plugin_name.dylib(on macOS), oryour_plugin_name.dll(on Windows).
Both the main project using plugins and the individual plugin projects are end users of the plugin_manager.
-
Main Project Cargo.toml:
- Located in the root of the project that will use plugins.
- Includes
plugin_manageras a dependency. - Does not need the
crate-typespecification. - Does not contain any metadata for plugin configuration.
- The loaded plugins are dependant on the plugins specified in the
End-User'sproject Cargo.toml.
Example:
[package] name = "main_project" version = "0.1.0" edition = "2024" [dependencies] plugin_manager = "0.1.0"
-
Plugin Project Cargo.toml:
- Located in a separate project directory for each plugin.
- Includes
plugin_manageras a dependency. - Specifies
crate-type = ["lib", "cdylib"]to build as both a Rust library and a dynamic library. - Does not contain plugin metadata configuration.
Example:
[package] name = "my_plugin" version = "0.1.0" edition = "2024" [dependencies] plugin_manager = "0.1.0" [lib] name = "my_plugin" crate-type = ["lib", "cdylib"]
-
End-User Project Cargo.toml:
- Includes the main project as dependencies.
- Contains metadata for plugin configuration.
Example:
[package] name = "my_application" version = "0.1.0" edition = "2024" [dependencies] main_project = "0.1.0" [package.metadata.plugins] my_plugin = "/path/to/libmy_plugin.so"
The main differences between these Cargo.toml files are:
-
The Main Project Cargo.toml sets up the core project that will use plugins:
- It includes the plugin_manager as a dependency.
- It doesn't specify crate-type or contain plugin metadata.
- The plugins it can load are determined by the End-User's project configuration.
-
The Plugin Project Cargo.toml configures individual plugin projects:
- It includes the plugin_manager as a dependency.
- It specifies crate-type as both "lib" and "cdylib" to produce a dynamic library.
- It doesn't contain any plugin metadata configuration.
-
The End-User Project Cargo.toml configures the application that will use the main project and its plugins:
- It includes the main project (not the plugin_manager directly) as a dependency.
- It contains the metadata for plugin configuration, specifying which plugins to load and how to group them.
Plugins are configured in the Cargo.toml file of the end-user project:
[package.metadata.plugins]
plugin_a = "/path/to/plugin_a.so"
[package.metadata.plugins.group_name]
plugin_b = "/path/to/plugin_b.so"
plugin_c = "/path/to/plugin_c.so"Here's a basic example of how to use the PluginManager:
use plugin_manager::PluginManager;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a new PluginManager
let mut plugin_manager = PluginManager::new();
// Activate plugins based on metadata in Cargo.toml
plugin_manager = plugin_manager.activate_plugins()?;
// Execute a specific plugin
plugin_manager.execute_plugin("plugin_a", &())?;
// Deregister a plugin
let deregistered = plugin_manager.deregister_plugin("plugin_b");
print!("Deregistered plugin: {:?}", deregistered);
// Deregister all plugins
let deregistered = plugin_manager.deregister_all_plugins();
println!("Deregistered plugins: {:?}", deregistered);
Ok(())
}This project is licensed under the Apache License, Version 2.0 - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.