mirror of
https://github.com/insistence/RuoYi-Vue3-FastAPI.git
synced 2026-09-23 21:18:10 +00:00
* feat: 初始化插件系统 * refactor: 收口插件系统运行时重构 * perf: 优化插件系统类型提示 * fix&perf: 修复和优化插件系统 * fix: 修复gitignore规则误忽略插件文件的问题 * fix: 修复运行时插件根路径算错的问题 * fix: 加强插件发现和路由注册的防护措施 * revert: 回滚定时任务白名单 * fix: 移除未使用的应用路由注册探测 * revert: 恢复部分代码 * perf: 优化插件系统 * docs: 新增插件开发文档 * perf: 优化插件管理模块 * perf: 提升插件系统核心能力 * refactor: 重构生命周期 step runner * fix: 修复lint错误 * test: 清理测试用例 * test: 调整测试目录名称 * fix: 修复前后端目录硬编码的问题 * fix: 修复插件系统安全性缺口 * refactor: 重新设计插件生命周期 Migration 事务与回滚 * perf: 优化插件系统边界问题 * refactor: 重构当前插件系统的依赖体系设计 * perf: 优化代码 * perf: 优化代码 * fix: 修复代码合并问题 * fix: 修复bug * perf: 优化代码 * perf&fix: 优化代码和修复bug * docs: 优化文档格式 * feat: 适配Vue2版本 * docs: 更新README文档 * fix: 修复ruff lint错误 * chore: 更新后端依赖文件
155 lines
5.4 KiB
Python
155 lines
5.4 KiB
Python
from copy import deepcopy
|
|
from typing import Any
|
|
|
|
|
|
class PluginCommandPayloadAdapter:
|
|
"""
|
|
插件 CLI 输出负载适配器。
|
|
|
|
核心运行时 payload 同时服务管理接口和 CLI。CLI 在输出前通过本适配器消除
|
|
`enabled` 的多重语义,不改变管理接口既有契约。
|
|
"""
|
|
|
|
_LIFECYCLE_OPERATIONS = {'enable', 'disable', 'uninstall'}
|
|
|
|
@classmethod
|
|
def adapt(cls, payload: dict[str, Any]) -> dict[str, Any]:
|
|
"""
|
|
生成语义明确的 CLI 输出负载。
|
|
|
|
:param payload: 核心运行时负载
|
|
:return: CLI 输出负载
|
|
"""
|
|
adapted_payload = deepcopy(payload)
|
|
cls._adapt_node(adapted_payload)
|
|
return adapted_payload
|
|
|
|
@classmethod
|
|
def _adapt_node(cls, node: object, *, parent_key: str | None = None) -> None:
|
|
"""
|
|
递归适配负载节点。
|
|
|
|
:param node: 当前负载节点
|
|
:param parent_key: 当前节点在父对象中的字段名
|
|
:return: None
|
|
"""
|
|
if isinstance(node, list):
|
|
for item in node:
|
|
cls._adapt_node(item, parent_key=parent_key)
|
|
return
|
|
if not isinstance(node, dict):
|
|
return
|
|
|
|
cls._adapt_database_state(node, parent_key)
|
|
cls._adapt_lifecycle_target(node)
|
|
cls._adapt_action_state(node, parent_key)
|
|
cls._adapt_plan_plugin_state(node, parent_key)
|
|
cls._adapt_plugin_runtime_state(node)
|
|
cls._adapt_manifest_job_state(node, parent_key)
|
|
for key, value in list(node.items()):
|
|
cls._adapt_node(value, parent_key=key)
|
|
|
|
@staticmethod
|
|
def _adapt_database_state(node: dict[str, Any], parent_key: str | None) -> None:
|
|
"""
|
|
将数据库启停枚举转换为语义明确的布尔字段。
|
|
|
|
:param node: 当前负载节点
|
|
:param parent_key: 当前节点在父对象中的字段名
|
|
:return: None
|
|
"""
|
|
if parent_key != 'database' or 'enabled' not in node:
|
|
return
|
|
database_enabled = node.pop('enabled')
|
|
node['configuredEnabled'] = PluginCommandPayloadAdapter._normalize_enabled_value(database_enabled)
|
|
|
|
@classmethod
|
|
def _adapt_lifecycle_target(cls, node: dict[str, Any]) -> None:
|
|
"""
|
|
将生命周期结果中的目标启停值改为 targetEnabled。
|
|
|
|
:param node: 当前负载节点
|
|
:return: None
|
|
"""
|
|
if node.get('operation') == 'purge' and 'enabled' in node:
|
|
node.pop('enabled')
|
|
return
|
|
if (
|
|
node.get('operation') in cls._LIFECYCLE_OPERATIONS
|
|
and 'pluginId' in node
|
|
and 'dryRun' in node
|
|
and 'enabled' in node
|
|
):
|
|
node['targetEnabled'] = node.pop('enabled')
|
|
|
|
@staticmethod
|
|
def _adapt_action_state(node: dict[str, Any], parent_key: str | None) -> None:
|
|
"""
|
|
将动作和清理计划项中的 enabled 改为 willRun。
|
|
|
|
:param node: 当前负载节点
|
|
:param parent_key: 当前节点在父对象中的字段名
|
|
:return: None
|
|
"""
|
|
is_action = parent_key == 'actions' and 'name' in node
|
|
is_purge_plan_item = parent_key == 'items' and 'destructive' in node and 'label' in node
|
|
if (is_action or is_purge_plan_item) and isinstance(node.get('enabled'), bool):
|
|
node['willRun'] = node.pop('enabled')
|
|
|
|
@staticmethod
|
|
def _adapt_plan_plugin_state(node: dict[str, Any], parent_key: str | None) -> None:
|
|
"""
|
|
将批量计划项中的数据库启停枚举改为 configuredEnabled。
|
|
|
|
:param node: 当前负载节点
|
|
:param parent_key: 当前节点在父对象中的字段名
|
|
:return: None
|
|
"""
|
|
if parent_key != 'items' or 'pluginId' not in node or 'ready' not in node or 'enabled' not in node:
|
|
return
|
|
configured_enabled = node.pop('enabled')
|
|
node['configuredEnabled'] = PluginCommandPayloadAdapter._normalize_enabled_value(configured_enabled)
|
|
|
|
@staticmethod
|
|
def _adapt_plugin_runtime_state(node: dict[str, Any]) -> None:
|
|
"""
|
|
将插件有效启用态改为 runtimeEnabled。
|
|
|
|
:param node: 当前负载节点
|
|
:return: None
|
|
"""
|
|
if 'pluginId' not in node or 'status' not in node or 'enabled' not in node or 'dryRun' in node:
|
|
return
|
|
enabled = node.pop('enabled')
|
|
if isinstance(enabled, bool):
|
|
node['runtimeEnabled'] = enabled
|
|
return
|
|
node['configuredEnabled'] = PluginCommandPayloadAdapter._normalize_enabled_value(enabled)
|
|
|
|
@staticmethod
|
|
def _adapt_manifest_job_state(node: dict[str, Any], parent_key: str | None) -> None:
|
|
"""
|
|
将 manifest 任务默认启用配置改为 defaultEnabled。
|
|
|
|
:param node: 当前负载节点
|
|
:param parent_key: 当前节点在父对象中的字段名
|
|
:return: None
|
|
"""
|
|
if parent_key == 'jobs' and 'id' in node and isinstance(node.get('enabled'), bool):
|
|
node['defaultEnabled'] = node.pop('enabled')
|
|
|
|
@staticmethod
|
|
def _normalize_enabled_value(value: object) -> object:
|
|
"""
|
|
将数据库 0/1 枚举转换为布尔值,其余值原样保留。
|
|
|
|
:param value: 原始启停值
|
|
:return: 规范化启停值
|
|
"""
|
|
if isinstance(value, str) and value in {'0', '1'}:
|
|
return value == '0'
|
|
return value
|
|
|
|
|
|
__all__ = ['PluginCommandPayloadAdapter']
|