Merge pull request #2073 from Raven95676/fix/register_star

fix: 提升兼容性,并尽可能避免数据竞争
This commit is contained in:
Soulter
2025-07-10 11:03:57 +08:00
committed by GitHub
4 changed files with 159 additions and 126 deletions

View File

@@ -1,4 +1,4 @@
from .star import StarMetadata, star_map
from .star import StarMetadata, star_map, star_registry
from .star_manager import PluginManager
from .context import Context
from astrbot.core.provider import Provider
@@ -16,11 +16,16 @@ class Star(CommandParserMixin):
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
if not star_map.get(cls.__module__):
metadata = StarMetadata(
star_cls_type=cls,
module_path=cls.__module__,
)
star_map[cls.__module__] = metadata
star_registry.append(metadata)
else:
star_map[cls.__module__].star_cls_type = cls
star_map[cls.__module__].module_path = cls.__module__
@staticmethod
async def text_to_image(text: str, return_url=True) -> str:

View File

@@ -1,5 +1,7 @@
import warnings
from astrbot.core.star import StarMetadata, star_map
_warned_register_star = False
@@ -37,6 +39,22 @@ def register_star(name: str, author: str, desc: str, version: str, repo: str = N
)
def decorator(cls):
if not star_map.get(cls.__module__):
metadata = StarMetadata(
name=name,
author=author,
desc=desc,
version=version,
repo=repo,
)
star_map[cls.__module__] = metadata
else:
star_map[cls.__module__].name = name
star_map[cls.__module__].author = author
star_map[cls.__module__].desc = desc
star_map[cls.__module__].version = version
star_map[cls.__module__].repo = repo
return cls
return decorator

View File

@@ -56,7 +56,10 @@ class StarMetadata:
"""插件支持的平台ID字典key为平台IDvalue为是否支持"""
def __str__(self) -> str:
return f"StarMetadata({self.name}, {self.desc}, {self.version}, {self.repo})"
return f"Plugin {self.name} ({self.version}) by {self.author}: {self.desc}"
def __repr__(self) -> str:
return f"Plugin {self.name} ({self.version}) by {self.author}: {self.desc}"
def update_platform_compatibility(self, plugin_enable_config: dict) -> None:
"""更新插件支持的平台列表

View File

@@ -57,6 +57,8 @@ class PluginManager:
"""保留插件的路径。在 packages 目录下"""
self.conf_schema_fname = "_conf_schema.json"
"""插件配置 Schema 文件名"""
self._pm_lock = asyncio.Lock()
"""StarManager操作互斥锁"""
self.failed_plugin_info = ""
if os.getenv("ASTRBOT_RELOAD", "0") == "1":
@@ -186,9 +188,9 @@ class PluginManager:
@staticmethod
def _load_plugin_metadata(plugin_path: str, plugin_obj=None) -> StarMetadata:
"""v3.4.0 以前的方式载入插件元数据
"""先寻找 metadata.yaml 文件,如果不存在,则使用插件对象的 info() 函数获取元数据
先寻找 metadata.yaml 文件,如果不存在,则使用插件对象的 info() 函数获取元数据。
Notes: 旧版本 AstrBot 插件可能使用的是 info() 函数获取元数据。
"""
metadata = None
@@ -200,7 +202,7 @@ class PluginManager:
os.path.join(plugin_path, "metadata.yaml"), "r", encoding="utf-8"
) as f:
metadata = yaml.safe_load(f)
elif plugin_obj:
elif plugin_obj and hasattr(plugin_obj, "info"):
# 使用 info() 函数
metadata = plugin_obj.info()
@@ -293,6 +295,7 @@ class PluginManager:
- success (bool): 重载是否成功
- error_message (str|None): 错误信息,成功时为 None
"""
async with self._pm_lock:
specified_module_path = None
if specified_plugin_name:
for smd in star_registry:
@@ -435,7 +438,7 @@ class PluginManager:
)
if path in star_map:
# 通过__init__subclass__注册插件
# 通过 __init__subclass__ 注册插件
metadata = star_map[path]
try:
@@ -450,9 +453,10 @@ class PluginManager:
metadata.version = metadata_yaml.version
metadata.repo = metadata_yaml.repo
except Exception as e:
logger.error(
logger.warning(
f"插件 {root_dir_name} 元数据载入失败: {str(e)}。使用默认元数据。"
)
logger.info(metadata)
metadata.config = plugin_config
if path not in inactivated_plugins:
# 只有没有禁用插件时才实例化插件类
@@ -506,8 +510,6 @@ class PluginManager:
if func_tool.name in inactivated_llm_tools:
func_tool.active = False
star_registry.append(metadata)
else:
# v3.4.0 以前的方式注册插件
logger.debug(
@@ -626,6 +628,7 @@ class PluginManager:
- readme: README.md 文件的内容(如果存在)
如果找不到插件元数据则返回 None。
"""
async with self._pm_lock:
plugin_path = await self.updator.install(repo_url, proxy)
# reload the plugin
dir_name = os.path.basename(plugin_path)
@@ -651,7 +654,9 @@ class PluginManager:
with open(readme_path, "r", encoding="utf-8") as f:
readme_content = f.read()
except Exception as e:
logger.warning(f"读取插件 {dir_name} 的 README.md 文件失败: {str(e)}")
logger.warning(
f"读取插件 {dir_name} 的 README.md 文件失败: {str(e)}"
)
plugin_info = None
if plugin:
@@ -672,6 +677,7 @@ class PluginManager:
Raises:
Exception: 当插件不存在、是保留插件时,或删除插件文件夹失败时抛出异常
"""
async with self._pm_lock:
plugin = self.context.get_registered_star(plugin_name)
if not plugin:
raise Exception("插件不存在。")
@@ -750,6 +756,7 @@ class PluginManager:
将插件的 module_path 加入到 data/shared_preferences.json 的 inactivated_plugins 列表中。
并且同时将插件启用的 llm_tool 禁用。
"""
async with self._pm_lock:
plugin = self.context.get_registered_star(plugin_name)
if not plugin:
raise Exception("插件不存在。")