use std::fmt::Debug;
use steckrs::{error::PluginResult, extension_point, simple_plugin, PluginManager};
struct CommandProcessor {
plugin_manager: PluginManager,
}
extension_point!(
CommandHandler:
CommandHandlerFunctions;
fn can_handle(&mut self , command: &str) -> bool;
fn handle(&mut self, command: &str, args: &[&str]) -> String;
);
extension_point!(
ByeExtPoint: ByeExtPointF;
fn say_bye(&self) -> String;
);
impl CommandProcessor {
fn new() -> Self {
Self {
plugin_manager: PluginManager::new(),
}
}
fn process_command(&mut self, input: &str) -> String {
let parts: Vec<&str> = input.split_whitespace().collect();
if parts.is_empty() {
return "Please enter a command".to_string();
}
let command = parts[0];
let args = &parts[1..];
let hooks = self
.plugin_manager
.get_enabled_hooks_by_ep_mut::<CommandHandler>();
for (_id, hook) in hooks.into_iter() {
if hook.inner_mut().can_handle(command) {
return hook.inner_mut().handle(command, args);
}
}
format!("Unknown command: {}", command)
}
fn load_plugins(&mut self) -> PluginResult<()> {
self.plugin_manager
.load_plugin(Box::new(CorePlugin::new()))?;
self.plugin_manager
.load_plugin(Box::new(EchoPlugin::new()))?;
self.plugin_manager.enable_plugin(CorePlugin::ID)?;
self.plugin_manager.enable_plugin(EchoPlugin::ID)?;
Ok(())
}
fn end(&mut self) {
let hooks = self.plugin_manager.get_enabled_hooks_by_ep::<ByeExtPoint>();
for (_id, hook) in hooks {
println!("{}", hook.inner().say_bye())
}
}
}
simple_plugin!(
CorePlugin, "core_plugin", "Core commands for the command processor", hooks: [
(CommandHandler, {HelpHook::default()}, "help"), (CommandHandler, VersionHook, "version"), (ByeExtPoint, ByeHook)
]
);
simple_plugin!(
EchoPlugin,
"echo_plugin",
"Echoes input back to the user and is a very simple plugin",
hooks: [(CommandHandler, EchoHook)]
);
#[derive(Default)]
struct HelpHook {
already_helped: bool, }
impl CommandHandlerFunctions for HelpHook {
fn can_handle(&mut self, command: &str) -> bool {
command == "help"
}
fn handle(&mut self, _command: &str, _args: &[&str]) -> String {
if self.already_helped {
eprintln!("okaaaaaaaay... helping agaaaaaaaaain....");
}
self.already_helped |= true;
"Available commands: help, version, echo".to_string()
}
}
struct VersionHook;
impl CommandHandlerFunctions for VersionHook {
fn can_handle(&mut self, command: &str) -> bool {
command == "version"
}
fn handle(&mut self, _command: &str, _args: &[&str]) -> String {
"Command Processor v1.0.0".to_string()
}
}
struct EchoHook;
impl CommandHandlerFunctions for EchoHook {
fn can_handle(&mut self, command: &str) -> bool {
command == "echo"
}
fn handle(&mut self, _command: &str, args: &[&str]) -> String {
args.join(" ")
}
}
struct ByeHook;
impl ByeExtPointF for ByeHook {
fn say_bye(&self) -> String {
"さようなら".to_string()
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut processor = CommandProcessor::new();
processor.load_plugins()?;
let commands = [
"help",
"version",
"echo Hello, Plugin System!",
"thiscommanddoesnotexist",
"help", ];
for cmd in &commands {
println!("Command: {}", cmd);
println!("Response: {}", processor.process_command(cmd));
println!("---");
}
println!("Unloading the echo plugin...");
processor.plugin_manager.unload_plugin("echo_plugin")?;
println!("\nAfter unloading echo plugin:");
println!("Command: echo This won't work anymore");
println!(
"Response: {}",
processor.process_command("echo This won't work anymore")
);
println!("---");
processor.end();
Ok(())
}