secra_plugins 0.1.32

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

use crate::error::{PluginManagerError, PluginManagerResult};
use crate::status::PluginStatus;
use crate::manager::types::{PluginInstance, PluginMap};
use crate::manager::unloader::{check_plugin_dependencies, cleanup_single_temp_files};
use std::collections::HashMap;
use tracing::{debug, error, info, trace, warn};

/// 从父插件中移除子插件信息
///
/// 当卸载子插件时,需要从其父插件的 `child_plugins` 列表中移除该子插件的信息。
/// 这确保了父子插件关系的正确维护。
///
/// # 参数
/// * `plugins` - 插件实例的共享映射表,使用 `Arc<RwLock<>>` 保证线程安全
/// * `child_id` - 要移除的子插件ID
/// * `parent_id` - 父插件ID
///
/// # 返回值
/// * `bool` - 如果成功移除返回 `true`,如果父插件不存在或子插件不在列表中返回 `false`
///
/// # 行为
/// * 如果父插件不存在,会记录警告并返回 `false`
/// * 如果子插件不在父插件的子插件列表中,返回 `false`
/// * 成功移除时会记录信息日志
///
/// # 示例
/// ```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 removed = remove_child_from_parent(plugins, "child-plugin", "parent-plugin").await;
/// if removed {
///     println!("成功从父插件中移除子插件");
/// }
/// # }
/// ```
pub async fn remove_child_from_parent(
    plugins: PluginMap,
    child_id: &str,
    parent_id: &str,
) -> bool {
    trace!("准备从父插件移除子插件 - 父插件: {}, 子插件: {}", parent_id, child_id);
    
    let mut plugins = plugins.write().await;

    if let Some(parent) = plugins.get_mut(parent_id) {
        let original_len = parent.child_plugins.len();
        debug!("父插件 {} 当前有 {} 个子插件", parent_id, original_len);
        
        parent.child_plugins.retain(|child| child.id != child_id);

        let removed = parent.child_plugins.len() < original_len;
        if removed {
            info!(
                "已从父插件 {} 的子插件列表中移除子插件 {}",
                parent_id, child_id
            );
            debug!("父插件 {} 现在有 {} 个子插件", parent_id, parent.child_plugins.len());
        } else {
            trace!("子插件 {} 不在父插件 {} 的子插件列表中", child_id, parent_id);
        }
        removed
    } else {
        warn!("父插件 {} 不存在,无法移除子插件 {}", parent_id, child_id);
        false
    }
}

/// 获取插件卸载所需的信息(子插件列表、是否为子插件、父插件ID)
///
/// 在卸载插件之前,需要收集相关信息以确定卸载顺序和依赖关系。
/// 此函数会检查插件依赖关系,确保没有其他插件依赖要卸载的插件。
///
/// # 参数
/// * `plugins` - 插件实例的映射表(不需要锁,因为通常是在已持有锁的上下文中调用)
/// * `plugin_id` - 要卸载的插件ID
///
/// # 返回值
/// * `PluginManagerResult<(Vec<String>, bool, Option<String>)>` - 成功时返回元组:
///   - `Vec<String>`: 该插件的所有子插件ID列表
///   - `bool`: 该插件是否为子插件
///   - `Option<String>`: 如果是子插件,返回父插件ID;否则返回 `None`
///
/// # 错误
/// * `PluginManagerError::NotFound` - 如果指定的插件不存在
/// * `PluginManagerError::DependencyError` - 如果有其他插件依赖此插件
///
/// # 行为
/// * 检查插件依赖关系,如果有其他插件依赖此插件,会返回错误
/// * 过滤掉不存在的子插件(可能由于数据不一致导致)
/// * 返回的信息用于确定卸载顺序
///
/// # 示例
/// ```no_run
/// use std::collections::HashMap;
/// 
/// # fn example() {
/// let plugins = HashMap::new();
/// let (child_ids, is_sub, parent_id) = get_unload_info(&plugins, "my-plugin")?;
/// if is_sub {
///     println!("这是子插件,父插件ID: {:?}", parent_id);
/// }
/// println!("子插件数量: {}", child_ids.len());
/// # }
/// ```
pub fn get_unload_info(
    plugins: &HashMap<String, PluginInstance>,
    plugin_id: &str,
) -> PluginManagerResult<(Vec<String>, bool, Option<String>)> {
    trace!("获取插件卸载信息: {}", plugin_id);
    
    let plugin_instance = plugins.get(plugin_id)
        .ok_or_else(|| {
            error!("插件不存在: {}", plugin_id);
            PluginManagerError::not_found(plugin_id)
        })?;
    
    debug!("找到插件实例: {} (状态: {:?})", 
           plugin_instance.metadata.name, plugin_instance.status);

    debug!("检查插件依赖关系");
    check_plugin_dependencies(plugins, plugin_id)?;
    trace!("依赖关系检查通过");

    let child_plugin_ids: Vec<String> = plugin_instance
        .child_plugins
        .iter()
        .filter_map(|child| {
            if plugins.contains_key(&child.id) {
                trace!("找到有效的子插件: {}", child.id);
                Some(child.id.clone())
            } else {
                warn!(
                    "子插件 {} 在父插件 {} 的列表中,但实际不存在,将跳过",
                    child.id, plugin_id
                );
                None
            }
        })
        .collect();
    
    debug!("插件 {} 有 {} 个子插件", plugin_id, child_plugin_ids.len());

    let is_sub_plugin = plugin_instance.metadata.is_sub_plugin;
    let parent_id = plugin_instance.metadata.parent_plugin_id.clone();
    
    if is_sub_plugin {
        debug!("这是子插件,父插件ID: {:?}", parent_id);
    } else {
        debug!("这是主插件");
    }

    Ok((child_plugin_ids, is_sub_plugin, parent_id))
}

/// 执行实际的插件卸载操作(移除插件实例并清理文件)
///
/// 从插件管理器中移除插件实例,并清理插件相关的临时文件。
/// 这是卸载流程的最后一步,执行后插件将完全从系统中移除。
///
/// # 参数
/// * `plugins` - 插件实例的共享映射表,使用 `Arc<RwLock<>>` 保证线程安全
/// * `plugin_id` - 要卸载的插件ID
///
/// # 返回值
/// * `PluginManagerResult<PluginInstance>` - 成功时返回被卸载的插件实例
///
/// # 错误
/// * `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 unloaded_instance = perform_unload(plugins, "my-plugin").await?;
/// println!("已卸载插件: {}", unloaded_instance.metadata.name);
/// # }
/// ```
pub async fn perform_unload(
    plugins: PluginMap,
    plugin_id: &str,
) -> PluginManagerResult<PluginInstance> {
    trace!("开始执行插件卸载: {}", plugin_id);
    
    let mut plugins = plugins.write().await;

    let plugin_instance = plugins.remove(plugin_id)
        .ok_or_else(|| {
            error!("插件在卸载过程中被移除: {}", plugin_id);
            PluginManagerError::not_found(format!("插件在卸载过程中被移除: {}", plugin_id))
        })?;
    
    debug!("插件实例已从映射表中移除: {} ({})", 
           plugin_instance.metadata.name, plugin_id);
    drop(plugins);

    // 清理插件临时文件
    trace!("开始清理插件临时文件");
    cleanup_single_temp_files(&plugin_instance).await;
    debug!("临时文件清理完成");

    info!(
        plugin_id = %plugin_id,
        plugin_name = %plugin_instance.metadata.name,
        plugin_version = %plugin_instance.metadata.version,
        fingerprint = %plugin_instance.fingerprint,
        "插件卸载成功: {} ({}) v{}",
        plugin_instance.metadata.name,
        plugin_id,
        plugin_instance.metadata.version
    );
    trace!("插件卸载流程完成");

    Ok(plugin_instance)
}

/// 获取卸载顺序(子插件在前,父插件在后)
///
/// 计算所有插件的卸载顺序。卸载时必须先卸载子插件,再卸载父插件,
/// 以确保依赖关系的正确维护。
///
/// # 参数
/// * `plugins` - 插件实例的映射表(不需要锁,因为通常是在已持有锁的上下文中调用)
///
/// # 返回值
/// * `Vec<String>` - 按卸载顺序排列的插件ID列表:
///   - 子插件在前
///   - 父插件在后
///
/// # 行为
/// * 遍历所有插件,根据 `is_sub_plugin` 标志分类
/// * 先收集所有子插件ID,再收集所有父插件ID
/// * 返回合并后的列表,确保子插件优先卸载
///
/// # 示例
/// ```no_run
/// use std::collections::HashMap;
/// 
/// # fn example() {
/// let plugins = HashMap::new();
/// let unload_order = get_unload_order(&plugins);
/// for plugin_id in unload_order {
///     println!("卸载插件: {}", plugin_id);
/// }
/// # }
/// ```
pub fn get_unload_order(
    plugins: &HashMap<String, PluginInstance>,
) -> Vec<String> {
    trace!("计算插件卸载顺序");
    let mut child_ids = Vec::new();
    let mut parent_ids = Vec::new();

    for (id, instance) in plugins.iter() {
        if instance.metadata.is_sub_plugin {
            trace!("发现子插件: {}", id);
            child_ids.push(id.clone());
        } else {
            trace!("发现主插件: {}", id);
            parent_ids.push(id.clone());
        }
    }

    debug!("卸载顺序: {} 个子插件, {} 个主插件", child_ids.len(), parent_ids.len());
    
    let order = child_ids.into_iter()
        .chain(parent_ids.into_iter())
        .collect();
    
    trace!("卸载顺序计算完成: {:?}", order);
    order
}