新增observer类和开发调试器

This commit is contained in:
snowy 2024-08-12 04:45:59 +08:00
parent 83325e63ea
commit c9157f0e2c
20 changed files with 222 additions and 214 deletions

View File

@ -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 ENV TZ Asia/Shanghai

View File

@ -1,7 +1,6 @@
nonebot: nonebot:
host: 127.0.0.1 host: 127.0.0.1
port: 20216 port: 20216
superusers: ["1234"]
command_start: ["", "/"] command_start: ["", "/"]
nickname: [ "liteyuki-dev" ] nickname: [ "liteyuki-dev" ]
default_language: zh default_language: zh

9
docs/deployment/cfg.txt Normal file
View File

@ -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 # 开发者模式,开启后将会启动看门狗

View File

@ -25,14 +25,16 @@ __all__ = [
class LiteyukiBot: class LiteyukiBot:
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
print_logo()
global _BOT_INSTANCE global _BOT_INSTANCE
_BOT_INSTANCE = self # 引用 _BOT_INSTANCE = self # 引用
self.lifespan = Lifespan()
self.config: dict[str, Any] = kwargs self.config: dict[str, Any] = kwargs
self.init(**self.config) # 初始化 self.init(**self.config) # 初始化
logger.info("Liteyuki is initializing...")
self.lifespan = Lifespan()
self.process_manager: ProcessManager = ProcessManager(bot=self) self.process_manager: ProcessManager = ProcessManager(bot=self)
self.loop = asyncio.new_event_loop() self.loop = asyncio.new_event_loop()
@ -41,19 +43,7 @@ class LiteyukiBot:
self.stop_event = threading.Event() self.stop_event = threading.Event()
self.call_restart_count = 0 self.call_restart_count = 0
print("\033[34m" + r"""
__ ______ ________ ________ __ __ __ __ __ __ ______
/ | / |/ |/ |/ \ / |/ | / |/ | / |/ |
$$ | $$$$$$/ $$$$$$$$/ $$$$$$$$/ $$ \ /$$/ $$ | $$ |$$ | /$$/ $$$$$$/
$$ | $$ | $$ | $$ |__ $$ \/$$/ $$ | $$ |$$ |/$$/ $$ |
$$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |$$ $$< $$ |
$$ | $$ | $$ | $$$$$/ $$$$/ $$ | $$ |$$$$$ \ $$ |
$$ |_____ _$$ |_ $$ | $$ |_____ $$ | $$ \__$$ |$$ |$$ \ _$$ |_
$$ |/ $$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |/ $$ |
$$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/
""" + "\033[0m")
load_plugins("liteyuki/plugins") # 加载轻雪插件 load_plugins("liteyuki/plugins") # 加载轻雪插件
logger.info("Liteyuki is initializing...")
def run(self): def run(self):
""" """
@ -75,7 +65,6 @@ $$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/
Returns: Returns:
""" """
if self.call_restart_count < 1: if self.call_restart_count < 1:
executable = sys.executable executable = sys.executable
args = sys.argv args = sys.argv
@ -103,16 +92,10 @@ $$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/
Returns: 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()) # 重启前钩子 if name is not None:
self.loop.create_task(self.lifespan.before_shutdown()) # 停止前钩子
# if name:
# self.process_manager.terminate(name)
# else:
# self.process_manager.terminate_all()
if name:
chan_active = get_channel(f"{name}-active") chan_active = get_channel(f"{name}-active")
chan_active.send(1) chan_active.send(1)
else: else:
@ -158,17 +141,6 @@ $$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/
""" """
return self.lifespan.on_after_start(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): def on_after_shutdown(self, func: LIFESPAN_FUNC):
""" """
注册停止后的函数未实现 注册停止后的函数未实现
@ -180,9 +152,20 @@ $$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/
""" """
return self.lifespan.on_after_shutdown(func) 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: Args:
func: 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): def on_after_restart(self, func: LIFESPAN_FUNC):
""" """
@ -228,13 +211,14 @@ def get_bot() -> Optional[LiteyukiBot]:
LiteyukiBot: 当前的轻雪实例 LiteyukiBot: 当前的轻雪实例
""" """
if IS_MAIN_PROCESS: if IS_MAIN_PROCESS:
if _BOT_INSTANCE is None:
raise RuntimeError("Liteyuki instance not initialized.")
return _BOT_INSTANCE return _BOT_INSTANCE
else: else:
# 从多进程上下文中获取 raise RuntimeError("Can't get bot instance in sub process.")
pass
def get_config(key: str, default: Any = None) -> Any: def get_config(key: str = None, default: Any = None) -> Any:
""" """
获取配置 获取配置
Args: Args:
@ -244,7 +228,9 @@ def get_config(key: str, default: Any = None) -> Any:
Returns: Returns:
Any: 配置值 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: 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: Returns:
Any: 配置值 Any: 配置值
""" """
if key in _BOT_INSTANCE.config: if key in get_bot().config:
return _BOT_INSTANCE.config[key] return get_bot().config[key]
for compat_key in compat_keys: 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.") 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 return default
def print_logo():
print("\033[34m" + r"""
__ ______ ________ ________ __ __ __ __ __ __ ______
/ | / |/ |/ |/ \ / |/ | / |/ | / |/ |
$$ | $$$$$$/ $$$$$$$$/ $$$$$$$$/ $$ \ /$$/ $$ | $$ |$$ | /$$/ $$$$$$/
$$ | $$ | $$ | $$ |__ $$ \/$$/ $$ | $$ |$$ |/$$/ $$ |
$$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |$$ $$< $$ |
$$ | $$ | $$ | $$$$$/ $$$$/ $$ | $$ |$$$$$ \ $$ |
$$ |_____ _$$ |_ $$ | $$ |_____ $$ | $$ \__$$ |$$ |$$ \ _$$ |_
$$ |/ $$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |/ $$ |
$$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/
""" + "\033[0m")

View File

@ -29,10 +29,10 @@ class Lifespan:
self._before_start_funcs: list[LIFESPAN_FUNC] = [] self._before_start_funcs: list[LIFESPAN_FUNC] = []
self._after_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._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_restart_funcs: list[LIFESPAN_FUNC] = []
self._after_nonebot_init_funcs: list[LIFESPAN_FUNC] = [] self._after_nonebot_init_funcs: list[LIFESPAN_FUNC] = []
@ -73,7 +73,7 @@ class Lifespan:
self._after_start_funcs.append(func) self._after_start_funcs.append(func)
return 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: Args:
@ -81,7 +81,7 @@ class Lifespan:
Returns: Returns:
LIFESPAN_FUNC: LIFESPAN_FUNC:
""" """
self._before_shutdown_funcs.append(func) self._before_process_shutdown_funcs.append(func)
return func return func
def on_after_shutdown(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC: def on_after_shutdown(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
@ -97,7 +97,7 @@ class Lifespan:
self._after_shutdown_funcs.append(func) self._after_shutdown_funcs.append(func)
return 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: Args:
@ -105,7 +105,7 @@ class Lifespan:
Returns: Returns:
LIFESPAN_FUNC: LIFESPAN_FUNC:
""" """
self._before_restart_funcs.append(func) self._before_process_restart_funcs.append(func)
return func return func
def on_after_restart(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC: def on_after_restart(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
@ -147,13 +147,13 @@ class Lifespan:
logger.debug("Running after_start functions") logger.debug("Running after_start functions")
await self._run_funcs(self._after_start_funcs) await self._run_funcs(self._after_start_funcs)
async def before_shutdown(self) -> None: async def before_process_shutdown(self) -> None:
""" """
停止前 停止前
Returns: Returns:
""" """
logger.debug("Running before_shutdown functions") 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: async def after_shutdown(self) -> None:
""" """
@ -163,13 +163,13 @@ class Lifespan:
logger.debug("Running after_shutdown functions") logger.debug("Running after_shutdown functions")
await self._run_funcs(self._after_shutdown_funcs) await self._run_funcs(self._after_shutdown_funcs)
async def before_restart(self) -> None: async def before_process_restart(self) -> None:
""" """
重启前 重启前
Returns: Returns:
""" """
logger.debug("Running before_restart functions") 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: async def after_restart(self) -> None:
""" """

View File

@ -53,7 +53,6 @@ class ProcessManager:
should_exit = False should_exit = False
while not should_exit: while not should_exit:
chan_active = get_channel(f"{name}-active") 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], process = Process(target=self.targets[name][0], args=self.targets[name][1],
kwargs=self.targets[name][2]) kwargs=self.targets[name][2])
self.processes[name] = process self.processes[name] = process
@ -62,15 +61,19 @@ class ProcessManager:
# 0退出 1重启 # 0退出 1重启
data = chan_active.receive() data = chan_active.receive()
if data == 1: if data == 1:
logger.info(f"Restarting process {name}") # 重启
asyncio.run(self.bot.lifespan.before_shutdown()) if self.is_process_alive(name):
asyncio.run(self.bot.lifespan.before_restart()) logger.info(f"Restarting process {name}")
self.terminate(name) asyncio.run(self.bot.lifespan.before_process_shutdown())
break 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: elif data == 0:
logger.info(f"Stopping process {name}") logger.info(f"Stopping process {name}")
asyncio.run(self.bot.lifespan.before_shutdown()) asyncio.run(self.bot.lifespan.before_process_shutdown())
should_exit = True should_exit = True
self.terminate(name) self.terminate(name)
else: else:
@ -129,3 +132,17 @@ class ProcessManager:
def terminate_all(self): def terminate_all(self):
for name in self.targets: for name in self.targets:
self.terminate(name) 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()

View File

@ -1,5 +1,92 @@
# -*- coding: utf-8 -*-
""" """
此模块用于注册观察者函数使用watchdog监控文件变化并重启bot
启用该模块需要在配置文件中设置`dev_mode`为True
"""
import functools
import time
from typing import Callable, TypeAlias
""" from watchdog.events import FileSystemEvent, FileSystemEventHandler
import watchdog 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

View File

@ -9,22 +9,8 @@ Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Software: PyCharm @Software: PyCharm
""" """
import sys 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日志格式
debug_format: str = ( debug_format: str = (
@ -50,35 +36,26 @@ def get_format(level: str) -> str:
return default_format return default_format
logger = loguru.logger.bind()
def init_log(config: dict): def init_log(config: dict):
""" """
在语言加载完成后执行 在语言加载完成后执行
Returns: Returns:
""" """
global logger
logger.remove() logger.remove()
logger.add( logger.add(
sys.stdout, sys.stdout,
level=0, level=0,
diagnose=False, diagnose=False,
filter=default_filter,
format=get_format(config.get("log_level", "INFO")), format=get_format(config.get("log_level", "INFO")),
) )
show_icon = config.get("log_icon", True) show_icon = config.get("log_icon", True)
logger.level("DEBUG", color="<blue>", icon=f"{'🐛' if show_icon else ''}DEBUG")
logger.level("INFO", color="<normal>", icon=f"{'' if show_icon else ''}INFO")
logger.level("SUCCESS", color="<green>", icon=f"{'' if show_icon else ''}SUCCESS")
logger.level("WARNING", color="<yellow>", icon=f"{'⚠️' if show_icon else ''}WARNING")
logger.level("ERROR", color="<red>", icon=f"{'' if show_icon else ''}ERROR")
# debug = lang.get("log.debug", default="==DEBUG")
# info = lang.get("log.info", default="===INFO") init_log(config={})
# 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="<blue>", icon=f"{'🐛' if show_icon else ''}{debug}")
# logger.level("INFO", color="<normal>", icon=f"{'' if show_icon else ''}{info}")
# logger.level("SUCCESS", color="<green>", icon=f"{'✅' if show_icon else ''}{success}")
# logger.level("WARNING", color="<yellow>", icon=f"{'⚠️' if show_icon else ''}{warning}")
# logger.level("ERROR", color="<red>", icon=f"{'⭕' if show_icon else ''}{error}")

View File

@ -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")

View File

@ -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()

View File

@ -15,14 +15,13 @@ from liteyuki.plugin import PluginMetadata
from liteyuki import get_bot from liteyuki import get_bot
from liteyuki.comm import Channel, set_channel from liteyuki.comm import Channel, set_channel
from liteyuki.core import IS_MAIN_PROCESS from liteyuki.core import IS_MAIN_PROCESS
from .nb_utils import adapter_manager, driver_manager from .nb_utils import adapter_manager, driver_manager
__plugin_meta__ = PluginMetadata( __plugin_meta__ = PluginMetadata(
name="NoneBot2启动器", name="NoneBot2启动器",
) )
liteyuki = get_bot()
def nb_run(chan_active: "Channel", chan_passive: "Channel", **kwargs): 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-active", chan_active)
set_channel("nonebot-passive", chan_passive) set_channel("nonebot-passive", chan_passive)
kwargs.update(kwargs.get("nonebot", {})) # nonebot配置优先 kwargs.update(kwargs.get("nonebot", {})) # nonebot配置优先
nonebot.init(**kwargs) nonebot.init(**kwargs)
driver_manager.init(config=kwargs) driver_manager.init(config=kwargs)
@ -50,6 +49,11 @@ def nb_run(chan_active: "Channel", chan_passive: "Channel", **kwargs):
if IS_MAIN_PROCESS: if IS_MAIN_PROCESS:
from .dev_reloader import *
liteyuki = get_bot()
@liteyuki.on_after_start @liteyuki.on_after_start
def start_run_nonebot(): def start_run_nonebot():
liteyuki.process_manager.add_target(name="nonebot", target=nb_run, args=(), kwargs=liteyuki.config) liteyuki.process_manager.add_target(name="nonebot", target=nb_run, args=(), kwargs=liteyuki.config)

View File

@ -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")

View File

@ -5,5 +5,5 @@ from liteyuki import LiteyukiBot
from liteyuki.config import load_config_in_default from liteyuki.config import load_config_in_default
if __name__ == "__main__": if __name__ == "__main__":
bot = LiteyukiBot(**load_config_in_default()) bot = LiteyukiBot(**load_config_in_default(no_waring=True))
bot.run() bot.run()

View File

@ -21,6 +21,7 @@ pytz~=2024.1
PyYAML~=6.0.1 PyYAML~=6.0.1
pillow~=10.0.0 pillow~=10.0.0
starlette~=0.36.3 starlette~=0.36.3
toml~=0.10.2
loguru~=0.7.2 loguru~=0.7.2
importlib_metadata~=7.0.2 importlib_metadata~=7.0.2
requests~=2.31.0 requests~=2.31.0

View File

@ -2,8 +2,6 @@ from nonebot.plugin import PluginMetadata
from .core import * from .core import *
from .loader import * from .loader import *
from .dev import *
__author__ = "snowykami" __author__ = "snowykami"
__plugin_meta__ = PluginMetadata( __plugin_meta__ = PluginMetadata(
name="轻雪核心插件", name="轻雪核心插件",
@ -18,6 +16,5 @@ __plugin_meta__ = PluginMetadata(
from ..utils.base.language import Language, get_default_lang_code from ..utils.base.language import Language, get_default_lang_code
sys_lang = 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"))) nonebot.logger.info(sys_lang.get("main.current_language", LANG=sys_lang.get("language.name")))

View File

@ -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()

View File

@ -16,7 +16,6 @@ load_resources()
init_log() init_log()
driver = get_driver() driver = get_driver()
liteyuki_bot = get_bot()
@driver.on_startup @driver.on_startup

View File

@ -29,13 +29,12 @@ def _():
logger.info("生命周期监控器:准备启动") logger.info("生命周期监控器:准备启动")
@bot.on_before_shutdown @bot.on_before_process_shutdown
def _(): def _():
print(get_channel("main"))
logger.info("生命周期监控器:准备停止") logger.info("生命周期监控器:准备停止")
@bot.on_before_restart @bot.on_before_process_restart
def _(): def _():
logger.info("生命周期监控器:准备重启") logger.info("生命周期监控器:准备重启")

View File

@ -21,4 +21,3 @@ __plugin_meta__ = PluginMetadata(
"default_enable" : True, "default_enable" : True,
} }
) )

View File

@ -2,8 +2,8 @@ import os
from pydantic import Field from pydantic import Field
from .data import Database, LiteModel, Database from .data import Database, LiteModel
print("导入数据库模块")
DATA_PATH = "data/liteyuki" DATA_PATH = "data/liteyuki"
user_db: Database = Database(os.path.join(DATA_PATH, "users.ldb")) user_db: Database = Database(os.path.join(DATA_PATH, "users.ldb"))
group_db: Database = Database(os.path.join(DATA_PATH, "groups.ldb")) group_db: Database = Database(os.path.join(DATA_PATH, "groups.ldb"))