合并轻雪f22f4d2更新,增加人性化语言内容。

This commit is contained in:
2024-07-25 01:58:21 +08:00
parent 0cb38d8ce7
commit da08f8d085
45 changed files with 1050 additions and 215 deletions

View File

@ -1,6 +0,0 @@
import abc
class Bot(abc.ABC):
def __init__(self):
pass

View File

@ -1,10 +0,0 @@
"""exception模块包含了liteyuki运行中的所有错误
"""
from typing import Any, Optional
class LiteyukiException(BaseException):
"""Liteyuki的异常基类。"""
def __str__(self) -> str:
return self.__repr__()

View File

@ -11,24 +11,15 @@ __plugin_meta__ = PluginMetadata(
usage="",
homepage="https://github.com/snowykami/LiteyukiBot",
extra={
"liteyuki" : True,
"toggleable": False,
}
"liteyuki": True,
"toggleable": False,
},
)
from ..utils.base.language import Language, get_default_lang_code
print("\033[34m" + r"""
__ ______ ________ ________ __ __ __ __ __ __ ______
/ | / |/ |/ |/ \ / |/ | / |/ | / |/ |
$$ | $$$$$$/ $$$$$$$$/ $$$$$$$$/ $$ \ /$$/ $$ | $$ |$$ | /$$/ $$$$$$/
$$ | $$ | $$ | $$ |__ $$ \/$$/ $$ | $$ |$$ |/$$/ $$ |
$$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |$$ $$< $$ |
$$ | $$ | $$ | $$$$$/ $$$$/ $$ | $$ |$$$$$ \ $$ |
$$ |_____ _$$ |_ $$ | $$ |_____ $$ | $$ \__$$ |$$ |$$ \ _$$ |_
$$ |/ $$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |/ $$ |
$$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/
""" + "\033[0m")
sys_lang = Language(get_default_lang_code())
nonebot.logger.info(sys_lang.get("main.current_language", LANG=sys_lang.get("language.name")))
nonebot.logger.info(
sys_lang.get("main.current_language", LANG=sys_lang.get("language.name"))
)

View File

@ -16,9 +16,12 @@ from src.utils.base.data_manager import StoredConfig, TempConfig, common_db
from src.utils.base.language import get_user_lang
from src.utils.base.ly_typing import T_Bot, T_MessageEvent
from src.utils.message.message import MarkdownMessage as md, broadcast_to_superusers
from src.utils.base.reloader import Reloader
# from src.liteyuki.core import Reloader
from src.utils import event as event_utils, satori_utils
from liteyuki.core import ProcessingManager
from .api import update_liteyuki
from liteyuki.bot import get_bot
from ..utils.base.ly_function import get_function
require("nonebot_plugin_alconna")
@ -115,7 +118,9 @@ async def _(matcher: Matcher, bot: T_Bot, event: T_MessageEvent):
)
common_db.save(temp_data)
Reloader.reload(0)
# Reloader.reload(0)
bot = get_bot()
bot.restart()
@on_alconna(
@ -314,7 +319,6 @@ async def _(result: Arparma, bot: T_Bot, event: T_MessageEvent, matcher: Matcher
result = str(e)
args_show = "\n".join("- %s: %s" % (k, v) for k, v in args_dict.items())
print(f"API: {api_name}\n\nArgs: \n{args_show}\n\nResult: {result}")
await matcher.finish(f"API: {api_name}\n\nArgs: \n{args_show}\n\nResult: {result}")
@ -376,12 +380,19 @@ async def test_for_md_image(bot: T_Bot, api: str, data: dict):
@driver.on_startup
async def on_startup():
temp_data = common_db.where_one(TempConfig(), default=TempConfig())
# 储存重启信息
if temp_data.data.get("reload", False):
delta_time = time.time() - temp_data.data.get("reload_time", 0)
temp_data.data["delta_time"] = delta_time
common_db.save(temp_data) # 更新数据
# temp_data = common_db.where_one(TempConfig(), default=TempConfig())
# # 储存重启信息
# if temp_data.data.get("reload", False):
# delta_time = time.time() - temp_data.data.get("reload_time", 0)
# temp_data.data["delta_time"] = delta_time
# common_db.save(temp_data) # 更新数据
"""
该部分迁移至轻雪生命周期
Returns:
"""
pass
@driver.on_shutdown
@ -407,7 +418,7 @@ async def _(bot: T_Bot):
if isinstance(bot, satori.Bot):
await bot.send_message(
channel_id=reload_session_id,
message="灵温 重载耗时 %.2f" % delta_time,
message="轻雪核心 重载耗时 {:.2f}\n*此数据仅作参考,具体计时请以实际为准\n灵温 预计体感重载耗时 {:.2f}".format(delta_time,time.time() - temp_data.data.get("reload_time", 0)),
)
else:
await bot.call_api(
@ -415,7 +426,7 @@ async def _(bot: T_Bot):
message_type=reload_session_type,
user_id=reload_session_id,
group_id=reload_session_id,
message="灵温 重载耗时 %.2f" % delta_time,
message="轻雪核心 重载耗时 {:.2f}\n*此数据仅作参考,具体计时请以实际为准\n灵温 预计体感重载耗时 {:.2f}".format(delta_time,time.time() - temp_data.data.get("reload_time", 0)),
)
@ -426,9 +437,9 @@ async def every_day_update():
result, logs = update_liteyuki()
pip.main(["install", "-r", "requirements.txt"])
if result:
await broadcast_to_superusers(f"灵温已更新: ```\n{logs}\n```")
nonebot.logger.info(f"灵温已更新: {logs}")
Reloader.reload(5)
await broadcast_to_superusers(f"灵温已更新:```\n{logs}\n```")
nonebot.logger.info(f"灵温已更新:{logs}")
ProcessingManager.restart(3)
else:
nonebot.logger.info(logs)

View File

@ -2,28 +2,28 @@ import nonebot
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from liteyuki.bot import get_bot
from src.utils.base.config import get_config
from src.utils.base.reloader import Reloader
from liteyuki.core import ProcessingManager
from src.utils.base.resource import load_resources
if get_config("debug", False):
liteyuki_bot = get_bot()
src_directories = (
"src/liteyuki_main",
"src/plugins",
"src/utils",
)
src_excludes_extensions = (
"pyc",
)
src_excludes_extensions = ("pyc",)
res_directories = (
"src/resources",
"resources",
)
nonebot.logger.info("Liteyuki Reload enabled, watching for file changes...")
nonebot.logger.info("已启用 Liteyuki Reload ,正在监测文件变动。")
class CodeModifiedHandler(FileSystemEventHandler):
"""
@ -31,12 +31,14 @@ if get_config("debug", False):
"""
def on_modified(self, event):
if event.src_path.endswith(
src_excludes_extensions) or event.is_directory or "__pycache__" in event.src_path:
if (
event.src_path.endswith(src_excludes_extensions)
or event.is_directory
or "__pycache__" in event.src_path
):
return
nonebot.logger.info(f"{event.src_path} modified, reloading bot...")
Reloader.reload()
nonebot.logger.info(f"文件 {event.src_path} 变更,正在重载…")
liteyuki_bot.restart()
class ResourceModifiedHandler(FileSystemEventHandler):
"""
@ -44,10 +46,9 @@ if get_config("debug", False):
"""
def on_modified(self, event):
nonebot.logger.info(f"{event.src_path} modified, reloading resource...")
nonebot.logger.info(f"资源 {event.src_path} 变更,重载资源包…")
load_resources()
code_modified_handler = CodeModifiedHandler()
resource_modified_handle = ResourceModifiedHandler()

View File

@ -6,10 +6,13 @@ from src.utils.base.data_manager import InstalledPlugin, plugin_db
from src.utils.base.resource import load_resources
from src.utils.message.tools import check_for_package
from liteyuki import get_bot
load_resources()
init_log()
driver = get_driver()
liteyuki_bot = get_bot()
@driver.on_startup
@ -18,14 +21,47 @@ async def load_plugins():
# 从数据库读取已安装的插件
if not get_config("safe_mode", False):
# 安全模式下,不加载插件
installed_plugins: list[InstalledPlugin] = plugin_db.where_all(InstalledPlugin())
installed_plugins: list[InstalledPlugin] = plugin_db.where_all(
InstalledPlugin()
)
if installed_plugins:
for installed_plugin in installed_plugins:
if not check_for_package(installed_plugin.module_name):
nonebot.logger.error(
f"{installed_plugin.module_name} not installed, but in loading database. please run `npm fixup` in chat to reinstall it.")
f"插件 {installed_plugin.module_name} 在加载列表中但未安装。请使用超管账户对机器人发送 `npm fixup` 以重新安装。"
)
else:
nonebot.load_plugin(installed_plugin.module_name)
nonebot.plugin.load_plugins("plugins")
else:
nonebot.logger.info("Safe mode is on, no plugin loaded.")
nonebot.logger.info("安全模式已启动,未加载任何插件。")
@liteyuki_bot.on_before_start
async def _():
print("启动前")
@liteyuki_bot.on_after_start
async def _():
print("启动后")
@liteyuki_bot.on_before_shutdown
async def _():
print("停止前")
@liteyuki_bot.on_after_shutdown
async def _():
print("停止后")
@liteyuki_bot.on_before_restart
async def _():
print("重启前")
@liteyuki_bot.on_after_restart
async def _():
print("重启后")

View File

@ -1,4 +1,7 @@
import multiprocessing
from nonebot.plugin import PluginMetadata
from liteyuki.plugin import get_loaded_plugins
from .rt_guide import *
from .crt_matchers import *
@ -14,3 +17,5 @@ __plugin_meta__ = PluginMetadata(
"default_enable": True,
}
)
print("已加载插件:", len(get_loaded_plugins()))

View File

@ -554,7 +554,7 @@ async def _(result: Arparma, event: T_MessageEvent, bot: T_Bot, npm: Matcher):
Subcommand(
disable,
Args["group_id", str, None],
alias=["d", "停用"],
alias=["d", "停用","禁用"],
),
),
permission=SUPERUSER | GROUP_OWNER | GROUP_ADMIN,

View File

@ -1,21 +1,21 @@
from nonebot.plugin import PluginMetadata
from .main import *
__author__ = "snowykami"
__plugin_meta__ = PluginMetadata(
name="网页监控面板",
description="网页监控面板,用于查看机器人的状态和信息",
usage=(
"访问 127.0.0.1:port 查看机器人的状态信息\n"
"stat msg -g|--group [group_id] 查看群的统计信息,不带参数为全群\n"
"配置项custom_domain自定义域名通常对外用内网无需"
),
type="application",
homepage="https://github.com/snowykami/LiteyukiBot",
extra={
"liteyuki" : True,
"toggleable" : False,
"default_enable": True,
}
)
from nonebot.plugin import PluginMetadata
from .main import *
__author__ = "snowykami"
__plugin_meta__ = PluginMetadata(
name="网页监控面板",
description="网页监控面板,用于查看机器人的状态和信息",
usage=(
"访问 127.0.0.1:port 查看机器人的状态信息\n"
"stat msg -g|--group [group_id] 查看群的统计信息,不带参数为全群\n"
"配置项custom_domain自定义域名通常对外用内网无需"
),
type="application",
homepage="https://github.com/snowykami/LiteyukiBot",
extra={
"liteyuki" : True,
"toggleable" : False,
"default_enable": True,
}
)

View File

@ -1,4 +1,4 @@
from fastapi import FastAPI
from nonebot import get_app
from fastapi import FastAPI
from nonebot import get_app
app: FastAPI = get_app()

View File

@ -1,10 +1,10 @@
from fastapi import FastAPI
from nonebot import get_app
from .restful_api import *
@app.get("/ping")
async def root():
return {
"message": "pong"
}
from fastapi import FastAPI
from nonebot import get_app
from .restful_api import *
@app.get("/ping")
async def root():
return {
"message": "pong"
}

View File

@ -1,24 +1,24 @@
from fastapi import FastAPI, APIRouter
from .common import *
device_info_router = APIRouter(prefix="/api/device-info")
bot_info_router = APIRouter(prefix="/api/bot-info")
@device_info_router.get("/")
async def device_info():
print("Hello Device Info")
return {
"message": "Hello Device Info"
}
@bot_info_router.get("/")
async def bot_info():
return {
"message": "Hello Bot Info"
}
app.include_router(device_info_router)
app.include_router(bot_info_router)
from fastapi import FastAPI, APIRouter
from .common import *
device_info_router = APIRouter(prefix="/api/device-info")
bot_info_router = APIRouter(prefix="/api/bot-info")
@device_info_router.get("/")
async def device_info():
print("Hello Device Info")
return {
"message": "Hello Device Info"
}
@bot_info_router.get("/")
async def bot_info():
return {
"message": "Hello Bot Info"
}
app.include_router(device_info_router)
app.include_router(bot_info_router)

View File

@ -1,29 +0,0 @@
import nonebot
from src.utils import adapter_manager, driver_manager, init
from src.utils.base.config import load_from_yaml
from src.utils.base.data_manager import StoredConfig, common_db
from src.utils.base.ly_api import liteyuki_api
if __name__ == "__mp_main__":
# Start as multiprocessing
init()
store_config: dict = common_db.where_one(StoredConfig(), default=StoredConfig()).config
static_config = load_from_yaml("config.yml")
store_config.update(static_config)
driver_manager.init(config=store_config)
adapter_manager.init(store_config)
nonebot.init(**store_config)
adapter_manager.register()
try:
nonebot.load_plugin("liteyuki.liteyuki_main")
nonebot.load_from_toml("pyproject.toml")
except BaseException as e:
if not isinstance(e, KeyboardInterrupt):
nonebot.logger.error(f"An error occurred: {e}, Bug will be reported automatically.")
liteyuki_api.bug_report(str(e.__repr__()))
if __name__ == "__main__":
# Start as __main__
from src.utils.base.reloader import Reloader
nonebot.run()

View File

@ -6,8 +6,8 @@ import time
import nonebot
__NAME__ = "LiteyukiBot-TriMO"
__VERSION__ = "6.3.3" # 60201
__NAME__ = "尹灵温|轻雪-睿乐"
__VERSION__ = "6.3.4" # 60201
# __VERSION_I__ = 99060303
import requests

View File

@ -7,14 +7,14 @@ from nonebot.adapters import satori
def init(config: dict):
if config.get("satori", None) is None:
nonebot.logger.info("Satori config not found, skip Satori init.")
nonebot.logger.info("未查见 Satori 的配置文档,将跳过 Satori 初始化")
return None
satori_config = config.get("satori")
if not satori_config.get("enable", False):
nonebot.logger.info("Satori not enabled, skip Satori init.")
nonebot.logger.info("未启用 Satori ,将跳过 Satori 初始化")
return None
if os.getenv("SATORI_CLIENTS", None) is not None:
nonebot.logger.info("Satori clients already set in environment variable, skip.")
nonebot.logger.info("Satori 客户端已设入环境变量,跳过此步。")
os.environ["SATORI_CLIENTS"] = json.dumps(satori_config.get("hosts", []), ensure_ascii=False)
config['satori_clients'] = satori_config.get("hosts", [])
return

View File

@ -20,25 +20,26 @@ class SatoriNodeConfig(BaseModel):
class SatoriConfig(BaseModel):
comment: str = "These features are still in development. Do not enable in production environment."
comment: str = "此皆正处于开发之中,切勿在生产环境中启用。"
enable: bool = False
hosts: List[SatoriNodeConfig] = [SatoriNodeConfig()]
class BasicConfig(BaseModel):
host: str = "127.0.0.1"
port: int = 20216
port: int = 20247
superusers: list[str] = []
command_start: list[str] = ["/", ""]
nickname: list[str] = [f"LiteyukiBot-{random_hex_string(6)}"]
nickname: list[str] = [f"灵温-{random_hex_string(6)}"]
satori: SatoriConfig = SatoriConfig()
data_path: str = "data/liteyuki"
def load_from_yaml(file: str) -> dict:
global config
nonebot.logger.debug("Loading config from %s" % file)
if not os.path.exists(file):
nonebot.logger.warning(f"Config file {file} not found, created default config, please modify it and restart")
nonebot.logger.warning(f"未找到配置文件 {file} ,已创建默认配置,请修改后重启。")
with open(file, "w", encoding="utf-8") as f:
yaml.dump(BasicConfig().dict(), f, default_flow_style=False)
@ -46,7 +47,7 @@ def load_from_yaml(file: str) -> dict:
conf = init_conf(yaml.load(f, Loader=yaml.FullLoader))
config = conf
if conf is None:
nonebot.logger.warning(f"Config file {file} is empty, use default config. please modify it and restart")
nonebot.logger.warning(f"配置文件 {file} 为空,已创建默认配置,请修改后重启。")
conf = BasicConfig().dict()
return conf
@ -95,6 +96,8 @@ def init_conf(conf: dict) -> dict:
"""
# 若command_start中无""则添加必要命令头开启alconna_use_command_start防止冲突
if "" not in conf.get("command_start", []):
conf["alconna_use_command_start"] = True
# 以下内容由于issue #53 被注释
# if "" not in conf.get("command_start", []):
# conf["alconna_use_command_start"] = True
return conf
pass

View File

@ -20,8 +20,9 @@ class LiteyukiAPI:
self.data = json.loads(f.read())
self.liteyuki_id = self.data.get("liteyuki_id")
self.report = load_from_yaml("config.yml").get("auto_report", True)
if self.report:
nonebot.logger.info("Auto bug report is enabled")
nonebot.logger.info("已启用自动上报")
@property
def device_info(self) -> dict:
@ -37,10 +38,10 @@ class LiteyukiAPI:
"python" : f"{platform.python_implementation()} {platform.python_version()}",
"os" : f"{platform.system()} {platform.version()} {platform.machine()}",
"cpu" : f"{psutil.cpu_count(logical=False)}c{psutil.cpu_count()}t{psutil.cpu_freq().current}MHz",
"memory_total": f"{psutil.virtual_memory().total / 1024 / 1024 / 1024:.2f}GB",
"memory_used" : f"{psutil.virtual_memory().used / 1024 / 1024 / 1024:.2f}GB",
"memory_bot" : f"{psutil.Process(os.getpid()).memory_info().rss / 1024 / 1024:.2f}MB",
"disk" : f"{psutil.disk_usage('/').total / 1024 / 1024 / 1024:.2f}GB"
"memory_total": f"{psutil.virtual_memory().total / 1024 ** 3:.2f}吉字节",
"memory_used" : f"{psutil.virtual_memory().used / 1024 ** 3:.2f}吉字节",
"memory_bot" : f"{psutil.Process(os.getpid()).memory_info().rss / 1024 ** 2:.2f}兆字节",
"disk" : f"{psutil.disk_usage('/').total / 1024 ** 3:.2f}吉字节"
}
def bug_report(self, content: str):
@ -53,7 +54,7 @@ class LiteyukiAPI:
"""
if self.report:
nonebot.logger.warning(f"Reporting bug...: {content}")
nonebot.logger.warning(f"正在上报查误:{content}")
url = "https://api.liteyuki.icu/bug_report"
data = {
"liteyuki_id": self.liteyuki_id,
@ -62,11 +63,11 @@ class LiteyukiAPI:
}
resp = requests.post(url, json=data)
if resp.status_code == 200:
nonebot.logger.success(f"Bug report sent successfully, report_id: {resp.json().get('report_id')}")
nonebot.logger.success(f"成功上报差误信息报文ID为{resp.json().get('report_id')}")
else:
nonebot.logger.error(f"Bug report failed: {resp.text}")
nonebot.logger.error(f"差误上报错误:{resp.text}")
else:
nonebot.logger.warning(f"Bug report is disabled: {content}")
nonebot.logger.warning(f"已禁用自动上报:{content}")
async def heartbeat_report(self):
"""
@ -77,14 +78,11 @@ class LiteyukiAPI:
url = "https://api.liteyuki.icu/heartbeat"
data = {
"liteyuki_id": self.liteyuki_id,
"version": __VERSION__,
"version" : __VERSION__,
}
async with aiohttp.ClientSession() as session:
async with session.post(url, json=data) as resp:
if resp.status == 200:
nonebot.logger.success("Heartbeat sent successfully")
nonebot.logger.success("心跳成功送达。")
else:
nonebot.logger.error(f"Heartbeat failed: {await resp.text()}")
liteyuki_api = LiteyukiAPI()
nonebot.logger.error(f"休克:{await resp.text()}")

View File

@ -9,13 +9,12 @@ from .defines import *
def auto_set_env(config: dict):
dotenv.load_dotenv(".env")
if os.getenv("DRIVER", None) is not None:
print(os.getenv("DRIVER"))
nonebot.logger.info("Driver already set in environment variable, skip auto configure.")
nonebot.logger.info("Driver 已设入环境变量中,将跳过自动配置环节。")
return
if config.get("satori", {'enable': False}).get("enable", False):
os.environ["DRIVER"] = get_driver_string(ASGI_DRIVER, HTTPX_DRIVER, WEBSOCKETS_DRIVER)
nonebot.logger.info("Enable Satori, set driver to ASGI+HTTPX+WEBSOCKETS")
nonebot.logger.info("已启用 Satori,将 driver 设为 ASGI+HTTPX+WEBSOCKETS")
else:
os.environ["DRIVER"] = get_driver_string(ASGI_DRIVER)
nonebot.logger.info("Disable Satori, set driver to ASGI")
nonebot.logger.info("已禁用 Satori,将 driver 设为 ASGI")
return

View File

@ -1,15 +1,17 @@
from aiohttp import ClientSession
async def simple_get(url: str) -> str:
"""
简单异步get请求
Args:
url:
Returns:
"""
async with ClientSession() as session:
async with session.get(url) as resp:
return await resp.text()
from aiohttp import ClientSession
from .net import *
from .file import *
async def simple_get(url: str) -> str:
"""
简单异步get请求
Args:
url:
Returns:
"""
async with ClientSession() as session:
async with session.get(url) as resp:
return await resp.text()

29
src/utils/io/file.py Normal file
View File

@ -0,0 +1,29 @@
import aiofiles
async def write_file(
file_path: str,
content: str | bytes,
mode: str = "w"
):
"""
写入文件
Args:
mode: 写入模式
file_path: 文件路径
content: 内容
"""
async with aiofiles.open(file_path, mode) as f:
await f.write(content)
async def read_file(file_path: str, mode: str = "r") -> str:
"""
读取文件
Args:
file_path: 文件路径
mode: 读取模式
Returns:
"""
async with aiofiles.open(file_path, mode) as f:
return await f.read()

12
src/utils/io/net.py Normal file
View File

@ -0,0 +1,12 @@
async def fetch(url: str) -> str:
"""
异步get请求
Args:
url:
Returns:
"""
async with ClientSession() as session:
async with session.get(url) as resp:
return await resp.text()