# 📖 插件配置访问完整示例 > 这个示例展示了如何在Action和Command组件中正确访问插件的配置文件。 ## 🎯 问题背景 在插件开发过程中,你可能遇到这样的问题: - `get_config`方法只在`BasePlugin`类中 - `BaseAction`和`BaseCommand`无法直接继承这个方法 - 想要在Action或Command中访问插件配置 ## ✅ 解决方案 通过`self.api.get_config()`方法访问配置,系统会自动将插件配置传递给组件。 ## 📁 完整示例 ### 1. 插件配置文件 创建 `config.toml`: ```toml [greeting] default_style = "casual" enable_emoji = true custom_messages = [ "你好呀!", "嗨!很高兴见到你!", "哈喽!" ] [database] enabled = true table_prefix = "hello_" max_records = 1000 [features] enable_weather = false enable_jokes = true api_timeout = 30 [advanced.logging] level = "INFO" file_path = "logs/hello_plugin.log" [advanced.cache] enabled = true ttl_seconds = 3600 max_size = 100 ``` ### 2. 插件主文件 创建 `plugin.py`: ```python """ 配置访问示例插件 展示如何在Action和Command中访问配置 """ from src.plugin_system import ( BasePlugin, BaseAction, BaseCommand, register_plugin, ActionInfo, CommandInfo, PythonDependency, ActionActivationType ) from src.common.logger import get_logger logger = get_logger("config_example_plugin") @register_plugin class ConfigExamplePlugin(BasePlugin): """配置访问示例插件""" plugin_name = "config_example_plugin" plugin_description = "展示如何在组件中访问配置的示例插件" plugin_version = "1.0.0" plugin_author = "MaiBot Team" config_file_name = "config.toml" def get_plugin_components(self): """返回插件组件""" return [ (ActionInfo( name="config_greeting_action", description="使用配置的问候Action", focus_activation_type=ActionActivationType.KEYWORD, normal_activation_type=ActionActivationType.KEYWORD, activation_keywords=["配置问候", "config hello"], ), ConfigGreetingAction), (CommandInfo( name="config_status", description="显示配置状态", command_pattern=r"^/config\s*(status|show)?$", command_help="显示插件配置状态", command_examples=["/config", "/config status"], ), ConfigStatusCommand), (CommandInfo( name="config_test", description="测试配置访问", command_pattern=r"^/config\s+test\s+(?P\S+)$", command_help="测试访问指定配置项", command_examples=["/config test greeting.default_style"], ), ConfigTestCommand), ] class ConfigGreetingAction(BaseAction): """使用配置的问候Action""" async def execute(self): """执行配置化的问候""" try: # 方法1: 直接访问配置项 style = self.api.get_config("greeting.default_style", "casual") enable_emoji = self.api.get_config("greeting.enable_emoji", True) # 方法2: 检查配置是否存在 if self.api.has_config("greeting.custom_messages"): messages = self.api.get_config("greeting.custom_messages", []) if messages: # 随机选择一个问候语 import random message = random.choice(messages) else: message = "你好!" else: # 使用默认问候语 if style == "formal": message = "您好!很高兴为您服务!" else: message = "嗨!很开心见到你!" # 添加表情符号 if enable_emoji: emoji = "😊" if style == "casual" else "🙏" message += emoji # 发送问候消息 await self.send_text(message) # 记录到数据库(如果启用) await self._save_greeting_record(style, message) return True, f"发送了{style}风格的配置化问候" except Exception as e: logger.error(f"配置问候执行失败: {e}") await self.send_text("抱歉,问候功能遇到了问题") return False, f"执行失败: {str(e)}" async def _save_greeting_record(self, style: str, message: str): """保存问候记录到数据库""" try: # 检查数据库功能是否启用 if not self.api.get_config("database.enabled", False): return # 获取数据库配置 table_prefix = self.api.get_config("database.table_prefix", "hello_") max_records = self.api.get_config("database.max_records", 1000) # 构造记录数据 record_data = { "style": style, "message": message, "timestamp": "now", # 实际应用中使用datetime "user_id": "demo_user" # 从context获取真实用户ID } # 这里应该调用数据库API保存记录 logger.info(f"保存问候记录到 {table_prefix}greetings: {record_data}") except Exception as e: logger.error(f"保存问候记录失败: {e}") class ConfigStatusCommand(BaseCommand): """显示配置状态Command""" async def execute(self): """显示插件配置状态""" try: # 获取所有配置 all_config = self.api.get_all_config() if not all_config: await self.send_text("❌ 没有找到配置文件") return True, "没有配置文件" # 构建状态报告 status_lines = ["📋 插件配置状态:", ""] # 问候配置 greeting_config = all_config.get("greeting", {}) if greeting_config: status_lines.append("🎯 问候配置:") status_lines.append(f" - 默认风格: {greeting_config.get('default_style', 'N/A')}") status_lines.append(f" - 启用表情: {'✅' if greeting_config.get('enable_emoji') else '❌'}") custom_msgs = greeting_config.get('custom_messages', []) status_lines.append(f" - 自定义消息: {len(custom_msgs)}条") status_lines.append("") # 数据库配置 db_config = all_config.get("database", {}) if db_config: status_lines.append("🗄️ 数据库配置:") status_lines.append(f" - 状态: {'✅ 启用' if db_config.get('enabled') else '❌ 禁用'}") status_lines.append(f" - 表前缀: {db_config.get('table_prefix', 'N/A')}") status_lines.append(f" - 最大记录: {db_config.get('max_records', 'N/A')}") status_lines.append("") # 功能配置 features_config = all_config.get("features", {}) if features_config: status_lines.append("🔧 功能配置:") for feature, enabled in features_config.items(): if isinstance(enabled, bool): status_lines.append(f" - {feature}: {'✅' if enabled else '❌'}") else: status_lines.append(f" - {feature}: {enabled}") status_lines.append("") # 高级配置 advanced_config = all_config.get("advanced", {}) if advanced_config: status_lines.append("⚙️ 高级配置:") for section, config in advanced_config.items(): status_lines.append(f" - {section}: {len(config) if isinstance(config, dict) else 1}项") # 发送状态报告 status_text = "\n".join(status_lines) await self.send_text(status_text) return True, "显示了配置状态" except Exception as e: logger.error(f"获取配置状态失败: {e}") await self.send_text(f"❌ 获取配置状态失败: {str(e)}") return False, f"获取失败: {str(e)}" class ConfigTestCommand(BaseCommand): """测试配置访问Command""" async def execute(self): """测试访问指定的配置项""" try: # 获取要测试的配置键 config_key = self.matched_groups.get("key", "") if not config_key: await self.send_text("❌ 请指定要测试的配置项\n用法: /config test ") return True, "缺少配置键参数" # 测试配置访问的不同方法 result_lines = [f"🔍 测试配置项: `{config_key}`", ""] # 方法1: 检查是否存在 exists = self.api.has_config(config_key) result_lines.append(f"📋 配置存在: {'✅ 是' if exists else '❌ 否'}") if exists: # 方法2: 获取配置值 config_value = self.api.get_config(config_key) value_type = type(config_value).__name__ result_lines.append(f"📊 数据类型: {value_type}") # 根据类型显示值 if isinstance(config_value, (str, int, float, bool)): result_lines.append(f"💾 配置值: {config_value}") elif isinstance(config_value, list): result_lines.append(f"📝 列表长度: {len(config_value)}") if config_value: result_lines.append(f"📋 首项: {config_value[0]}") elif isinstance(config_value, dict): result_lines.append(f"🗂️ 字典大小: {len(config_value)}项") if config_value: keys = list(config_value.keys())[:3] result_lines.append(f"🔑 键示例: {', '.join(keys)}") else: result_lines.append(f"💾 配置值: {str(config_value)[:100]}...") # 方法3: 测试默认值 test_default = self.api.get_config(config_key, "DEFAULT_VALUE") if test_default != "DEFAULT_VALUE": result_lines.append("✅ 默认值机制正常") else: result_lines.append("⚠️ 配置值为空或等于测试默认值") else: # 测试默认值返回 default_value = self.api.get_config(config_key, "NOT_FOUND") result_lines.append(f"🔄 默认值返回: {default_value}") # 显示相关配置项 if "." in config_key: section = config_key.split(".")[0] all_config = self.api.get_all_config() section_config = all_config.get(section, {}) if section_config and isinstance(section_config, dict): related_keys = list(section_config.keys())[:5] result_lines.append("") result_lines.append(f"🔗 相关配置项 ({section}):") for key in related_keys: full_key = f"{section}.{key}" status = "✅" if self.api.has_config(full_key) else "❌" result_lines.append(f" {status} {full_key}") # 发送测试结果 result_text = "\n".join(result_lines) await self.send_text(result_text) return True, f"测试了配置项: {config_key}" except Exception as e: logger.error(f"配置测试失败: {e}") await self.send_text(f"❌ 配置测试失败: {str(e)}") return False, f"测试失败: {str(e)}" # 演示代码 async def demo_config_access(): """演示配置访问功能""" print("🔧 插件配置访问演示") print("=" * 50) # 模拟插件配置 mock_config = { "greeting": { "default_style": "casual", "enable_emoji": True, "custom_messages": ["你好呀!", "嗨!很高兴见到你!"] }, "database": { "enabled": True, "table_prefix": "hello_", "max_records": 1000 }, "advanced": { "logging": { "level": "INFO", "file_path": "logs/hello_plugin.log" } } } # 创建模拟API from src.plugin_system.apis.plugin_api import PluginAPI api = PluginAPI(plugin_config=mock_config) print("\n📋 配置访问测试:") # 测试1: 基本配置访问 style = api.get_config("greeting.default_style", "unknown") print(f" 问候风格: {style}") # 测试2: 布尔值配置 enable_emoji = api.get_config("greeting.enable_emoji", False) print(f" 启用表情: {enable_emoji}") # 测试3: 列表配置 messages = api.get_config("greeting.custom_messages", []) print(f" 自定义消息: {len(messages)}条") # 测试4: 深层嵌套配置 log_level = api.get_config("advanced.logging.level", "INFO") print(f" 日志级别: {log_level}") # 测试5: 不存在的配置 unknown = api.get_config("unknown.config", "default") print(f" 未知配置: {unknown}") # 测试6: 配置存在检查 exists1 = api.has_config("greeting.default_style") exists2 = api.has_config("nonexistent.config") print(f" greeting.default_style 存在: {exists1}") print(f" nonexistent.config 存在: {exists2}") # 测试7: 获取所有配置 all_config = api.get_all_config() print(f" 总配置节数: {len(all_config)}") print("\n✅ 配置访问测试完成!") if __name__ == "__main__": import asyncio asyncio.run(demo_config_access()) ``` ## 🎯 核心要点 ### 1. 在Action中访问配置 ```python class MyAction(BaseAction): async def execute(self): # 基本配置访问 value = self.api.get_config("section.key", "default") # 检查配置是否存在 if self.api.has_config("section.key"): # 配置存在,执行相应逻辑 pass # 获取所有配置 all_config = self.api.get_all_config() ``` ### 2. 在Command中访问配置 ```python class MyCommand(BaseCommand): async def execute(self): # 访问配置的方法与Action完全相同 value = self.api.get_config("section.key", "default") # 支持嵌套键访问 nested_value = self.api.get_config("section.subsection.key") ``` ### 3. 配置传递机制 系统会自动处理配置传递: 1. `BasePlugin`加载配置文件到`self.config` 2. 组件注册时,系统通过`component_registry.get_plugin_config()`获取配置 3. Action/Command实例化时,配置作为`plugin_config`参数传递 4. `PluginAPI`初始化时保存配置到`self._plugin_config` 5. 组件通过`self.api.get_config()`访问配置 ## 🔧 使用这个示例 ### 1. 创建插件目录 ```bash mkdir plugins/config_example_plugin cd plugins/config_example_plugin ``` ### 2. 复制文件 - 将配置文件保存为 `config.toml` - 将插件代码保存为 `plugin.py` ### 3. 测试功能 ```bash # 启动MaiBot后测试以下命令: # 测试配置状态显示 /config status # 测试特定配置项 /config test greeting.default_style /config test database.enabled /config test advanced.logging.level # 触发配置化问候 配置问候 ``` ## 💡 最佳实践 ### 1. 提供合理的默认值 ```python # 总是提供默认值 timeout = self.api.get_config("api.timeout", 30) enabled = self.api.get_config("feature.enabled", False) ``` ### 2. 验证配置类型 ```python # 验证配置类型 max_items = self.api.get_config("list.max_items", 10) if not isinstance(max_items, int) or max_items <= 0: max_items = 10 # 使用安全的默认值 ``` ### 3. 缓存复杂配置 ```python class MyAction(BaseAction): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 缓存复杂配置避免重复解析 self._cached_config = self._parse_complex_config() def _parse_complex_config(self): # 解析复杂配置逻辑 return processed_config ``` ### 4. 配置变更检测 ```python # 对于支持热更新的配置 last_config_hash = None def check_config_changes(self): current_config = self.api.get_all_config() current_hash = hash(str(current_config)) if current_hash != self.last_config_hash: self.last_config_hash = current_hash self._reload_config() ``` 通过这种方式,你的Action和Command组件可以灵活地访问插件配置,实现更加强大和可定制的功能!