🔀手动Merge轻雪主仓库a77f97f

This commit is contained in:
2024-10-06 02:39:10 +08:00
parent 4cc2ae61db
commit f8b57bfe9a
108 changed files with 3131 additions and 3574 deletions

View File

@ -1,103 +1,102 @@
import asyncio
import atexit
import os
import platform
import signal
import sys
import threading
import time
from typing import Any, Optional
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer
from liteyuki.bot.lifespan import LIFESPAN_FUNC, Lifespan
from liteyuki.core import IS_MAIN_PROCESS
from liteyuki.bot.lifespan import LIFESPAN_FUNC, Lifespan, PROCESS_LIFESPAN_FUNC
from liteyuki.comm.channel import get_channel
from liteyuki.core.manager import ProcessManager
from liteyuki.core.spawn_process import mb_run, nb_run
from liteyuki.log import init_log, logger
from liteyuki.plugin import load_plugins
from liteyuki.plugin import load_plugin
from liteyuki.utils import IS_MAIN_PROCESS
__all__ = ["LiteyukiBot", "get_bot"]
__all__ = [
"LiteyukiBot",
"get_bot",
"get_config",
"get_config_with_compat",
]
class LiteyukiBot:
def __init__(self, *args, **kwargs):
def __init__(self, **kwargs) -> None:
"""
初始化轻雪实例
Args:
**kwargs: 配置
"""
"""常规操作"""
print_logo()
global _BOT_INSTANCE
_BOT_INSTANCE = self # 引用
"""配置"""
self.config: dict[str, Any] = kwargs
"""初始化"""
self.init(**self.config) # 初始化
logger.info("尹灵温 正在初始化…")
self.lifespan: Lifespan = Lifespan()
"""生命周期管理"""
self.lifespan = Lifespan()
self.process_manager: ProcessManager = ProcessManager(lifespan=self.lifespan)
self.process_manager: ProcessManager = ProcessManager(bot=self)
"""事件循环"""
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
self.loop_thread = threading.Thread(target=self.loop.run_forever, daemon=True)
self.stop_event = threading.Event()
self.call_restart_count = 0
"""加载插件加载器"""
load_plugin("liteyuki.plugins.plugin_loader") # 加载轻雪插件
async def _run(self):
"""
启动逻辑
"""
await self.lifespan.before_start() # 启动前钩子
await self.lifespan.after_start() # 启动后钩子
await self.keep_alive()
def run(self):
load_plugins("liteyuki/plugins") # 加载轻雪插件
"""
外部启动接口
"""
self.process_manager.start_all()
try:
asyncio.run(self._run())
except KeyboardInterrupt:
logger.opt(colors=True).info("<y>尹灵温 关闭中…</y>")
self.stop()
logger.opt(colors=True).info("<y>尹灵温 已关停</y>")
self.loop_thread.start() # 启动事件循环
asyncio.run(self.lifespan.before_start()) # 启动前钩子
self.process_manager.add_target("nonebot", nb_run, **self.config)
self.process_manager.start("nonebot")
self.process_manager.add_target("melobot", mb_run, **self.config)
self.process_manager.start("melobot")
asyncio.run(self.lifespan.after_start()) # 启动后钩子
self.start_watcher() # 启动文件监视器
def start_watcher(self):
if self.config.get("debug", False):
src_directories = (
"liteyuki",
"src/liteyuki_main",
"src/liteyuki_plugins",
"src/nonebot_plugins",
"src/utils",
)
src_excludes_extensions = ("pyc",)
logger.debug("轻雪重载 已启用,正在加载文件修改监测……")
restart = self.restart_process
class CodeModifiedHandler(FileSystemEventHandler):
"""
Handler for code file changes
"""
def on_modified(self, event):
if (
event.src_path.endswith(src_excludes_extensions)
or event.is_directory
or "__pycache__" in event.src_path
):
return
logger.info(f"文件 {event.src_path} 已修改,机器人自动重启……")
restart()
code_modified_handler = CodeModifiedHandler()
observer = Observer()
for directory in src_directories:
observer.schedule(code_modified_handler, directory, recursive=True)
observer.start()
async def keep_alive(self):
"""
保持轻雪运行
"""
logger.info("尹灵温 持续运行中…")
try:
while not self.stop_event.is_set():
await asyncio.sleep(0.1)
except Exception:
logger.info("尹灵温 现退停…")
self.stop()
def restart(self, delay: int = 0):
"""
重启轻雪本体
Returns:
Args:
delay ([`int`](https%3A//docs.python.org/3/library/functions.html#int), optional): 延迟重启时间. Defaults to 0.
"""
if self.call_restart_count < 1:
executable = sys.executable
args = sys.argv
logger.info("正在重启 尹灵温...")
logger.info("正在重启 尹灵温机器人框架")
time.sleep(delay)
if platform.system() == "Windows":
cmd = "start"
@ -110,7 +109,9 @@ class LiteyukiBot:
self.process_manager.terminate_all()
# 进程退出后重启
threading.Thread(
target=os.system, args=(f"{cmd} {executable} {' '.join(args)}",)
target=os.system,
args=(f"{cmd} {executable} {' '.join(args)}",),
daemon=True,
).start()
sys.exit(0)
self.call_restart_count += 1
@ -119,44 +120,46 @@ class LiteyukiBot:
"""
停止轻雪
Args:
name: 进程名称, 默认为None, 所有进程
name ([`Optional`](https%3A//docs.python.org/3/library/typing.html#typing.Optional)[[`str`](https%3A//docs.python.org/3/library/stdtypes.html#str)]): 进程名. Defaults to None.
Returns:
"""
logger.info("Stopping LiteyukiBot...")
self.loop.create_task(self.lifespan.before_shutdown()) # 重启前钩子
self.loop.create_task(self.lifespan.before_shutdown()) # 停止前钩子
if name:
self.process_manager.terminate(name)
if name is not None:
chan_active = get_channel(f"{name}-active")
chan_active.send(1)
else:
self.process_manager.terminate_all()
for process_name in self.process_manager.processes:
chan_active = get_channel(f"{process_name}-active")
chan_active.send(1)
def init(self, *args, **kwargs):
"""
初始化轻雪, 自动调用
Returns:
Args:
*args: 参数
**kwargs: 关键字参数
"""
self.init_config()
self.init_logger()
def init_logger(self):
# 修改nonebot的日志配置
"""
初始化日志
"""
init_log(config=self.config)
def init_config(self):
pass
def stop(self):
"""
停止轻雪
"""
self.process_manager.terminate_all()
self.stop_event.set()
def on_before_start(self, func: LIFESPAN_FUNC):
def on_before_start(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
"""
注册启动前的函数
Args:
func:
func ([`LIFESPAN_FUNC`](./lifespan#var-lifespan-func)): 生命周期函数
Returns:
[`LIFESPAN_FUNC`](./lifespan#var-lifespan-func): 生命周期函数
"""
return self.lifespan.on_before_start(func)
@ -164,81 +167,128 @@ class LiteyukiBot:
"""
注册启动后的函数
Args:
func:
func ([`LIFESPAN_FUNC`](./lifespan#var-lifespan-func)): 生命周期函数
Returns:
[`LIFESPAN_FUNC`](./lifespan#var-lifespan-func): 生命周期函数
"""
return self.lifespan.on_after_start(func)
def on_before_shutdown(self, func: LIFESPAN_FUNC):
"""
注册停止前的函数,为子进程停止时调用
Args:
func:
Returns:
"""
return self.lifespan.on_before_shutdown(func)
def on_after_shutdown(self, func: LIFESPAN_FUNC):
"""
注册停止后的函数:未实现
Args:
func:
func ([`LIFESPAN_FUNC`](./lifespan#var-lifespan-func)): 生命周期函数
Returns:
[`LIFESPAN_FUNC`](./lifespan#var-lifespan-func): 生命周期函数
"""
return self.lifespan.on_after_shutdown(func)
def on_before_restart(self, func: LIFESPAN_FUNC):
def on_before_process_shutdown(self, func: PROCESS_LIFESPAN_FUNC):
"""
注册重启前的函数,为子进程重启时调用
注册进程停止前的函数,为子进程停止时调用
Args:
func:
func ([`PROCESS_LIFESPAN_FUNC`](./lifespan#var-process-lifespan-func)): 生命周期函数
Returns:
[`PROCESS_LIFESPAN_FUNC`](./lifespan#var-process-lifespan-func): 生命周期函数
"""
return self.lifespan.on_before_process_shutdown(func)
def on_before_process_restart(
self, func: PROCESS_LIFESPAN_FUNC
) -> PROCESS_LIFESPAN_FUNC:
"""
注册进程重启前的函数,为子进程重启时调用
Args:
func ([`PROCESS_LIFESPAN_FUNC`](./lifespan#var-process-lifespan-func)): 生命周期函数
Returns:
[`PROCESS_LIFESPAN_FUNC`](./lifespan#var-process-lifespan-func): 生命周期函数
"""
return self.lifespan.on_before_restart(func)
return self.lifespan.on_before_process_restart(func)
def on_after_restart(self, func: LIFESPAN_FUNC):
"""
注册重启后的函数:未实现
Args:
func:
func ([`LIFESPAN_FUNC`](./lifespan#var-lifespan-func)): 生命周期函数
Returns:
[`LIFESPAN_FUNC`](./lifespan#var-lifespan-func): 生命周期函数
"""
return self.lifespan.on_after_restart(func)
def on_after_nonebot_init(self, func: LIFESPAN_FUNC):
"""
注册nonebot初始化后的函数
Args:
func:
Returns:
"""
return self.lifespan.on_after_nonebot_init(func)
_BOT_INSTANCE: LiteyukiBot
_BOT_INSTANCE: Optional[LiteyukiBot] = None
def get_bot() -> Optional[LiteyukiBot]:
def get_bot() -> LiteyukiBot:
"""
获取轻雪实例
Returns:
LiteyukiBot: 当前的轻雪实例
[`LiteyukiBot`](#class-liteyukibot): 轻雪实例
"""
if IS_MAIN_PROCESS:
if _BOT_INSTANCE is None:
raise RuntimeError("尹灵温 实例未初始化")
return _BOT_INSTANCE
else:
# 从多进程上下文中获取
pass
raise RuntimeError("无法在子进程中获取机器人实例")
def get_config(key: str, default: Any = None) -> Any:
"""
获取配置
Args:
key ([`str`](https%3A//docs.python.org/3/library/stdtypes.html#str)): 配置键
default ([`Any`](https%3A//docs.python.org/3/library/functions.html#any), optional): 默认值. Defaults to None.
Returns:
[`Any`](https%3A//docs.python.org/3/library/functions.html#any): 配置值
"""
return get_bot().config.get(key, default)
def get_config_with_compat(
key: str, compat_keys: tuple[str], default: Any = None
) -> Any:
"""
获取配置,兼容旧版本
Args:
key ([`str`](https%3A//docs.python.org/3/library/stdtypes.html#str)): 配置键
compat_keys ([`tuple`](https%3A//docs.python.org/3/library/stdtypes.html#tuple)[`str`](https%3A//docs.python.org/3/library/stdtypes.html#str)): 兼容键
default ([`Any`](https%3A//docs.python.org/3/library/functions.html#any), optional): 默认值. Defaults to None.
Returns:
[`Any`](https%3A//docs.python.org/3/library/functions.html#any): 配置值
"""
if key in get_bot().config:
return get_bot().config[key]
for compat_key in compat_keys:
if compat_key in get_bot().config:
logger.warning(f'配置键 "{compat_key}" 即将被 "{key}" 取代,请及时更新')
return get_bot().config[compat_key]
return default
def print_logo():
"""@litedoc-hide"""
print(
"\033[34m"
+ r"""
▅▅▅▅▅▅▅▅▅▅▅▅▅▅██ ▅▅▅▅▅▅▅▅▅▅▅▅▅▅██ ██ ▅▅▅▅▅▅▅▅▅▅█™
▛ ██ ██ ▛ ██ ███ ██ ██
██ ██ ███████████████ ██ ████████▅ ██
███████████████ ██ ███ ██ ██
██ ██ ▅██████████████▛ ██ ████████████
██ ██ ███ ███
████████████████ ██▅ ███ ██ ▅▅▅▅▅▅▅▅▅▅▅██
███ █ ▜███████ ██ ███ ██ ██ ██ ██
███ ███ █████▛ ██ ██ ██ ██ ██
███ ██ ███ █ ██ ██ ██ ██ ██
███ █████ ██████ ███ ██████████████
商业标记 版权所有 © 2024 金羿Eilles
机器软件 版权所有 © 2020-2024 神羽SnowyKami & 金羿Eilles\\
会同 LiteyukiStudio & 睿乐组织
保留所有权利
"""
+ "\033[0m"
)

View File

@ -8,14 +8,19 @@ Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@File : lifespan.py
@Software: PyCharm
"""
from typing import Any, Awaitable, Callable, TypeAlias
import asyncio
from typing import Any, Awaitable, Callable, TypeAlias, Sequence
from liteyuki.log import logger
from liteyuki.utils import is_coroutine_callable
from liteyuki.utils import is_coroutine_callable, async_wrapper
SYNC_LIFESPAN_FUNC: TypeAlias = Callable[[], Any]
ASYNC_LIFESPAN_FUNC: TypeAlias = Callable[[], Awaitable[Any]]
LIFESPAN_FUNC: TypeAlias = SYNC_LIFESPAN_FUNC | ASYNC_LIFESPAN_FUNC
SYNC_LIFESPAN_FUNC: TypeAlias = Callable[[], Any] # 同步生命周期函数
ASYNC_LIFESPAN_FUNC: TypeAlias = Callable[[], Awaitable[Any]] # 异步生命周期函数
LIFESPAN_FUNC: TypeAlias = SYNC_LIFESPAN_FUNC | ASYNC_LIFESPAN_FUNC # 生命周期函数
SYNC_PROCESS_LIFESPAN_FUNC: TypeAlias = Callable[[str], Any] # 同步进程生命周期函数
ASYNC_PROCESS_LIFESPAN_FUNC: TypeAlias = Callable[[str], Awaitable[Any]] # 异步进程生命周期函数
PROCESS_LIFESPAN_FUNC: TypeAlias = SYNC_PROCESS_LIFESPAN_FUNC | ASYNC_PROCESS_LIFESPAN_FUNC # 进程函数
class Lifespan:
@ -23,41 +28,35 @@ class Lifespan:
"""
轻雪生命周期管理,启动、停止、重启
"""
self.life_flag: int = 0 # 0: 启动前1: 启动后2: 停止前3: 停止后
self.life_flag: int = 0
self._before_start_funcs: list[LIFESPAN_FUNC] = []
self._after_start_funcs: list[LIFESPAN_FUNC] = []
self._before_shutdown_funcs: list[LIFESPAN_FUNC] = []
self._before_process_shutdown_funcs: list[PROCESS_LIFESPAN_FUNC] = []
self._after_shutdown_funcs: list[LIFESPAN_FUNC] = []
self._before_restart_funcs: list[LIFESPAN_FUNC] = []
self._before_process_restart_funcs: list[PROCESS_LIFESPAN_FUNC] = []
self._after_restart_funcs: list[LIFESPAN_FUNC] = []
self._after_nonebot_init_funcs: list[LIFESPAN_FUNC] = []
@staticmethod
async def _run_funcs(funcs: list[LIFESPAN_FUNC]) -> None:
async def run_funcs(funcs: Sequence[LIFESPAN_FUNC | PROCESS_LIFESPAN_FUNC], *args, **kwargs) -> None:
"""
运行函数
并发运行异步函数
Args:
funcs:
funcs ([`Sequence`](https%3A//docs.python.org/3/library/typing.html#typing.Sequence)[[`ASYNC_LIFESPAN_FUNC`](#var-lifespan-func) | [`PROCESS_LIFESPAN_FUNC`](#var-process-lifespan-func)]): 函数列表
Returns:
"""
for func in funcs:
if is_coroutine_callable(func):
await func()
else:
func()
tasks = [func(*args, **kwargs) if is_coroutine_callable(func) else async_wrapper(func)(*args, **kwargs) for func in funcs]
await asyncio.gather(*tasks)
def on_before_start(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
"""
注册启动时的函数
Args:
func:
func ([`LIFESPAN_FUNC`](#var-lifespan-func)): 生命周期函数
Returns:
LIFESPAN_FUNC:
[`LIFESPAN_FUNC`](#var-lifespan-func): 生命周期函数
"""
self._before_start_funcs.append(func)
return func
@ -66,124 +65,95 @@ class Lifespan:
"""
注册启动时的函数
Args:
func:
func ([`LIFESPAN_FUNC`](#var-lifespan-func)): 生命周期函数
Returns:
LIFESPAN_FUNC:
[`LIFESPAN_FUNC`](#var-lifespan-func): 生命周期函数
"""
self._after_start_funcs.append(func)
return func
def on_before_shutdown(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
def on_before_process_shutdown(self, func: PROCESS_LIFESPAN_FUNC) -> PROCESS_LIFESPAN_FUNC:
"""
注册停止前的函数
注册进程停止前的函数
Args:
func:
func ([`PROCESS_LIFESPAN_FUNC`](#var-process-lifespan-func)): 进程生命周期函数
Returns:
LIFESPAN_FUNC:
[`PROCESS_LIFESPAN_FUNC`](#var-process-lifespan-func): 进程生命周期函数
"""
self._before_shutdown_funcs.append(func)
self._before_process_shutdown_funcs.append(func)
return func
def on_after_shutdown(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
"""
注册停止后的函数
Args:
func:
func ([`LIFESPAN_FUNC`](#var-lifespan-func)): 生命周期函数
Returns:
LIFESPAN_FUNC:
[`LIFESPAN_FUNC`](#var-lifespan-func): 生命周期函数
"""
self._after_shutdown_funcs.append(func)
return func
def on_before_restart(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
def on_before_process_restart(self, func: PROCESS_LIFESPAN_FUNC) -> PROCESS_LIFESPAN_FUNC:
"""
注册重启的函数
注册进程重启的函数
Args:
func:
func ([`PROCESS_LIFESPAN_FUNC`](#var-process-lifespan-func)): 进程生命周期函数
Returns:
LIFESPAN_FUNC:
[`PROCESS_LIFESPAN_FUNC`](#var-process-lifespan-func): 进程生命周期函数
"""
self._before_restart_funcs.append(func)
self._before_process_restart_funcs.append(func)
return func
def on_after_restart(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
"""
注册重启后的函数
Args:
func:
func ([`LIFESPAN_FUNC`](#var-lifespan-func)): 生命周期函数
Returns:
LIFESPAN_FUNC:
[`LIFESPAN_FUNC`](#var-lifespan-func): 生命周期函数
"""
self._after_restart_funcs.append(func)
return func
def on_after_nonebot_init(self, func):
"""
注册 NoneBot 初始化后的函数
Args:
func:
Returns:
"""
self._after_nonebot_init_funcs.append(func)
return func
async def before_start(self) -> None:
"""
启动前
Returns:
启动前钩子
"""
logger.debug("正在运行 before_start 函数")
await self._run_funcs(self._before_start_funcs)
logger.debug("运行 before_start 函数")
await self.run_funcs(self._before_start_funcs)
async def after_start(self) -> None:
"""
启动后
Returns:
启动后钩子
"""
logger.debug("正在运行 after_start 函数")
await self._run_funcs(self._after_start_funcs)
logger.debug("运行 after_start 函数")
await self.run_funcs(self._after_start_funcs)
async def before_shutdown(self) -> None:
async def before_process_shutdown(self, *args, **kwargs) -> None:
"""
停止前
Returns:
停止前钩子
"""
logger.debug("正在运行 before_shutdown 函数")
await self._run_funcs(self._before_shutdown_funcs)
logger.debug("运行 before_shutdown 函数")
await self.run_funcs(self._before_process_shutdown_funcs, *args, **kwargs)
async def after_shutdown(self) -> None:
"""
停止后
Returns:
停止后钩子 未实现
"""
logger.debug("正在运行 after_shutdown 函数")
await self._run_funcs(self._after_shutdown_funcs)
logger.debug("运行 after_shutdown 函数")
await self.run_funcs(self._after_shutdown_funcs)
async def before_restart(self) -> None:
async def before_process_restart(self, *args, **kwargs) -> None:
"""
重启前
Returns:
重启前钩子
"""
logger.debug("正在运行 before_restart 函数")
await self._run_funcs(self._before_restart_funcs)
logger.debug("运行 before_restart 函数")
await self.run_funcs(self._before_process_restart_funcs, *args, **kwargs)
async def after_restart(self) -> None:
"""
重启后
Returns:
重启后钩子 未实现
"""
logger.debug("正在运行 after_restart 函数")
await self._run_funcs(self._after_restart_funcs)
async def after_nonebot_init(self) -> None:
"""
NoneBot 初始化后
Returns:
"""
logger.debug("正在运行 after_nonebot_init 之函数")
await self._run_funcs(self._after_nonebot_init_funcs)
logger.debug("运行 after_restart 函数")
await self.run_funcs(self._after_restart_funcs)