Warning
This post was published 113 days ago. The information described in this article may have changed.
use serde_json::Value;
use std::{cell::RefCell, collections::HashMap, rc::Rc};
pub struct Event {
name: String, // 事件名
data: Option<Value>, // 数据使用Value格式
}
impl Event {
pub fn new(name: &str, data: Option<Value>) -> Self {
Self {
name: name.to_string(),
data,
}
}
}
// type EventListener = fn(Option<Value>);
type EventListener = Box<dyn FnMut(Option<Value>)>;
type ListenersMap = HashMap<String, Vec<EventListener>>;
struct EventDispatcher {
listeners: ListenersMap,
}
impl EventDispatcher {
pub fn new() -> Self {
Self {
listeners: HashMap::new(),
}
}
pub fn dispatch_event(&mut self, event: Event) {
if let Some(listeners) = self.listeners.get_mut(&event.name) {
for listener in listeners {
listener(event.data.clone());
}
}
}
pub fn add_event_listener(&mut self, name: &str, listener: EventListener) {
let arr = self
.listeners
.entry(name.to_string())
.or_insert_with(Vec::new);
arr.push(listener);
// let func = &(listener);
// if !arr.contains(func) {
// arr.push(listener);
// }
}
pub fn on(&mut self, name: &str, listener: EventListener) {
self.add_event_listener(name, listener);
}
pub fn emit(&mut self, name: &str, params: Option<Value>) {
self.dispatch_event(Event::new(name, params))
}
}
trait PluginOptions {
fn name(&self) -> &str;
fn deps(&self) -> Vec<&str>;
fn install(&mut self, engine: &mut Engine);
fn dispose(&mut self, engine: &mut Engine);
}
trait StrategyOptions {
fn name(&self) -> &str;
fn condition(&self) -> Vec<&str>;
fn exec(&self, engine: &mut Engine);
fn rollback(&mut self, engine: &mut Engine);
}
type PluginsMap = HashMap<String, Box<dyn PluginOptions>>;
type StrategysMap = HashMap<String, Box<dyn StrategyOptions>>;
struct Engine {
event: EventDispatcher,
plugins: PluginsMap,
strategys: StrategysMap,
}
impl Engine {
pub fn new() -> Self {
Self {
event: EventDispatcher::new(),
plugins: HashMap::new(),
strategys: HashMap::new(),
}
}
pub fn install<P: PluginOptions + 'static>(&mut self, plugin: P) -> String {
let name = plugin.name();
if !self.plugins.contains_key(name) {
// 不存在对应的插件
// 检查插件依赖
let mut deps: Vec<&str> = Vec::new();
for dep in plugin.deps() {
// 依赖插件不存在
if !self.plugins.contains_key(dep) {
deps.push(dep);
}
}
if !deps.is_empty() {
// 提示错误
return format!(
"安装插件 '{}' 出错:依赖插件 '{}' 不存在",
name,
deps.join(",")
);
}
// 执行插件安装方法
let mut plugin_box = Box::new(plugin);
plugin_box.install(self);
// 记录插件
self.plugins
.insert(plugin_box.name().to_string(), plugin_box);
}
"".to_string()
}
pub fn uninstall(&mut self, plugin_name: &str) {
if let Some(mut plugin) = self.plugins.remove(plugin_name) {
// 策略B依赖插件A,插件A被卸载,关联的策略B也要被回滚
let mut strategies = Vec::new();
for (_, strategy) in self.strategys.iter() {
if strategy.condition().contains(&plugin_name) {
strategies.push(strategy.name().to_string());
}
}
// 执行回滚操作
for strategy_name in strategies {
self.rollback(&strategy_name);
}
// 插件B依赖插件A,插件A被卸载,关联的插件B也要被卸载
let mut plugins = Vec::new();
for (_, plugin) in self.plugins.iter() {
if plugin.deps().contains(&plugin_name) {
plugins.push(plugin.name().to_string());
}
}
// 执行关键插件的卸载
for plugin_name in plugins {
self.uninstall(&plugin_name);
}
// 执行销毁方法
plugin.dispose(self);
} else {
println!("插件 {} 不存在", plugin_name)
}
}
pub fn exec<S: StrategyOptions + 'static>(&mut self, strategy: S) -> String {
let name = strategy.name();
if !self.strategys.contains_key(name) {
// 不存在对应的策略
// 检查策略依赖
let mut plugins: Vec<&str> = Vec::new();
for plugin in strategy.condition() {
// 依赖插件不存在,记录起来
if !self.plugins.contains_key(plugin) {
plugins.push(plugin);
}
}
if plugins.len() > 0 {
// 提示错误
return format!(
"执行策略 '{}' 出错:依赖插件 '{}' 不存在",
name,
plugins.join(",")
);
}
// 执行策略
strategy.exec(self);
// 记录策略
self.strategys
.insert(strategy.name().to_string(), Box::new(strategy));
}
"".to_string()
}
pub fn rollback(&mut self, strategy_name: &str) {
// 找到与name对应的策略并删除
if let Some(mut strategy) = self.strategys.remove(strategy_name) {
// 执行回滚方法
strategy.rollback(self);
} else {
println!("策略 {} 不存在", strategy_name)
}
}
}
struct APlugin;
impl PluginOptions for APlugin {
fn name(&self) -> &str {
"APlugin"
}
fn deps(&self) -> Vec<&str> {
vec![]
}
fn install(&mut self, engine: &mut Engine) {
println!("--APlugin--");
let engine_rc = Rc::new(RefCell::new(engine));
let engine_move = Rc::clone(&engine_rc);
let listener = Box::new(move |x| {
println!("--1--{:?}", x);
engine_move.borrow_mut().event.emit("list", None);
});
engine_rc.borrow_mut().event.on("get-list", listener);
}
fn dispose(&mut self, engine: &mut Engine) {}
}
struct BPlugin;
impl PluginOptions for BPlugin {
fn name(&self) -> &str {
"BPlugin"
}
fn deps(&self) -> Vec<&str> {
vec!["APlugin"]
}
fn install(&mut self, engine: &mut Engine) {
println!("--BPlugin--");
engine.event.emit("get-list", Some(1.into()));
engine.event.on(
"list",
Box::new(|x| {
println!("--2--{:?}", x);
}),
);
}
fn dispose(&mut self, engine: &mut Engine) {}
}
struct AStrategy;
impl StrategyOptions for AStrategy {
fn name(&self) -> &str {
"AStrategy"
}
fn condition(&self) -> Vec<&str> {
vec!["APlugin", "BPlugin"]
}
fn exec(&self, engine: &mut Engine) {
println!("--AStrategy--");
}
fn rollback(&mut self, engine: &mut Engine) {}
}
fn main() {
let mut engine = Engine::new();
engine.install(APlugin);
engine.install(BPlugin);
engine.exec(AStrategy);
}
8 posts - 3 participants
🏷️ rust_feed