PluginManager

Struct PluginManager 

Source
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

Source

pub async fn new(config: PluginManagerConfig) -> PluginManagerResult<Self>

创建新的插件管理器

创建插件管理器实例,并确保临时目录存在。 如果临时目录不存在,会自动创建。

§参数
  • config - 插件管理器配置
§返回值
  • PluginManagerResult<Self> - 成功时返回插件管理器实例
§错误
  • PluginManagerError::Io - 如果创建临时目录失败
Source

pub async fn load_all_plugins(&self) -> PluginManagerResult<()>

加载所有插件

从配置的插件目录中扫描并加载所有插件文件(.spk 格式)。 加载过程包括签名验证、解包、动态库加载和实例创建。 子插件会在父插件加载完成后自动挂载到对应的父插件上。

§返回值
  • PluginManagerResult<()> - 成功时返回 Ok(())
§行为
  • 清空并重新创建临时目录
  • 扫描插件目录,查找所有 .spk 文件
  • 逐个加载插件,主插件直接插入,子插件暂存
  • 所有主插件加载完成后,将子插件挂载到对应的父插件
  • 如果某个插件加载失败,会记录错误但继续加载其他插件
§错误
  • 如果插件目录不存在,会记录警告但不会返回错误
  • 如果某个插件加载失败,会记录错误但继续处理其他插件
§示例
manager.load_all_plugins().await?;
Source

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?;
Source

pub async fn insert_child_plugin( &self, plugin_instance: PluginInstance, ) -> PluginManagerResult<()>

将子插件挂载到对应父插件

将子插件实例插入到插件管理器,并同时将其信息添加到父插件的 child_plugins 列表中。 这确保了父子插件关系的正确建立。

§参数
  • plugin_instance - 要插入的子插件实例
§返回值
  • PluginManagerResult<()> - 成功时返回 Ok(())
§错误
  • PluginManagerError::Other - 如果子插件未配置父插件ID
  • PluginManagerError::NotFound - 如果父插件不存在
§行为
  • 检查子插件是否配置了父插件ID
  • 验证父插件是否存在
  • 将子插件信息添加到父插件的 child_plugins 列表
  • 将子插件实例插入到映射表
  • 记录详细的挂载日志
§示例
// ... 创建子插件实例 ...
manager.insert_child_plugin(child_instance).await?;
Source

pub async fn initialize_all_plugins(&self) -> PluginManagerResult<()>

初始化所有插件

批量初始化所有处于 Loaded 状态的插件。 初始化顺序会优先处理主插件,然后处理子插件,确保依赖关系的正确初始化。

§返回值
  • PluginManagerResult<()> - 成功时返回 Ok(())
§行为
  • 只初始化状态为 Loaded 的插件
  • 按照主插件优先、子插件其次的顺序初始化
  • 如果某个插件初始化失败,会将其状态设置为 Error,但继续初始化其他插件
  • 初始化超时也会将插件状态设置为 Error
§状态转换
  • Loaded -> Initialized: 初始化成功
  • Loaded -> Error: 初始化失败或超时
§示例
manager.initialize_all_plugins().await?;
Source

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?;
Source

pub async fn start_all_plugins(&self) -> PluginManagerResult<()>

启动所有插件

批量启动所有处于 Initialized 状态的插件。 启动顺序会优先处理主插件,然后处理子插件,确保依赖关系的正确启动。

§返回值
  • PluginManagerResult<()> - 成功时返回 Ok(())
§行为
  • 只启动状态为 Initialized 的插件
  • 按照主插件优先、子插件其次的顺序启动
  • 如果某个插件启动失败,会将其状态设置为 Error,但继续启动其他插件
  • 启动超时也会将插件状态设置为 Error
§状态转换
  • Initialized -> Running: 启动成功
  • Initialized -> Error: 启动失败或超时
§示例
manager.start_all_plugins().await?;
Source

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?;
Source

pub async fn stop_all_plugins(&self) -> PluginManagerResult<()>

停止所有插件

批量停止所有处于 Running 状态的插件。 停止顺序会优先处理子插件,然后处理主插件,确保依赖关系的正确停止。

§返回值
  • PluginManagerResult<()> - 成功时返回 Ok(())
§行为
  • 只停止状态为 Running 的插件
  • 按照子插件优先、主插件其次的顺序停止
  • 如果某个插件停止失败,会将其状态设置为 Error,但继续停止其他插件
  • 停止超时也会将插件状态设置为 Error
§状态转换
  • Running -> Stopped: 停止成功
  • Running -> Error: 停止失败或超时
§示例
manager.stop_all_plugins().await?;
Source

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?;
Source

pub async fn unload_plugin(&self, plugin_id: String) -> PluginManagerResult<()>

卸载单个插件

从插件管理器中卸载指定的插件。卸载过程包括:

  1. 停止插件(如果正在运行)
  2. 检查依赖关系
  3. 递归卸载所有子插件
  4. 从父插件中移除子插件信息(如果是子插件)
  5. 移除插件实例并清理临时文件
§参数
  • plugin_id - 要卸载的插件ID
§返回值
  • PluginManagerResult<()> - 成功时返回 Ok(())
§错误
  • PluginManagerError::ValidationFailed - 如果插件ID为空
  • PluginManagerError::NotFound - 如果插件不存在
  • PluginManagerError::DependencyError - 如果有其他插件依赖此插件
  • PluginManagerError::UninstallFailed - 如果停止插件失败
§行为
  • 如果插件正在运行,会先停止插件
  • 检查是否有其他插件依赖此插件,如果有则拒绝卸载
  • 递归卸载所有子插件
  • 如果是子插件,从父插件中移除子插件信息
  • 移除插件实例并清理临时文件
§注意

卸载会永久删除插件的临时文件,请确保在调用前已保存必要数据。

§示例
manager.unload_plugin("my-plugin".to_string()).await?;
Source

pub async fn unload_all_plugins(&self) -> PluginManagerResult<()>

卸载所有插件

卸载插件管理器中所有已加载的插件。 卸载顺序会优先处理子插件,然后处理主插件,确保依赖关系的正确卸载。

§返回值
  • PluginManagerResult<()> - 成功时返回 Ok(())
§行为
  • 获取所有插件的ID列表
  • 计算卸载顺序(子插件在前,父插件在后)
  • 按顺序逐个卸载插件
  • 如果某个插件卸载失败,会记录错误但继续卸载其他插件
§注意

卸载会永久删除所有插件的临时文件,请确保在调用前已保存必要数据。

§示例
manager.unload_all_plugins().await?;
Source

pub async fn reload_plugin_directory(&self) -> PluginManagerResult<()>

重新加载插件目录

卸载所有当前已加载的插件,然后重新扫描插件目录并加载所有插件。 这是一个便捷方法,用于刷新整个插件目录的状态。

§返回值
  • PluginManagerResult<()> - 成功时返回 Ok(())
§行为
  1. 卸载所有当前已加载的插件(如果存在)
  2. 重新扫描插件目录,查找所有 .spk 文件
  3. 加载所有找到的插件
  4. 子插件会自动挂载到对应的父插件
§错误
  • 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?;
Source

pub async fn execute_plugin( &self, plugin_id: &str, action: &str, params: Value, ) -> PluginManagerResult<Value>

执行插件功能

调用指定插件的 execute 方法来执行特定的功能操作。 插件必须处于运行状态才能执行。

§参数
  • plugin_id - 要执行功能的插件ID
  • action - 要执行的动作名称,会被验证长度和格式
  • params - 传递给插件执行的参数,使用 JSON 格式
§返回值
  • PluginManagerResult<serde_json::Value> - 成功时返回插件执行的结果(JSON 格式)
§错误
  • PluginManagerError::NotFound - 如果指定的插件不存在
  • PluginManagerError::StateError - 如果插件未处于运行状态
  • PluginManagerError::ValidationFailed - 如果动作名称验证失败
  • PluginManagerError::ExecutionError - 如果插件执行失败或超时
§执行流程
  1. 验证并清理插件ID
  2. 验证动作名称参数
  3. 检查插件是否存在且处于运行状态
  4. 调用插件的 execute 方法(带超时保护)
  5. 返回执行结果或错误信息
§示例
use serde_json::json;

let params = json!({"key": "value"});
let result = manager.execute_plugin("my-plugin", "my_action", params).await?;
println!("执行结果: {}", result);
Source

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?;
Source

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)?;
Source

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);
}
Source

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);
Source

pub async fn disable_plugin(&self, plugin_id: &str) -> PluginManagerResult<()>

禁用插件

将指定插件设置为禁用状态。禁用后的插件不会处理请求,但保持已加载状态。 插件必须处于 LoadedInitializedRunningStopped 状态才能被禁用。

§参数
  • 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?;
Source

pub async fn reload_plugin(&self, plugin_id: &str) -> PluginManagerResult<()>

重载单个插件

重新加载指定的插件。重载过程包括:

  1. 检查插件是否存在并获取基本信息
  2. 查找插件文件路径
  3. 停止插件(如果正在运行)
  4. 卸载插件
  5. 重新加载插件
  6. 插入插件实例
  7. 初始化插件
  8. 启动插件
  9. 调用插件的 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?;
Source

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?;
Source

pub async fn stop_watching(&mut self) -> PluginManagerResult<()>

停止插件目录监听

停止正在运行的插件目录监听器。

§返回值
  • PluginManagerResult<()> - 成功时返回 Ok(())
§错误
  • PluginManagerError::Other - 如果监听器未运行
§示例
manager.stop_watching().await?;

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more