secra_plugins 0.1.32

生产级插件系统 - 插件的生命周期
Documentation
//! 插件重载相关操作

use crate::error::{PluginManagerError, PluginManagerResult};
use crate::status::PluginStatus;
use crate::manager::types::PluginMap;
use crate::manager::loader::load_plugin;
use crate::manager::query::find_plugin_file_by_id;
use crate::manager::validation::sanitize_plugin_name;
use crate::manager::load_ops::{insert_plugin_instance, insert_child_plugin};
use tokio::time::{timeout, Duration};
use tracing::{debug, error, info, trace, warn};

/// 获取插件重载所需的基本信息
///
/// 在重载插件之前,需要获取插件的基本信息,包括插件名称和运行状态。
/// 这些信息用于在重载后恢复插件的状态。
///
/// # 参数
/// * `plugins` - 插件实例的共享映射表,使用 `Arc<RwLock<>>` 保证线程安全
/// * `plugin_id` - 要重载的插件ID
///
/// # 返回值
/// * `PluginManagerResult<(String, bool)>` - 成功时返回元组:
///   - `String`: 插件名称
///   - `bool`: 插件在重载前是否处于运行状态
///
/// # 错误
/// * `PluginManagerError::NotFound` - 如果指定的插件不存在
///
/// # 示例
/// ```no_run
/// use std::sync::Arc;
/// use tokio::sync::RwLock;
/// use std::collections::HashMap;
/// 
/// # async fn example() {
/// let plugins = Arc::new(RwLock::new(HashMap::new()));
/// let (name, was_running) = get_reload_info(plugins, "my-plugin").await?;
/// # }
/// ```
pub async fn get_reload_info(
    plugins: PluginMap,
    plugin_id: &str,
) -> PluginManagerResult<(String, bool)> {
    trace!("获取插件重载信息: {}", plugin_id);
    
    let plugins = plugins.read().await;
    let plugin_instance = plugins.get(plugin_id)
        .ok_or_else(|| {
            error!("插件不存在: {}", plugin_id);
            PluginManagerError::not_found(plugin_id)
        })?;

    let plugin_name = plugin_instance.metadata.name.clone();
    let was_running = plugin_instance.status == PluginStatus::Running;
    
    debug!("插件重载信息 - 名称: {}, 运行状态: {}", plugin_name, was_running);

    Ok((plugin_name, was_running))
}

/// 调用插件的 on_reload 生命周期钩子
///
/// 在插件重载过程中,如果插件处于运行状态,会调用其 `on_reload()` 生命周期钩子。
/// 这个钩子允许插件在重载前执行清理或状态保存操作。
///
/// # 参数
/// * `plugins` - 插件实例的共享映射表,使用 `Arc<RwLock<>>` 保证线程安全
/// * `plugin_id` - 要调用重载钩子的插件ID
/// * `timeout_secs` - 钩子执行的超时时间(秒)
///
/// # 行为
/// * 只对状态为 `Running` 的插件调用重载钩子
/// * 如果钩子执行超时或失败,会记录警告日志,但不会阻止插件重载
/// * 钩子执行结果不会影响重载流程的继续
///
/// # 注意
/// 此函数不会返回错误,即使钩子执行失败也会继续执行,确保重载流程的健壮性。
///
/// # 示例
/// ```no_run
/// use std::sync::Arc;
/// use tokio::sync::RwLock;
/// use std::collections::HashMap;
/// 
/// # async fn example() {
/// let plugins = Arc::new(RwLock::new(HashMap::new()));
/// call_reload_hook(plugins, "my-plugin", 30).await;
/// # }
/// ```
pub async fn call_reload_hook(
    plugins: PluginMap,
    plugin_id: &str,
    timeout_secs: u64,
) {
    trace!("调用插件重载钩子: {} (超时: {}s)", plugin_id, timeout_secs);
    info!("调用插件重载钩子: {}", plugin_id);
    
    let mut plugins = plugins.write().await;
    if let Some(plugin_instance) = plugins.get_mut(plugin_id) {
        debug!("找到插件实例: {} (状态: {:?})", 
               plugin_instance.metadata.name, plugin_instance.status);
        
        if plugin_instance.status == PluginStatus::Running {
            trace!("插件处于运行状态,调用 on_reload 钩子");
            let reload_result = timeout(
                Duration::from_secs(timeout_secs),
                plugin_instance.plugin.on_reload()
            ).await;

            match reload_result {
                Ok(Ok(_)) => {
                    info!("插件重载钩子执行成功: {}", plugin_id);
                    trace!("重载钩子执行完成");
                }
                Ok(Err(e)) => {
                    warn!("插件重载钩子执行失败 {}: {},但插件已成功重载", plugin_id, e);
                }
                Err(_) => {
                    warn!("插件重载钩子执行超时 {} (超时时间: {}s),但插件已成功重载", plugin_id, timeout_secs);
                }
            }
        } else {
            debug!("插件 {} 未运行,跳过重载钩子", plugin_id);
        }
    } else {
        warn!("插件 {} 不存在,无法调用重载钩子", plugin_id);
    }
}