use crate::error::{PluginManagerError, PluginManagerResult};
use super::types::PluginInfo;
use super::validation::sanitize_plugin_name;
use secra_pluginctl as pluginctl;
use std::collections::HashMap;
use std::path::Path;
use tracing::{debug, error, info, trace, warn};
pub async fn find_plugin_file_by_id(
plugin_dir: &str,
plugin_id: &str,
plugin_name: &str,
) -> PluginManagerResult<String> {
trace!("查找插件文件 - ID: {}, 名称: {}, 目录: {}", plugin_id, plugin_name, plugin_dir);
let sanitized_name = sanitize_plugin_name(plugin_name)?;
let sanitized_plugin_id = sanitize_plugin_name(plugin_id)?;
debug!("清理后的名称: {} -> {}, ID: {} -> {}",
plugin_name, sanitized_name, plugin_id, sanitized_plugin_id);
let possible_names = vec![
format!("{}.spk", sanitized_name),
format!("{}.spk", sanitized_plugin_id),
];
debug!("尝试直接匹配文件名: {:?}", possible_names);
for possible_name in &possible_names {
let possible_path = Path::new(plugin_dir).join(possible_name);
trace!("检查文件路径: {}", possible_path.display());
if possible_path.exists() && possible_path.is_file() {
if let Some(path_str) = possible_path.to_str() {
info!("找到插件文件(直接匹配): {}", path_str);
debug!("使用直接匹配策略找到文件");
return Ok(path_str.to_string());
}
}
}
info!("未找到直接匹配的插件文件,开始扫描目录...");
debug!("策略2: 扫描目录查找匹配的插件文件");
let mut entries = tokio::fs::read_dir(plugin_dir).await?;
let mut scanned_count = 0;
while let Some(entry) = entries.next_entry().await? {
let path = entry.path();
if path.is_file() {
if let Some(extension) = path.extension() {
if extension == "spk" {
scanned_count += 1;
trace!("检查插件文件: {}", path.display());
if let Some(plugin_file) = path.to_str() {
match pluginctl::PluginArtifact::load_from_file(plugin_file) {
Ok(artifact) => {
let package_id_str = artifact.header.metadata.package_id.to_string();
let package_id_match = package_id_str == sanitized_plugin_id;
if !package_id_match {
if artifact.header.metadata.name == plugin_name {
info!("找到插件文件(名称匹配): {}", plugin_file);
debug!("通过名称匹配找到文件,扫描了 {} 个文件", scanned_count);
return Ok(plugin_file.to_string());
}
continue;
}
info!("找到插件文件(扫描匹配): {}", plugin_file);
debug!("通过ID匹配找到文件,扫描了 {} 个文件", scanned_count);
return Ok(plugin_file.to_string());
}
Err(e) => {
warn!("无法加载插件包头部信息 {}: {},跳过", plugin_file, e);
trace!("跳过无效的插件文件: {}", plugin_file);
continue;
}
}
}
}
}
}
}
error!("未找到插件文件 - ID: {}, 名称: {}, 扫描了 {} 个文件",
plugin_id, plugin_name, scanned_count);
Err(PluginManagerError::NotFound(
format!("未找到插件 {} 对应的插件文件", plugin_id)
))
}