From c9157f0e2c085b56ce05245ea712829362892b01 Mon Sep 17 00:00:00 2001 From: snowy Date: Mon, 12 Aug 2024 04:45:59 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E6=96=B0=E5=A2=9Eobserver?= =?UTF-8?q?=E7=B1=BB=E5=92=8C=E5=BC=80=E5=8F=91=E8=B0=83=E8=AF=95=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 2 +- config/default.yml | 1 - docs/deployment/cfg.txt | 9 ++ liteyuki/bot/__init__.py | 91 +++++++++--------- liteyuki/bot/lifespan.py | 20 ++-- liteyuki/core/manager.py | 31 +++++-- liteyuki/dev/observer.py | 93 ++++++++++++++++++- liteyuki/log.py | 39 ++------ liteyuki/plugins/code_watchdog/__init__.py | 21 ----- liteyuki/plugins/code_watchdog/observer.py | 44 --------- liteyuki/plugins/nonebot_launcher/__init__.py | 10 +- .../plugins/nonebot_launcher/dev_reloader.py | 22 +++++ main.py | 2 +- requirements.txt | 1 + src/liteyuki_main/__init__.py | 3 - src/liteyuki_main/dev.py | 36 ------- src/liteyuki_main/loader.py | 1 - src/liteyuki_plugins/lifespan_monitor.py | 5 +- .../liteyuki_status/__init__.py | 1 - src/utils/base/data_manager.py | 4 +- 20 files changed, 222 insertions(+), 214 deletions(-) create mode 100644 docs/deployment/cfg.txt delete mode 100644 liteyuki/plugins/code_watchdog/__init__.py delete mode 100644 liteyuki/plugins/code_watchdog/observer.py create mode 100644 liteyuki/plugins/nonebot_launcher/dev_reloader.py delete mode 100644 src/liteyuki_main/dev.py diff --git a/Dockerfile b/Dockerfile index 58839fea..fcd1d169 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11-bullseye +FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/python:3.10-slim-bullseye ENV TZ Asia/Shanghai diff --git a/config/default.yml b/config/default.yml index 0709f344..7a291f9e 100644 --- a/config/default.yml +++ b/config/default.yml @@ -1,7 +1,6 @@ nonebot: host: 127.0.0.1 port: 20216 - superusers: ["1234"] command_start: ["", "/"] nickname: [ "liteyuki-dev" ] default_language: zh diff --git a/docs/deployment/cfg.txt b/docs/deployment/cfg.txt new file mode 100644 index 00000000..af5aecd2 --- /dev/null +++ b/docs/deployment/cfg.txt @@ -0,0 +1,9 @@ +# note +开发者选项 +allow_update: true # 是否允许更新 +log_level: "INFO" # 日志等级 +log_icon: true # 是否显示日志等级图标(某些控制台字体不可用) +auto_report: true # 是否自动上报问题给轻雪服务器 +auto_update: true # 是否自动更新轻雪,每天4点检查更新 +safe_mode: false # 安全模式,开启后将不会加载任何第三方插件 +dev_mode: false # 开发者模式,开启后将会启动看门狗 \ No newline at end of file diff --git a/liteyuki/bot/__init__.py b/liteyuki/bot/__init__.py index 63363c92..fd298b79 100644 --- a/liteyuki/bot/__init__.py +++ b/liteyuki/bot/__init__.py @@ -25,14 +25,16 @@ __all__ = [ class LiteyukiBot: def __init__(self, *args, **kwargs): + print_logo() global _BOT_INSTANCE _BOT_INSTANCE = self # 引用 - self.lifespan = Lifespan() - self.config: dict[str, Any] = kwargs self.init(**self.config) # 初始化 + logger.info("Liteyuki is initializing...") + + self.lifespan = Lifespan() self.process_manager: ProcessManager = ProcessManager(bot=self) self.loop = asyncio.new_event_loop() @@ -41,19 +43,7 @@ class LiteyukiBot: self.stop_event = threading.Event() self.call_restart_count = 0 - print("\033[34m" + r""" - __ ______ ________ ________ __ __ __ __ __ __ ______ -/ | / |/ |/ |/ \ / |/ | / |/ | / |/ | -$$ | $$$$$$/ $$$$$$$$/ $$$$$$$$/ $$ \ /$$/ $$ | $$ |$$ | /$$/ $$$$$$/ -$$ | $$ | $$ | $$ |__ $$ \/$$/ $$ | $$ |$$ |/$$/ $$ | -$$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |$$ $$< $$ | -$$ | $$ | $$ | $$$$$/ $$$$/ $$ | $$ |$$$$$ \ $$ | -$$ |_____ _$$ |_ $$ | $$ |_____ $$ | $$ \__$$ |$$ |$$ \ _$$ |_ -$$ |/ $$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |/ $$ | -$$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/ - """ + "\033[0m") load_plugins("liteyuki/plugins") # 加载轻雪插件 - logger.info("Liteyuki is initializing...") def run(self): """ @@ -75,7 +65,6 @@ $$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/ Returns: """ - if self.call_restart_count < 1: executable = sys.executable args = sys.argv @@ -103,16 +92,10 @@ $$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/ Returns: """ - logger.info(f"Stopping process {name}...") + self.loop.create_task(self.lifespan.before_process_shutdown()) # 重启前钩子 + self.loop.create_task(self.lifespan.before_process_shutdown()) # 停止前钩子 - self.loop.create_task(self.lifespan.before_shutdown()) # 重启前钩子 - self.loop.create_task(self.lifespan.before_shutdown()) # 停止前钩子 - - # if name: - # self.process_manager.terminate(name) - # else: - # self.process_manager.terminate_all() - if name: + if name is not None: chan_active = get_channel(f"{name}-active") chan_active.send(1) else: @@ -158,17 +141,6 @@ $$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/ """ 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): """ 注册停止后的函数:未实现 @@ -180,9 +152,20 @@ $$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/ """ return self.lifespan.on_after_shutdown(func) - def on_before_restart(self, func: LIFESPAN_FUNC): + def on_before_process_shutdown(self, func: LIFESPAN_FUNC): """ - 注册重启前的函数,为子进程重启时调用 + 注册进程停止前的函数,为子进程停止时调用 + Args: + func: + + Returns: + + """ + return self.lifespan.on_before_process_shutdown(func) + + def on_before_process_restart(self, func: LIFESPAN_FUNC): + """ + 注册进程重启前的函数,为子进程重启时调用 Args: func: @@ -190,7 +173,7 @@ $$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/ """ - return self.lifespan.on_before_restart(func) + return self.lifespan.on_before_process_restart(func) def on_after_restart(self, func: LIFESPAN_FUNC): """ @@ -228,13 +211,14 @@ def get_bot() -> Optional[LiteyukiBot]: LiteyukiBot: 当前的轻雪实例 """ if IS_MAIN_PROCESS: + if _BOT_INSTANCE is None: + raise RuntimeError("Liteyuki instance not initialized.") return _BOT_INSTANCE else: - # 从多进程上下文中获取 - pass + raise RuntimeError("Can't get bot instance in sub process.") -def get_config(key: str, default: Any = None) -> Any: +def get_config(key: str = None, default: Any = None) -> Any: """ 获取配置 Args: @@ -244,7 +228,9 @@ def get_config(key: str, default: Any = None) -> Any: Returns: Any: 配置值 """ - return _BOT_INSTANCE.config.get(key, default) + if key is None: + return get_bot().config + return get_bot().config.get(key, default) def get_config_with_compat(key: str, compat_keys: tuple[str], default: Any = None) -> Any: @@ -258,11 +244,24 @@ def get_config_with_compat(key: str, compat_keys: tuple[str], default: Any = Non Returns: Any: 配置值 """ - if key in _BOT_INSTANCE.config: - return _BOT_INSTANCE.config[key] + if key in get_bot().config: + return get_bot().config[key] for compat_key in compat_keys: - if compat_key in _BOT_INSTANCE.config: + if compat_key in get_bot().config: logger.warning(f"Config key {compat_key} will be deprecated, use {key} instead.") - return _BOT_INSTANCE.config[compat_key] + return get_bot().config[compat_key] return default + +def print_logo(): + print("\033[34m" + r""" + __ ______ ________ ________ __ __ __ __ __ __ ______ + / | / |/ |/ |/ \ / |/ | / |/ | / |/ | + $$ | $$$$$$/ $$$$$$$$/ $$$$$$$$/ $$ \ /$$/ $$ | $$ |$$ | /$$/ $$$$$$/ + $$ | $$ | $$ | $$ |__ $$ \/$$/ $$ | $$ |$$ |/$$/ $$ | + $$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |$$ $$< $$ | + $$ | $$ | $$ | $$$$$/ $$$$/ $$ | $$ |$$$$$ \ $$ | + $$ |_____ _$$ |_ $$ | $$ |_____ $$ | $$ \__$$ |$$ |$$ \ _$$ |_ + $$ |/ $$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |/ $$ | + $$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/ + """ + "\033[0m") diff --git a/liteyuki/bot/lifespan.py b/liteyuki/bot/lifespan.py index 75327bf0..c0eda044 100644 --- a/liteyuki/bot/lifespan.py +++ b/liteyuki/bot/lifespan.py @@ -29,10 +29,10 @@ class Lifespan: 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[LIFESPAN_FUNC] = [] self._after_shutdown_funcs: list[LIFESPAN_FUNC] = [] - self._before_restart_funcs: list[LIFESPAN_FUNC] = [] + self._before_process_restart_funcs: list[LIFESPAN_FUNC] = [] self._after_restart_funcs: list[LIFESPAN_FUNC] = [] self._after_nonebot_init_funcs: list[LIFESPAN_FUNC] = [] @@ -73,7 +73,7 @@ class Lifespan: 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: LIFESPAN_FUNC) -> LIFESPAN_FUNC: """ 注册停止前的函数 Args: @@ -81,7 +81,7 @@ class Lifespan: Returns: 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: @@ -97,7 +97,7 @@ class Lifespan: 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: LIFESPAN_FUNC) -> LIFESPAN_FUNC: """ 注册重启时的函数 Args: @@ -105,7 +105,7 @@ class Lifespan: Returns: 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: @@ -147,13 +147,13 @@ class Lifespan: logger.debug("Running after_start functions") await self._run_funcs(self._after_start_funcs) - async def before_shutdown(self) -> None: + async def before_process_shutdown(self) -> None: """ 停止前 Returns: """ logger.debug("Running before_shutdown functions") - await self._run_funcs(self._before_shutdown_funcs) + await self._run_funcs(self._before_process_shutdown_funcs) async def after_shutdown(self) -> None: """ @@ -163,13 +163,13 @@ class Lifespan: logger.debug("Running after_shutdown functions") await self._run_funcs(self._after_shutdown_funcs) - async def before_restart(self) -> None: + async def before_process_restart(self) -> None: """ 重启前 Returns: """ logger.debug("Running before_restart functions") - await self._run_funcs(self._before_restart_funcs) + await self._run_funcs(self._before_process_restart_funcs) async def after_restart(self) -> None: """ diff --git a/liteyuki/core/manager.py b/liteyuki/core/manager.py index 9cb368a8..fa10b482 100644 --- a/liteyuki/core/manager.py +++ b/liteyuki/core/manager.py @@ -53,7 +53,6 @@ class ProcessManager: should_exit = False while not should_exit: chan_active = get_channel(f"{name}-active") - chan_passive = get_channel(f"{name}-passive") process = Process(target=self.targets[name][0], args=self.targets[name][1], kwargs=self.targets[name][2]) self.processes[name] = process @@ -62,15 +61,19 @@ class ProcessManager: # 0退出 1重启 data = chan_active.receive() if data == 1: - logger.info(f"Restarting process {name}") - asyncio.run(self.bot.lifespan.before_shutdown()) - asyncio.run(self.bot.lifespan.before_restart()) - self.terminate(name) - break + # 重启 + if self.is_process_alive(name): + logger.info(f"Restarting process {name}") + asyncio.run(self.bot.lifespan.before_process_shutdown()) + asyncio.run(self.bot.lifespan.before_process_restart()) + self.terminate(name) + break + else: + logger.warning(f"Process {name} is not restartable, cannot restart.") elif data == 0: logger.info(f"Stopping process {name}") - asyncio.run(self.bot.lifespan.before_shutdown()) + asyncio.run(self.bot.lifespan.before_process_shutdown()) should_exit = True self.terminate(name) else: @@ -129,3 +132,17 @@ class ProcessManager: def terminate_all(self): for name in self.targets: self.terminate(name) + + def is_process_alive(self, name: str) -> bool: + """ + 检查进程是否存活 + Args: + name: + + Returns: + + """ + if name not in self.targets: + raise logger.warning(f"Process {name} not found.") + process = self.processes[name] + return process.is_alive() diff --git a/liteyuki/dev/observer.py b/liteyuki/dev/observer.py index 8143c7fa..d61f540d 100644 --- a/liteyuki/dev/observer.py +++ b/liteyuki/dev/observer.py @@ -1,5 +1,92 @@ -# -*- coding: utf-8 -*- """ +此模块用于注册观察者函数,使用watchdog监控文件变化并重启bot +启用该模块需要在配置文件中设置`dev_mode`为True +""" +import functools +import time +from typing import Callable, TypeAlias -""" -import watchdog \ No newline at end of file +from watchdog.events import FileSystemEvent, FileSystemEventHandler +from watchdog.observers import Observer + +from liteyuki import get_bot, get_config, logger + +liteyuki_bot = get_bot() + +CALLBACK_FUNC: TypeAlias = Callable[[FileSystemEvent], None] # 位置1为FileSystemEvent +FILTER_FUNC: TypeAlias = Callable[[FileSystemEvent], bool] # 位置1为FileSystemEvent +observer = Observer() + + +def debounce(wait): + """ + 防抖函数 + """ + + def decorator(func): + def wrapper(*args, **kwargs): + nonlocal last_call_time + current_time = time.time() + if (current_time - last_call_time) > wait: + last_call_time = current_time + return func(*args, **kwargs) + + last_call_time = None + return wrapper + + return decorator + + +if get_config("dev_mode", False): + logger.debug("Liteyuki Reload enabled, watching for file changes...") + observer.start() + + +class CodeModifiedHandler(FileSystemEventHandler): + """ + Handler for code file changes + """ + + @debounce(1) + def on_modified(self, event): + raise NotImplementedError("on_modified must be implemented") + + def on_created(self, event): + self.on_modified(event) + + def on_deleted(self, event): + self.on_modified(event) + + def on_moved(self, event): + self.on_modified(event) + + def on_any_event(self, event): + self.on_modified(event) + + +def on_file_system_event(directories: tuple[str], recursive: bool = True, event_filter: FILTER_FUNC = None) -> Callable[[CALLBACK_FUNC], CALLBACK_FUNC]: + """ + 注册文件系统变化监听器 + Args: + directories: 监听目录们 + recursive: 是否递归监听子目录 + event_filter: 事件过滤器, 返回True则执行回调函数 + Returns: + 装饰器,装饰一个函数在接收到数据后执行 + """ + + def decorator(func: CALLBACK_FUNC) -> CALLBACK_FUNC: + def wrapper(event: FileSystemEvent): + + if event_filter is not None and not event_filter(event): + return + func(event) + + code_modified_handler = CodeModifiedHandler() + code_modified_handler.on_modified = wrapper + for directory in directories: + observer.schedule(code_modified_handler, directory, recursive=recursive) + + return func + + return decorator diff --git a/liteyuki/log.py b/liteyuki/log.py index a779a149..2ccd7d0f 100644 --- a/liteyuki/log.py +++ b/liteyuki/log.py @@ -9,22 +9,8 @@ Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved @Software: PyCharm """ import sys -import loguru -from typing import TYPE_CHECKING - -logger = loguru.logger -if TYPE_CHECKING: - # avoid sphinx autodoc resolve annotation failed - # because loguru module do not have `Logger` class actually - from loguru import Record - - -def default_filter(record: "Record"): - """默认的日志过滤器,根据 `config.log_level` 配置改变日志等级。""" - log_level = record["extra"].get("nonebot_log_level", "INFO") - levelno = logger.level(log_level).no if isinstance(log_level, str) else log_level - return record["level"].no >= levelno +from loguru import logger # DEBUG日志格式 debug_format: str = ( @@ -50,35 +36,26 @@ def get_format(level: str) -> str: return default_format -logger = loguru.logger.bind() - - def init_log(config: dict): """ 在语言加载完成后执行 Returns: """ - global logger logger.remove() logger.add( sys.stdout, level=0, diagnose=False, - filter=default_filter, format=get_format(config.get("log_level", "INFO")), ) show_icon = config.get("log_icon", True) + logger.level("DEBUG", color="", icon=f"{'🐛' if show_icon else ''}DEBUG") + logger.level("INFO", color="", icon=f"{'ℹ️' if show_icon else ''}INFO") + logger.level("SUCCESS", color="", icon=f"{'✅' if show_icon else ''}SUCCESS") + logger.level("WARNING", color="", icon=f"{'⚠️' if show_icon else ''}WARNING") + logger.level("ERROR", color="", icon=f"{'⭕' if show_icon else ''}ERROR") - # debug = lang.get("log.debug", default="==DEBUG") - # info = lang.get("log.info", default="===INFO") - # success = lang.get("log.success", default="SUCCESS") - # warning = lang.get("log.warning", default="WARNING") - # error = lang.get("log.error", default="==ERROR") - # - # logger.level("DEBUG", color="", icon=f"{'🐛' if show_icon else ''}{debug}") - # logger.level("INFO", color="", icon=f"{'ℹ️' if show_icon else ''}{info}") - # logger.level("SUCCESS", color="", icon=f"{'✅' if show_icon else ''}{success}") - # logger.level("WARNING", color="", icon=f"{'⚠️' if show_icon else ''}{warning}") - # logger.level("ERROR", color="", icon=f"{'⭕' if show_icon else ''}{error}") + +init_log(config={}) diff --git a/liteyuki/plugins/code_watchdog/__init__.py b/liteyuki/plugins/code_watchdog/__init__.py deleted file mode 100644 index 7500e8ab..00000000 --- a/liteyuki/plugins/code_watchdog/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved - -@Time : 2024/8/11 下午8:50 -@Author : snowykami -@Email : snowykami@outlook.com -@File : __init__.py.py -@Software: PyCharm -""" -from liteyuki.core import IS_MAIN_PROCESS -from liteyuki.plugin import PluginMetadata - -from .observer import * - -__plugin_meta__ = PluginMetadata( - name="代码热重载监视", -) - -if IS_MAIN_PROCESS: - config = get_config("liteyuki.reload") diff --git a/liteyuki/plugins/code_watchdog/observer.py b/liteyuki/plugins/code_watchdog/observer.py deleted file mode 100644 index c081c854..00000000 --- a/liteyuki/plugins/code_watchdog/observer.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved - -@Time : 2024/8/11 下午10:01 -@Author : snowykami -@Email : snowykami@outlook.com -@File : observer.py -@Software: PyCharm -""" -from watchdog.events import FileSystemEventHandler -from watchdog.observers import Observer -from liteyuki import get_config, logger, get_bot - -liteyuki_bot = get_bot() - -if get_config("debug", False): - - src_directories = ( - "src/nonebot_plugins", - "src/utils", - ) - src_excludes_extensions = ( - "pyc", - ) - logger.debug("Liteyuki Reload enabled, watching for file changes...") - - 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} modified, reloading bot...") - liteyuki_bot.restart_process("nonebot") - - code_modified_handler = CodeModifiedHandler() - - observer = Observer() - for directory in src_directories: - observer.schedule(code_modified_handler, directory, recursive=True) - observer.start() \ No newline at end of file diff --git a/liteyuki/plugins/nonebot_launcher/__init__.py b/liteyuki/plugins/nonebot_launcher/__init__.py index ee90b158..3812a5fc 100644 --- a/liteyuki/plugins/nonebot_launcher/__init__.py +++ b/liteyuki/plugins/nonebot_launcher/__init__.py @@ -15,14 +15,13 @@ from liteyuki.plugin import PluginMetadata from liteyuki import get_bot from liteyuki.comm import Channel, set_channel from liteyuki.core import IS_MAIN_PROCESS + from .nb_utils import adapter_manager, driver_manager __plugin_meta__ = PluginMetadata( name="NoneBot2启动器", ) -liteyuki = get_bot() - def nb_run(chan_active: "Channel", chan_passive: "Channel", **kwargs): """ @@ -39,7 +38,7 @@ def nb_run(chan_active: "Channel", chan_passive: "Channel", **kwargs): set_channel("nonebot-active", chan_active) set_channel("nonebot-passive", chan_passive) - kwargs.update(kwargs.get("nonebot", {})) # nonebot配置优先 + kwargs.update(kwargs.get("nonebot", {})) # nonebot配置优先 nonebot.init(**kwargs) driver_manager.init(config=kwargs) @@ -50,6 +49,11 @@ def nb_run(chan_active: "Channel", chan_passive: "Channel", **kwargs): if IS_MAIN_PROCESS: + from .dev_reloader import * + + liteyuki = get_bot() + + @liteyuki.on_after_start def start_run_nonebot(): liteyuki.process_manager.add_target(name="nonebot", target=nb_run, args=(), kwargs=liteyuki.config) diff --git a/liteyuki/plugins/nonebot_launcher/dev_reloader.py b/liteyuki/plugins/nonebot_launcher/dev_reloader.py new file mode 100644 index 00000000..de378ef4 --- /dev/null +++ b/liteyuki/plugins/nonebot_launcher/dev_reloader.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +""" +NoneBot 开发环境重载监视器 +""" +import os.path + +from liteyuki.dev import observer +from liteyuki import get_bot, logger +from watchdog.events import FileSystemEvent + +liteyuki = get_bot() + +exclude_extensions = (".pyc", ".pyo") + + +@observer.on_file_system_event( + directories=("src/nonebot_plugins",), + event_filter=lambda event: not event.src_path.endswith(exclude_extensions) and ("__pycache__" not in event.src_path ) and os.path.isfile(event.src_path) +) +def restart_nonebot_process(event: FileSystemEvent): + logger.debug(f"File {event.src_path} changed, reloading nonebot...") + liteyuki.restart_process("nonebot") \ No newline at end of file diff --git a/main.py b/main.py index a2a83b1f..53b5d35d 100644 --- a/main.py +++ b/main.py @@ -5,5 +5,5 @@ from liteyuki import LiteyukiBot from liteyuki.config import load_config_in_default if __name__ == "__main__": - bot = LiteyukiBot(**load_config_in_default()) + bot = LiteyukiBot(**load_config_in_default(no_waring=True)) bot.run() diff --git a/requirements.txt b/requirements.txt index a75d78b5..357269b4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -21,6 +21,7 @@ pytz~=2024.1 PyYAML~=6.0.1 pillow~=10.0.0 starlette~=0.36.3 +toml~=0.10.2 loguru~=0.7.2 importlib_metadata~=7.0.2 requests~=2.31.0 diff --git a/src/liteyuki_main/__init__.py b/src/liteyuki_main/__init__.py index 8bd623a3..972a3f2b 100644 --- a/src/liteyuki_main/__init__.py +++ b/src/liteyuki_main/__init__.py @@ -2,8 +2,6 @@ from nonebot.plugin import PluginMetadata from .core import * from .loader import * -from .dev import * - __author__ = "snowykami" __plugin_meta__ = PluginMetadata( name="轻雪核心插件", @@ -18,6 +16,5 @@ __plugin_meta__ = PluginMetadata( from ..utils.base.language import Language, get_default_lang_code - sys_lang = Language(get_default_lang_code()) nonebot.logger.info(sys_lang.get("main.current_language", LANG=sys_lang.get("language.name"))) \ No newline at end of file diff --git a/src/liteyuki_main/dev.py b/src/liteyuki_main/dev.py deleted file mode 100644 index e4a24f87..00000000 --- a/src/liteyuki_main/dev.py +++ /dev/null @@ -1,36 +0,0 @@ -import nonebot -from watchdog.observers import Observer -from watchdog.events import FileSystemEventHandler - -from liteyuki.bot import get_bot -from src.utils.base import reload -from src.utils.base.config import get_config -from src.utils.base.resource import load_resources - -if get_config("debug", False): - - liteyuki_bot = get_bot() - - res_directories = ( - "src/resources", - "resources", - - ) - - - class ResourceModifiedHandler(FileSystemEventHandler): - """ - Handler for resource file changes - """ - - def on_modified(self, event): - nonebot.logger.info(f"{event.src_path} modified, reloading resource...") - load_resources() - - - resource_modified_handle = ResourceModifiedHandler() - - observer = Observer() - for directory in res_directories: - observer.schedule(resource_modified_handle, directory, recursive=True) - observer.start() diff --git a/src/liteyuki_main/loader.py b/src/liteyuki_main/loader.py index 40883080..2a533856 100644 --- a/src/liteyuki_main/loader.py +++ b/src/liteyuki_main/loader.py @@ -16,7 +16,6 @@ load_resources() init_log() driver = get_driver() -liteyuki_bot = get_bot() @driver.on_startup diff --git a/src/liteyuki_plugins/lifespan_monitor.py b/src/liteyuki_plugins/lifespan_monitor.py index ca222bc8..a42d4d1d 100644 --- a/src/liteyuki_plugins/lifespan_monitor.py +++ b/src/liteyuki_plugins/lifespan_monitor.py @@ -29,13 +29,12 @@ def _(): logger.info("生命周期监控器:准备启动") -@bot.on_before_shutdown +@bot.on_before_process_shutdown def _(): - print(get_channel("main")) logger.info("生命周期监控器:准备停止") -@bot.on_before_restart +@bot.on_before_process_restart def _(): logger.info("生命周期监控器:准备重启") diff --git a/src/nonebot_plugins/liteyuki_status/__init__.py b/src/nonebot_plugins/liteyuki_status/__init__.py index b1a2588b..137afd66 100644 --- a/src/nonebot_plugins/liteyuki_status/__init__.py +++ b/src/nonebot_plugins/liteyuki_status/__init__.py @@ -21,4 +21,3 @@ __plugin_meta__ = PluginMetadata( "default_enable" : True, } ) - diff --git a/src/utils/base/data_manager.py b/src/utils/base/data_manager.py index 1ec893db..f883d207 100644 --- a/src/utils/base/data_manager.py +++ b/src/utils/base/data_manager.py @@ -2,8 +2,8 @@ import os from pydantic import Field -from .data import Database, LiteModel, Database -print("导入数据库模块") +from .data import Database, LiteModel + DATA_PATH = "data/liteyuki" user_db: Database = Database(os.path.join(DATA_PATH, "users.ldb")) group_db: Database = Database(os.path.join(DATA_PATH, "groups.ldb"))