pub struct PluginManager {
pub plugin_dir: String,
pub watch_rx: Option<Arc<Mutex<Receiver<Result<Event, Error>>>>>,
/* private fields */
}Expand description
插件管理器
Fields§
§plugin_dir: String插件目录路径
watch_rx: Option<Arc<Mutex<Receiver<Result<Event, Error>>>>>文件系统监听事件接收器(可选)
Implementations§
Source§impl PluginManager
impl PluginManager
Sourcepub async fn new(config: PluginManagerConfig) -> PluginManagerResult<Self>
pub async fn new(config: PluginManagerConfig) -> PluginManagerResult<Self>
Sourcepub async fn load_all_plugins(&self) -> PluginManagerResult<()>
pub async fn load_all_plugins(&self) -> PluginManagerResult<()>
加载所有插件
从配置的插件目录中扫描并加载所有插件文件(.spk 格式)。 加载过程包括签名验证、解包、动态库加载和实例创建。 子插件会在父插件加载完成后自动挂载到对应的父插件上。
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§行为
- 清空并重新创建临时目录
- 扫描插件目录,查找所有
.spk文件 - 逐个加载插件,主插件直接插入,子插件暂存
- 所有主插件加载完成后,将子插件挂载到对应的父插件
- 如果某个插件加载失败,会记录错误但继续加载其他插件
§错误
- 如果插件目录不存在,会记录警告但不会返回错误
- 如果某个插件加载失败,会记录错误但继续处理其他插件
§示例
manager.load_all_plugins().await?;Sourcepub async fn insert_plugin_instance(
&self,
plugin_instance: PluginInstance,
) -> PluginManagerResult<()>
pub async fn insert_plugin_instance( &self, plugin_instance: PluginInstance, ) -> PluginManagerResult<()>
将插件实例写入管理器
将已创建的插件实例插入到插件管理器的映射表中。 此方法用于主插件的插入,会记录详细的加载日志。
§参数
plugin_instance- 要插入的插件实例
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§行为
- 使用插件的ID作为键插入到映射表
- 记录包含插件ID、名称、版本和指纹的详细日志
- 使用 tracing span 注入上下文信息,便于日志追踪
§注意
此方法只用于主插件。子插件应使用 insert_child_plugin 方法。
§示例
// ... 创建 plugin_instance ...
manager.insert_plugin_instance(plugin_instance).await?;Sourcepub async fn insert_child_plugin(
&self,
plugin_instance: PluginInstance,
) -> PluginManagerResult<()>
pub async fn insert_child_plugin( &self, plugin_instance: PluginInstance, ) -> PluginManagerResult<()>
将子插件挂载到对应父插件
将子插件实例插入到插件管理器,并同时将其信息添加到父插件的 child_plugins 列表中。
这确保了父子插件关系的正确建立。
§参数
plugin_instance- 要插入的子插件实例
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§错误
PluginManagerError::Other- 如果子插件未配置父插件IDPluginManagerError::NotFound- 如果父插件不存在
§行为
- 检查子插件是否配置了父插件ID
- 验证父插件是否存在
- 将子插件信息添加到父插件的
child_plugins列表 - 将子插件实例插入到映射表
- 记录详细的挂载日志
§示例
// ... 创建子插件实例 ...
manager.insert_child_plugin(child_instance).await?;Sourcepub async fn initialize_all_plugins(&self) -> PluginManagerResult<()>
pub async fn initialize_all_plugins(&self) -> PluginManagerResult<()>
初始化所有插件
批量初始化所有处于 Loaded 状态的插件。
初始化顺序会优先处理主插件,然后处理子插件,确保依赖关系的正确初始化。
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§行为
- 只初始化状态为
Loaded的插件 - 按照主插件优先、子插件其次的顺序初始化
- 如果某个插件初始化失败,会将其状态设置为
Error,但继续初始化其他插件 - 初始化超时也会将插件状态设置为
Error
§状态转换
Loaded->Initialized: 初始化成功Loaded->Error: 初始化失败或超时
§示例
manager.initialize_all_plugins().await?;Sourcepub async fn initialize_plugin(
&self,
plugin_id: &str,
) -> PluginManagerResult<()>
pub async fn initialize_plugin( &self, plugin_id: &str, ) -> PluginManagerResult<()>
初始化单个插件(公开方法)
初始化指定的插件。插件必须处于 Loaded 状态才能初始化。
初始化过程会调用插件的 initialize() 方法,并设置默认配置。
§参数
plugin_id- 要初始化的插件ID
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§错误
PluginManagerError::NotFound- 如果指定的插件不存在PluginManagerError::StateError- 如果插件状态不正确或状态转换无效PluginManagerError::ExecutionError- 如果初始化失败或超时
§状态转换
Loaded->Initialized: 初始化成功Loaded->Error: 初始化失败或超时
§配置
初始化时会使用默认配置,并设置 enabled = true。
§示例
manager.initialize_plugin("my-plugin").await?;Sourcepub async fn start_all_plugins(&self) -> PluginManagerResult<()>
pub async fn start_all_plugins(&self) -> PluginManagerResult<()>
启动所有插件
批量启动所有处于 Initialized 状态的插件。
启动顺序会优先处理主插件,然后处理子插件,确保依赖关系的正确启动。
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§行为
- 只启动状态为
Initialized的插件 - 按照主插件优先、子插件其次的顺序启动
- 如果某个插件启动失败,会将其状态设置为
Error,但继续启动其他插件 - 启动超时也会将插件状态设置为
Error
§状态转换
Initialized->Running: 启动成功Initialized->Error: 启动失败或超时
§示例
manager.start_all_plugins().await?;Sourcepub async fn start_plugin(&self, plugin_id: &str) -> PluginManagerResult<()>
pub async fn start_plugin(&self, plugin_id: &str) -> PluginManagerResult<()>
启动单个插件(公开方法)
启动指定的插件。插件必须处于 Initialized 状态才能启动。
启动过程会调用插件的 start() 方法。
§参数
plugin_id- 要启动的插件ID
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§错误
PluginManagerError::NotFound- 如果指定的插件不存在PluginManagerError::StateError- 如果插件状态不正确或状态转换无效PluginManagerError::ExecutionError- 如果启动失败或超时
§状态转换
Initialized->Running: 启动成功Initialized->Error: 启动失败或超时
§示例
manager.start_plugin("my-plugin").await?;Sourcepub async fn stop_all_plugins(&self) -> PluginManagerResult<()>
pub async fn stop_all_plugins(&self) -> PluginManagerResult<()>
停止所有插件
批量停止所有处于 Running 状态的插件。
停止顺序会优先处理子插件,然后处理主插件,确保依赖关系的正确停止。
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§行为
- 只停止状态为
Running的插件 - 按照子插件优先、主插件其次的顺序停止
- 如果某个插件停止失败,会将其状态设置为
Error,但继续停止其他插件 - 停止超时也会将插件状态设置为
Error
§状态转换
Running->Stopped: 停止成功Running->Error: 停止失败或超时
§示例
manager.stop_all_plugins().await?;Sourcepub async fn stop_plugin(&self, plugin_id: &str) -> PluginManagerResult<()>
pub async fn stop_plugin(&self, plugin_id: &str) -> PluginManagerResult<()>
停止单个插件(公开方法)
停止指定的插件。插件必须处于 Running 状态才能停止。
停止过程会调用插件的 stop() 方法。
§参数
plugin_id- 要停止的插件ID
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§错误
PluginManagerError::NotFound- 如果指定的插件不存在PluginManagerError::StopFailed- 如果停止失败(插件状态变为Error)
§状态转换
Running->Stopped: 停止成功Running->Error: 停止失败或超时
§示例
manager.stop_plugin("my-plugin").await?;Sourcepub async fn unload_plugin(&self, plugin_id: String) -> PluginManagerResult<()>
pub async fn unload_plugin(&self, plugin_id: String) -> PluginManagerResult<()>
卸载单个插件
从插件管理器中卸载指定的插件。卸载过程包括:
- 停止插件(如果正在运行)
- 检查依赖关系
- 递归卸载所有子插件
- 从父插件中移除子插件信息(如果是子插件)
- 移除插件实例并清理临时文件
§参数
plugin_id- 要卸载的插件ID
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§错误
PluginManagerError::ValidationFailed- 如果插件ID为空PluginManagerError::NotFound- 如果插件不存在PluginManagerError::DependencyError- 如果有其他插件依赖此插件PluginManagerError::UninstallFailed- 如果停止插件失败
§行为
- 如果插件正在运行,会先停止插件
- 检查是否有其他插件依赖此插件,如果有则拒绝卸载
- 递归卸载所有子插件
- 如果是子插件,从父插件中移除子插件信息
- 移除插件实例并清理临时文件
§注意
卸载会永久删除插件的临时文件,请确保在调用前已保存必要数据。
§示例
manager.unload_plugin("my-plugin".to_string()).await?;Sourcepub async fn unload_all_plugins(&self) -> PluginManagerResult<()>
pub async fn unload_all_plugins(&self) -> PluginManagerResult<()>
Sourcepub async fn reload_plugin_directory(&self) -> PluginManagerResult<()>
pub async fn reload_plugin_directory(&self) -> PluginManagerResult<()>
重新加载插件目录
卸载所有当前已加载的插件,然后重新扫描插件目录并加载所有插件。 这是一个便捷方法,用于刷新整个插件目录的状态。
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§行为
- 卸载所有当前已加载的插件(如果存在)
- 重新扫描插件目录,查找所有
.spk文件 - 加载所有找到的插件
- 子插件会自动挂载到对应的父插件
§错误
PluginManagerError::Io- 如果插件目录操作失败PluginManagerError::LoadFailed- 如果加载插件时发生错误- 卸载过程中的错误会被记录但不会中断流程
§注意
- 此方法会卸载所有插件,包括正在运行的插件
- 重新加载后,插件状态为
Loaded,需要手动调用initialize_all_plugins()和start_all_plugins()来初始化和启动 - 如果某个插件加载失败,会记录错误但继续加载其他插件
§示例
// 重新加载插件目录
manager.reload_plugin_directory().await?;
// 初始化和启动所有插件
manager.initialize_all_plugins().await?;
manager.start_all_plugins().await?;Sourcepub async fn execute_plugin(
&self,
plugin_id: &str,
action: &str,
params: Value,
) -> PluginManagerResult<Value>
pub async fn execute_plugin( &self, plugin_id: &str, action: &str, params: Value, ) -> PluginManagerResult<Value>
执行插件功能
调用指定插件的 execute 方法来执行特定的功能操作。
插件必须处于运行状态才能执行。
§参数
plugin_id- 要执行功能的插件IDaction- 要执行的动作名称,会被验证长度和格式params- 传递给插件执行的参数,使用 JSON 格式
§返回值
PluginManagerResult<serde_json::Value>- 成功时返回插件执行的结果(JSON 格式)
§错误
PluginManagerError::NotFound- 如果指定的插件不存在PluginManagerError::StateError- 如果插件未处于运行状态PluginManagerError::ValidationFailed- 如果动作名称验证失败PluginManagerError::ExecutionError- 如果插件执行失败或超时
§执行流程
- 验证并清理插件ID
- 验证动作名称参数
- 检查插件是否存在且处于运行状态
- 调用插件的
execute方法(带超时保护) - 返回执行结果或错误信息
§示例
use serde_json::json;
let params = json!({"key": "value"});
let result = manager.execute_plugin("my-plugin", "my_action", params).await?;
println!("执行结果: {}", result);Sourcepub async fn register_all_plugin_routes(
&self,
cfg: &mut ServiceConfig,
) -> PluginManagerResult<()>
pub async fn register_all_plugin_routes( &self, cfg: &mut ServiceConfig, ) -> PluginManagerResult<()>
注册所有插件的路由
为所有处于运行状态且配置了路由的插件注册 HTTP 路由。 注册顺序会优先处理主插件,然后处理子插件,确保路由注册的正确顺序。
§参数
cfg- Actix Web 的服务配置对象,用于注册路由
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§行为
- 只注册状态为
Running且配置了路由的插件 - 按照主插件优先、子插件其次的顺序注册
- 如果某个插件路由注册失败,会记录错误但继续注册其他插件
- 注册完成后会输出统计信息(成功数、失败数、总数)
§错误
- 通常不会返回错误,即使部分插件注册失败也会继续执行
§示例
use actix_web::web;
let mut cfg = web::ServiceConfig::default();
manager.register_all_plugin_routes(&mut cfg).await?;Sourcepub fn register_all_plugin_routes_sync(
&self,
cfg: &mut ServiceConfig,
) -> PluginManagerResult<()>
pub fn register_all_plugin_routes_sync( &self, cfg: &mut ServiceConfig, ) -> PluginManagerResult<()>
注册所有插件的路由(同步版本)
这是 register_all_plugin_routes 的同步版本,可以在非异步上下文中调用。
内部会尝试使用当前的 Tokio 运行时句柄,如果不存在则创建新的运行时。
§参数
cfg- Actix Web 的服务配置对象,用于注册路由
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§示例
use actix_web::web;
let mut cfg = web::ServiceConfig::default();
manager.register_all_plugin_routes_sync(&mut cfg)?;Sourcepub async fn get_all_plugins(&self) -> PluginManagerResult<Vec<PluginInfo>>
pub async fn get_all_plugins(&self) -> PluginManagerResult<Vec<PluginInfo>>
查询所有插件信息
获取插件管理器中所有已加载插件的详细信息,包括元数据、状态、指纹和子插件列表。 返回的信息是只读的,不包含插件实例的内部实现细节。
§返回值
PluginManagerResult<Vec<PluginInfo>>- 成功时返回所有插件的PluginInfo列表
§错误
- 通常不会返回错误,除非发生内部系统错误
§示例
let plugin_infos = manager.get_all_plugins().await?;
for info in plugin_infos {
println!("插件: {}, 状态: {:?}", info.metadata.name, info.status);
}Sourcepub async fn get_plugin(
&self,
plugin_id: &str,
) -> PluginManagerResult<PluginInfo>
pub async fn get_plugin( &self, plugin_id: &str, ) -> PluginManagerResult<PluginInfo>
查询单个插件信息
根据插件ID获取指定插件的详细信息,包括元数据、状态、指纹和子插件列表。 插件ID会被自动清理和验证,防止注入攻击。
§参数
plugin_id- 要查询的插件ID
§返回值
PluginManagerResult<PluginInfo>- 成功时返回插件的PluginInfo
§错误
PluginManagerError::NotFound- 如果指定的插件不存在PluginManagerError::ValidationFailed- 如果插件ID验证失败
§示例
let plugin_info = manager.get_plugin("my-plugin").await?;
println!("插件名称: {}", plugin_info.metadata.name);
println!("插件状态: {:?}", plugin_info.status);Sourcepub async fn disable_plugin(&self, plugin_id: &str) -> PluginManagerResult<()>
pub async fn disable_plugin(&self, plugin_id: &str) -> PluginManagerResult<()>
禁用插件
将指定插件设置为禁用状态。禁用后的插件不会处理请求,但保持已加载状态。
插件必须处于 Loaded、Initialized、Running 或 Stopped 状态才能被禁用。
§参数
plugin_id- 要禁用的插件ID
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§错误
PluginManagerError::NotFound- 如果指定的插件不存在PluginManagerError::StateError- 如果插件状态不允许禁用
§行为
- 如果插件正在运行,会先停止插件
- 将插件状态设置为
Disabled - 禁用后的插件不会处理任何请求
§状态转换
Running->Stopped->Disabled: 如果插件正在运行Initialized->Disabled: 如果插件已初始化Stopped->Disabled: 如果插件已停止Loaded->Disabled: 如果插件已加载但未初始化
§注意
- 禁用插件不会卸载插件,插件仍然占用资源
- 禁用后的插件可以通过重新启动来恢复运行
- 如果插件正在运行,禁用前会先停止插件
§示例
manager.disable_plugin("my-plugin").await?;Sourcepub async fn reload_plugin(&self, plugin_id: &str) -> PluginManagerResult<()>
pub async fn reload_plugin(&self, plugin_id: &str) -> PluginManagerResult<()>
重载单个插件
重新加载指定的插件。重载过程包括:
- 检查插件是否存在并获取基本信息
- 查找插件文件路径
- 停止插件(如果正在运行)
- 卸载插件
- 重新加载插件
- 插入插件实例
- 初始化插件
- 启动插件
- 调用插件的
on_reload生命周期钩子
§参数
plugin_id- 要重载的插件ID
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§错误
PluginManagerError::NotFound- 如果插件不存在或插件文件未找到PluginManagerError::ValidationFailed- 如果插件ID验证失败PluginManagerError::UninstallFailed- 如果停止或卸载插件失败PluginManagerError::LoadFailed- 如果重新加载插件失败PluginManagerError::InitializationFailed- 如果插件初始化失败PluginManagerError::StartFailed- 如果插件启动失败
§行为
- 如果插件正在运行,会先停止插件
- 重载后会恢复插件的运行状态(如果之前是运行状态)
- 重载过程中会调用插件的
on_reload生命周期钩子
§注意
重载会重新加载插件的动态库,可能会丢失插件内部的状态。
插件可以通过 on_reload 钩子保存和恢复状态。
§示例
manager.reload_plugin("my-plugin").await?;Sourcepub async fn watch_plugin_directory(&mut self) -> PluginManagerResult<()>
pub async fn watch_plugin_directory(&mut self) -> PluginManagerResult<()>
启动插件目录监听
监听插件目录的变化,当检测到新的 .spk 文件时自动加载,删除时自动卸载。
监听器在后台异步运行,不会阻塞调用线程。
§返回值
PluginManagerResult<()>- 成功时返回Ok(())
§行为
- 监听插件目录的文件系统事件
- 当检测到新的
.spk文件时,自动加载插件 - 当检测到
.spk文件删除时,自动卸载对应插件 - 当检测到
.spk文件修改时,重新加载插件 - 使用防抖机制,避免频繁触发(默认延迟 500ms)
§错误
PluginManagerError::Io- 如果创建监听器失败PluginManagerError::ConfigError- 如果插件目录不存在PluginManagerError::Other- 如果已经在监听中
§注意
- 如果已经在监听,调用此方法会返回错误
- 使用
stop_watching()方法可以停止监听
§示例
manager.watch_plugin_directory().await?;
// 监听器在后台运行
// ...
manager.stop_watching().await?;Sourcepub async fn stop_watching(&mut self) -> PluginManagerResult<()>
pub async fn stop_watching(&mut self) -> PluginManagerResult<()>
Auto Trait Implementations§
impl Freeze for PluginManager
impl !RefUnwindSafe for PluginManager
impl Send for PluginManager
impl Sync for PluginManager
impl Unpin for PluginManager
impl !UnwindSafe for PluginManager
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more