Files
RuoYi-Vue3-FastAPI/ruoyi-fastapi-backend/module_plugin/service/plugin_service.py
T
insistence 2a055ba648 feat: 新增插件系统 (#112)
* 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: 更新后端依赖文件
2026-07-28 20:35:18 +08:00

149 lines
5.2 KiB
Python

from typing import cast
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.dao.dict_dao import DictDataDao
from plugins.core.management.entity.vo.schemas import (
PluginOperationLogDetailModel,
PluginOperationLogExportQueryModel,
)
from plugins.core.management.service.gateway import PluginManagementRuntimeGateway
from plugins.core.management.service.service import PluginService
from plugins.core.runtime.service import PluginRuntimeService
from plugins.core.runtime.service.dependency_container import PluginRuntimeGatewayOverrides
from plugins.core.runtime.service.lifecycle_lock import RedisPluginLifecycleLock
from plugins.core.runtime.service.responses import PluginDiagnoseResponse
from plugins.core.runtime.support import PluginAuditPayloadBuilder, PluginAuditSnapshotPayloadDict
AUDIT_LOG_OVERFETCH_MULTIPLIER = 3
class PluginOperationService:
"""
插件管理操作服务。
使用 Facade 模式复用插件应用运行时能力,为插件管理页面接口提供检查、安装和升级入口。
"""
def __init__(self, runtime_service: PluginRuntimeService | None = None) -> None:
"""
初始化插件管理操作服务。
:param runtime_service: 插件运行时服务
:return: None
"""
self.runtime_service = runtime_service or get_plugin_runtime_service()
async def diagnose_plugin_with_audit_services(
self,
query_db: AsyncSession,
plugin_id: str,
*,
audit_limit: int = 5,
) -> PluginDiagnoseResponse:
"""
生成包含最近审计记录的插件诊断包。
:param query_db: orm对象
:param plugin_id: 插件ID
:param audit_limit: 最近审计记录数量
:return: 插件诊断包负载
"""
payload = cast('dict[str, object]', await self.runtime_service.diagnose_plugin(plugin_id))
payload['audit'] = await self._build_recent_audit_snapshot(query_db, plugin_id, audit_limit=audit_limit)
return cast('PluginDiagnoseResponse', payload)
@classmethod
async def get_plugin_operation_dict_services(cls, query_db: AsyncSession) -> dict[str, str]:
"""
获取插件管理页面使用的操作类型字典映射。
:param query_db: orm对象
:return: 插件操作类型字典映射
"""
dict_data_list = await DictDataDao.query_dict_data_list(query_db, 'plugin_operation_type')
return {
dict_data.dict_value: dict_data.dict_label
for dict_data in dict_data_list
if dict_data and dict_data.dict_value
}
@classmethod
async def _build_recent_audit_snapshot(
cls,
query_db: AsyncSession,
plugin_id: str,
*,
audit_limit: int,
) -> PluginAuditSnapshotPayloadDict:
"""
构建插件最近审计记录快照。
:param query_db: orm对象
:param plugin_id: 插件ID
:param audit_limit: 最近审计记录数量
:return: 最近审计记录快照
"""
operation_logs = await PluginService.get_plugin_operation_log_export_list_services(
query_db,
PluginOperationLogExportQueryModel(exportLimit=audit_limit * AUDIT_LOG_OVERFETCH_MULTIPLIER),
)
return PluginAuditPayloadBuilder.build_recent_snapshot_payload(
plugin_id,
[
operation_log
for operation_log in operation_logs
if isinstance(operation_log, PluginOperationLogDetailModel)
],
audit_limit=audit_limit,
)
_PLUGIN_OPERATION_SERVICE_CACHE: dict[str, PluginOperationService] = {}
_PLUGIN_RUNTIME_SERVICE_CACHE: dict[str, PluginRuntimeService] = {}
def get_plugin_runtime_service() -> PluginRuntimeService:
"""
获取 Web 侧插件运行时服务单例。
:return: 插件运行时服务
"""
runtime_service = _PLUGIN_RUNTIME_SERVICE_CACHE.get('default')
if runtime_service is None:
runtime_gateway = PluginManagementRuntimeGateway()
runtime_service = PluginRuntimeService(
gateways=PluginRuntimeGatewayOverrides(
config_gateway=runtime_gateway,
audit_gateway=runtime_gateway,
state_query_gateway=runtime_gateway,
migration_history_gateway=runtime_gateway,
purge_plan_gateway=runtime_gateway,
lifecycle_state_gateway=runtime_gateway,
lifecycle_uow_gateway=runtime_gateway,
migration_execution_gateway=runtime_gateway,
),
model_gateway=runtime_gateway,
command_gateway=runtime_gateway,
lifecycle_lock=RedisPluginLifecycleLock(),
)
_PLUGIN_RUNTIME_SERVICE_CACHE['default'] = runtime_service
return runtime_service
def get_plugin_operation_service() -> PluginOperationService:
"""
获取 Web 侧插件操作服务单例。
:return: 插件操作服务
"""
operation_service = _PLUGIN_OPERATION_SERVICE_CACHE.get('default')
if operation_service is None:
operation_service = PluginOperationService()
_PLUGIN_OPERATION_SERVICE_CACHE['default'] = operation_service
return operation_service