refactor: moveplugins and temp folder to data/

This commit is contained in:
Soulter
2024-09-17 22:50:05 -04:00
parent 5bd6af3400
commit 78060c9985
17 changed files with 94 additions and 141 deletions
+1
View File
@@ -22,6 +22,7 @@ jobs:
pip install -r requirements.txt
pip install pytest pytest-cov pytest-asyncio
mkdir data
mkdir data/plugins
mkdir data/config
mkdir temp
-10
View File
@@ -1,10 +0,0 @@
# helloworld
AstrBot 插件模板
A template plugin for AstrBot plugin feature
# 支持
[帮助文档](https://astrbot.soulter.top/center/docs/%E5%BC%80%E5%8F%91/%E6%8F%92%E4%BB%B6%E5%BC%80%E5%8F%91/
)
-1
View File
@@ -1 +0,0 @@
https://github.com/Soulter/helloworld
-36
View File
@@ -1,36 +0,0 @@
flag_not_support = False
try:
from util.plugin_dev.api.v1 import (
Context,
CommandResult,
AstrMessageEvent,
Middleware,
)
except ImportError:
flag_not_support = True
print("导入接口失败。请升级到 AstrBot 最新版本。")
'''
注意以格式 XXXPlugin 或 Main 来修改插件名。
提示:把此模板仓库 fork 之后 clone 到机器人文件夹下的 addons/plugins/ 目录下,然后用 Pycharm/VSC 等工具打开可获更棒的编程体验(自动补全等)
'''
class HelloWorldPlugin:
"""
AstrBot 会传递 context 给插件。
- context.register_commands: 注册指令
- context.register_task: 注册任务
- context.message_handler: 消息处理器(平台类插件用)
"""
def __init__(self, context: Context) -> None:
self.context = context
self.context.register_commands("helloworld", "helloworld", "内置测试指令。", 1, self.helloworld)
"""
指令处理函数。
- 需要接收两个参数:message: AstrMessageEvent, context: Context
- 返回 CommandResult 对象
"""
async def helloworld(self, message: AstrMessageEvent, context: Context):
return CommandResult().message("Hello, World!")
-6
View File
@@ -1,6 +0,0 @@
name: helloworld # 这是你的插件的唯一识别名。
desc: 这是 AstrBot 的默认插件。
help:
version: v1.3 # 插件版本号。格式:v1.1.1 或者 v1.1
author: Soulter # 作者
repo: https://github.com/Soulter/helloworld # 插件的仓库地址
+4 -5
View File
@@ -1,21 +1,20 @@
import asyncio
import traceback
import os
from astrbot.message.handler import MessageHandler
from astrbot.persist.helper import dbConn
from dashboard.server import AstrBotDashBoard
from model.provider.provider import Provider
from model.command.manager import CommandManager
from model.command.internal_handler import InternalCommandHandler
from model.plugin.manager import PluginManager
from model.platform.manager import PlatformManager
from typing import Dict, List, Union
from typing import Union
from type.types import Context
from type.config import VERSION
from SparkleLogging.utils.core import LogManager
from logging import Logger
from util.cmd_config import AstrBotConfig
from util.cmd_config import AstrBotConfig, try_migrate
from util.metrics import MetricUploader
from util.config_utils import *
from util.updator.astrbot_updator import AstrBotUpdator
logger: Logger = LogManager.GetLogger(log_name='astrbot')
@@ -26,7 +25,7 @@ class AstrBotBootstrap():
self.context = Context()
# load configs and ensure the backward compatibility
try_migrate_config()
try_migrate()
self.config_helper = AstrBotConfig()
self.context.config_helper = self.config_helper
logger.info("AstrBot v" + VERSION)
+1 -2
View File
@@ -228,8 +228,7 @@ class AstrBotDashBoard():
file = request.files['file']
print(file.filename)
logger.info(f"正在安装用户上传的插件 {file.filename}")
# save file to temp/
file_path = f"temp/{uuid.uuid4()}.zip"
file_path = f"data/temp/{uuid.uuid4()}.zip"
file.save(file_path)
self.plugin_manager.install_plugin_from_file(file_path)
logger.info(f"安装插件 {file.filename} 成功")
+2 -1
View File
@@ -42,7 +42,8 @@ def check_env():
exit()
os.makedirs("data/config", exist_ok=True)
os.makedirs("temp", exist_ok=True)
os.makedirs("data/plugins", exist_ok=True)
os.makedirs("data/temp", exist_ok=True)
# workaround for issue #181
mimetypes.add_type("text/javascript", ".js")
+12 -12
View File
@@ -19,23 +19,23 @@ class InternalCommandHandler:
self.plugin_manager = plugin_manager
self.manager.register("help", "查看帮助", 10, self.help)
self.manager.register("wake", "设置机器人唤醒词", 10, self.set_nick)
self.manager.register("update", "更新 AstrBot", 10, self.update)
self.manager.register("wake", "唤醒前缀", 10, self.set_nick)
self.manager.register("update", "更新管理", 10, self.update)
self.manager.register("plugin", "插件管理", 10, self.plugin)
self.manager.register("reboot", "重启 AstrBot", 10, self.reboot)
self.manager.register("websearch", "网页搜索开关", 10, self.web_search)
self.manager.register("t2i", "转图片开关", 10, self.t2i_toggle)
self.manager.register("myid", "获取你在此平台上的ID", 10, self.myid)
self.manager.register("provider", "查看和切换当前使用的 LLM 资源来", 10, self.provider)
self.manager.register("websearch", "网页搜索", 10, self.web_search)
self.manager.register("t2i", "文转图", 10, self.t2i_toggle)
self.manager.register("myid", "用户ID", 10, self.myid)
self.manager.register("provider", "LLM 接入", 10, self.provider)
def provider(self, message: AstrMessageEvent, context: Context):
if len(context.llms) == 0:
return CommandResult().message("当前没有加载任何 LLM 源。")
return CommandResult().message("当前没有加载任何 LLM 接入源。")
tokens = self.manager.command_parser.parse(message.message_str)
if tokens.len == 1:
ret = "## 当前载入的 LLM \n"
ret = "## 当前载入的 LLM 接入\n"
for idx, llm in enumerate(context.llms):
ret += f"{idx}. {llm.llm_name}"
if llm.origin:
@@ -44,7 +44,7 @@ class InternalCommandHandler:
ret += " (当前使用)"
ret += "\n"
ret += "\n使用 provider <序号> 切换 LLM 源。"
ret += "\n使用 provider <序号> 切换 LLM 接入源。"
return CommandResult().message(ret)
else:
try:
@@ -52,7 +52,7 @@ class InternalCommandHandler:
if idx >= len(context.llms):
return CommandResult().message("provider: 无效的序号。")
context.message_handler.set_provider(context.llms[idx].llm_instance)
return CommandResult().message(f"已经成功切换到 LLM {context.llms[idx].llm_name}")
return CommandResult().message(f"已经成功切换到 LLM 接入{context.llms[idx].llm_name}")
except BaseException as e:
return CommandResult().message("provider: 参数错误。")
@@ -71,7 +71,7 @@ class InternalCommandHandler:
return CommandResult(
hit=True,
success=True,
message_chain=f"已经成功将唤醒设定为 {nick}",
message_chain=f"已经成功将唤醒前缀设定为 {nick}",
)
def update(self, message: AstrMessageEvent, context: Context):
@@ -280,5 +280,5 @@ class InternalCommandHandler:
return CommandResult(
hit=True,
success=False,
message_chain=f"{message.platform} 上获取你的ID失败,原因: {str(e)}",
message_chain=f"获取失败,原因: {str(e)}",
)
-1
View File
@@ -24,4 +24,3 @@ class PluginCommandBridge():
def register_command(self, plugin_name, command_name, description, priority, handler, use_regex=False, ignore_prefix=False):
self.plugin_commands_waitlist.append(CommandRegisterRequest(command_name, description, priority, handler, use_regex, plugin_name, ignore_prefix))
+1 -1
View File
@@ -184,7 +184,7 @@ class PluginManager():
self.check_plugin_dept_update(target_plugin=root_dir_name)
module = __import__("addons.plugins." +
module = __import__("data.plugins." +
root_dir_name + "." + p, fromlist=[p])
cls = self.get_classes(module)
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION = '3.3.9'
VERSION = '3.3.12'
DEFAULT_CONFIG = {
"qqbot": {
+26 -1
View File
@@ -1,6 +1,8 @@
import os
import json
import shutil
import logging
from util.io import on_error
from type.config import DEFAULT_CONFIG, DEFAULT_CONFIG_VERSION_2, MAPPINGS_1_2
from dataclasses import dataclass, field, asdict
from typing import List, Dict, Optional
@@ -295,4 +297,27 @@ class AstrBotConfig():
raise KeyError(f"Key {key} not found in config.")
def check_exist(self) -> bool:
return os.path.exists(ASTRBOT_CONFIG_PATH)
return os.path.exists(ASTRBOT_CONFIG_PATH)
def try_migrate():
'''
- 将 cmd_config.json 迁移至 data/cmd_config.json (如果存在)
- 将 addons/plugins 迁移至 data/plugins (如果存在)
'''
if os.path.exists("cmd_config.json") and not os.path.exists("data/cmd_config.json"):
try:
shutil.move("cmd_config.json", "data/cmd_config.json")
except:
logger.error("迁移 cmd_config.json 失败。")
if os.path.exists("addons/plugins"):
if os.path.exists("data/plugins"):
try:
shutil.rmtree("data/plugins", onerror=on_error)
except:
logger.error("删除 data/plugins 失败。")
try:
shutil.move("addons/plugins", "data/")
shutil.rmtree("addons", onerror=on_error)
except:
logger.error("迁移 addons/plugins 失败。")
-15
View File
@@ -1,15 +0,0 @@
import json, os, shutil
import logging
logger = logging.getLogger("astrbot")
def try_migrate_config():
'''
将 cmd_config.json 迁移至 data/cmd_config.json (如果存在的话)
'''
if os.path.exists("cmd_config.json") and not os.path.exists("data/cmd_config.json"):
try:
shutil.move("cmd_config.json", "data/cmd_config.json")
except:
logger.error("迁移 cmd_config.json 失败。AstrBot 将不会读取配置文件,你可以手动将 cmd_config.json 迁移至 data/cmd_config.json。")
+4 -6
View File
@@ -47,13 +47,11 @@ def port_checker(port: int, host: str = "localhost"):
def save_temp_img(img: Image) -> str:
if not os.path.exists("temp"):
os.makedirs("temp")
os.makedirs("data/temp", exist_ok=True)
# 获得文件创建时间,清除超过1小时的
try:
for f in os.listdir("temp"):
path = os.path.join("temp", f)
for f in os.listdir("data/temp"):
path = os.path.join("data/temp", f)
if os.path.isfile(path):
ctime = os.path.getctime(path)
if time.time() - ctime > 3600:
@@ -63,7 +61,7 @@ def save_temp_img(img: Image) -> str:
# 获得时间戳
timestamp = int(time.time())
p = f"temp/{timestamp}.jpg"
p = f"data/temp/{timestamp}.jpg"
if isinstance(img, Image.Image):
img.save(p)
+2 -39
View File
@@ -1,4 +1,4 @@
import os, psutil, sys, zipfile, shutil, time
import os, psutil, sys, time
from util.updator.zip_updator import ReleaseInfo, RepoZipUpdator
from SparkleLogging.utils.core import LogManager
from logging import Logger
@@ -65,7 +65,6 @@ class AstrBotUpdator(RepoZipUpdator):
raise Exception(f"未找到版本号为 {version} 的更新文件。")
try:
# self.download_from_repo_url("temp", file_url)
download_file(file_url, "temp.zip")
self.unzip_file("temp.zip", self.MAIN_PATH)
except BaseException as e:
@@ -78,40 +77,4 @@ class AstrBotUpdator(RepoZipUpdator):
'''
解压缩文件, 并将压缩包内**第一个**文件夹内的文件移动到 target_dir
'''
os.makedirs(target_dir, exist_ok=True)
update_dir = ""
logger.info(f"解压文件: {zip_path}")
with zipfile.ZipFile(zip_path, 'r') as z:
update_dir = z.namelist()[0]
z.extractall(target_dir)
avoid_dirs = ["logs", "data", "configs", "temp_plugins", update_dir]
# copy addons/plugins to the target_dir temporarily
if os.path.exists(os.path.join(target_dir, "addons/plugins")):
logger.info("备份插件目录:从 addons/plugins 到 temp_plugins")
shutil.copytree(os.path.join(target_dir, "addons/plugins"), "temp_plugins")
files = os.listdir(os.path.join(target_dir, update_dir))
for f in files:
logger.info(f"移动更新文件/目录: {f}")
if os.path.isdir(os.path.join(target_dir, update_dir, f)):
if f in avoid_dirs: continue
if os.path.exists(os.path.join(target_dir, f)):
shutil.rmtree(os.path.join(target_dir, f), onerror=on_error)
else:
if os.path.exists(os.path.join(target_dir, f)):
os.remove(os.path.join(target_dir, f))
shutil.move(os.path.join(target_dir, update_dir, f), target_dir)
# move back
if os.path.exists("temp_plugins"):
logger.info("恢复插件目录:从 temp_plugins 到 addons/plugins")
shutil.rmtree(os.path.join(target_dir, "addons/plugins"), onerror=on_error)
shutil.move("temp_plugins", os.path.join(target_dir, "addons/plugins"))
try:
logger.info(f"删除临时更新文件: {zip_path}{os.path.join(target_dir, update_dir)}")
shutil.rmtree(os.path.join(target_dir, update_dir), onerror=on_error)
os.remove(zip_path)
except:
logger.warn(f"删除更新文件失败,可以手动删除 {zip_path}{os.path.join(target_dir, update_dir)}")
pass
+40 -4
View File
@@ -1,19 +1,19 @@
import os
import os, zipfile, shutil
from util.updator.zip_updator import RepoZipUpdator
from util.io import remove_dir
from type.plugin import PluginMetadata
from type.register import RegisteredPlugin
from typing import Union
from SparkleLogging.utils.core import LogManager
from logging import Logger
from util.io import on_error
logger: Logger = LogManager.GetLogger(log_name='astrbot')
class PluginUpdator(RepoZipUpdator):
def __init__(self) -> None:
self.plugin_store_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../addons/plugins"))
self.plugin_store_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../data/plugins"))
def get_plugin_store_path(self) -> str:
return self.plugin_store_path
@@ -44,5 +44,41 @@ class PluginUpdator(RepoZipUpdator):
return plugin_path
def unzip_file(self, zip_path: str, target_dir: str):
os.makedirs(target_dir, exist_ok=True)
update_dir = ""
logger.info(f"解压文件: {zip_path}")
with zipfile.ZipFile(zip_path, 'r') as z:
update_dir = z.namelist()[0]
z.extractall(target_dir)
avoid_dirs = ["logs", "data", "configs", "temp_plugins", update_dir]
# copy addons/plugins to the target_dir temporarily
# if os.path.exists(os.path.join(target_dir, "addons/plugins")):
# logger.info("备份插件目录:从 addons/plugins 到 temp_plugins")
# shutil.copytree(os.path.join(target_dir, "addons/plugins"), "temp_plugins")
files = os.listdir(os.path.join(target_dir, update_dir))
for f in files:
logger.info(f"移动更新文件/目录: {f}")
if os.path.isdir(os.path.join(target_dir, update_dir, f)):
if f in avoid_dirs: continue
if os.path.exists(os.path.join(target_dir, f)):
shutil.rmtree(os.path.join(target_dir, f), onerror=on_error)
else:
if os.path.exists(os.path.join(target_dir, f)):
os.remove(os.path.join(target_dir, f))
shutil.move(os.path.join(target_dir, update_dir, f), target_dir)
# move back
# if os.path.exists("temp_plugins"):
# logger.info("恢复插件目录:从 temp_plugins 到 addons/plugins")
# shutil.rmtree(os.path.join(target_dir, "addons/plugins"), onerror=on_error)
# shutil.move("temp_plugins", os.path.join(target_dir, "addons/plugins"))
try:
logger.info(f"删除临时更新文件: {zip_path}{os.path.join(target_dir, update_dir)}")
shutil.rmtree(os.path.join(target_dir, update_dir), onerror=on_error)
os.remove(zip_path)
except:
logger.warn(f"删除更新文件失败,可以手动删除 {zip_path}{os.path.join(target_dir, update_dir)}")