diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml
index bb680846..c75e4ca7 100644
--- a/.github/workflows/deploy-docs.yml
+++ b/.github/workflows/deploy-docs.yml
@@ -42,7 +42,9 @@ jobs:
- name: 生成API markdown
run: |-
python -m pip install pydantic
- python liteyuki/mkdoc.py
+ python -m docs/litedoc liteyuki -o docs/api -l zh-Hans
+ python -m docs/litedoc liteyuki -o docs/en/api -l en
+
- name: 构建文档
diff --git a/docs/dev/README.md b/docs/dev/README.md
deleted file mode 100644
index 947ed654..00000000
--- a/docs/dev/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: 开发及贡献
-index: false
-icon: laptop-code
-category: 开发
----
-
-
\ No newline at end of file
diff --git a/docs/dev/api/README.md b/docs/dev/api/README.md
deleted file mode 100644
index 181ec73d..00000000
--- a/docs/dev/api/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-title: liteyuki
-index: true
-icon: laptop-code
-category: API
----
-
diff --git a/docs/dev/api/bot/README.md b/docs/dev/api/bot/README.md
deleted file mode 100644
index 9f019444..00000000
--- a/docs/dev/api/bot/README.md
+++ /dev/null
@@ -1,581 +0,0 @@
----
-title: liteyuki.bot
-index: true
-icon: laptop-code
-category: API
----
-
-### ***def*** `get_bot() -> LiteyukiBot`
-
-获取轻雪实例
-
-
-
-Returns:
-
- LiteyukiBot: 当前的轻雪实例
-
-
-源代码
-
-```python
-def get_bot() -> LiteyukiBot:
- """
- 获取轻雪实例
-
- Returns:
- LiteyukiBot: 当前的轻雪实例
- """
- if IS_MAIN_PROCESS:
- if _BOT_INSTANCE is None:
- raise RuntimeError('Liteyuki instance not initialized.')
- return _BOT_INSTANCE
- else:
- raise RuntimeError("Can't get bot instance in sub process.")
-```
-
-
-### ***def*** `get_config(key: str, default: Any) -> Any`
-
-获取配置
-
-Args:
-
- key: 配置键
-
- default: 默认值
-
-
-
-Returns:
-
- Any: 配置值
-
-
-源代码
-
-```python
-def get_config(key: str, default: Any=None) -> Any:
- """
- 获取配置
- Args:
- key: 配置键
- default: 默认值
-
- Returns:
- Any: 配置值
- """
- return get_bot().config.get(key, default)
-```
-
-
-### ***def*** `get_config_with_compat(key: str, compat_keys: tuple[str], default: Any) -> Any`
-
-获取配置,兼容旧版本
-
-Args:
-
- key: 配置键
-
- compat_keys: 兼容键
-
- default: 默认值
-
-
-
-Returns:
-
- Any: 配置值
-
-
-源代码
-
-```python
-def get_config_with_compat(key: str, compat_keys: tuple[str], default: Any=None) -> Any:
- """
- 获取配置,兼容旧版本
- Args:
- key: 配置键
- compat_keys: 兼容键
- default: 默认值
-
- Returns:
- 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'Config key "{compat_key}" will be deprecated, use "{key}" instead.')
- return get_bot().config[compat_key]
- return default
-```
-
-
-### ***def*** `print_logo() -> None`
-
-
-
-
-源代码
-
-```python
-def print_logo():
- print('\x1b[34m' + '\n __ ______ ________ ________ __ __ __ __ __ __ ______ \n / | / |/ |/ |/ \\ / |/ | / |/ | / |/ |\n $$ | $$$$$$/ $$$$$$$$/ $$$$$$$$/ $$ \\ /$$/ $$ | $$ |$$ | /$$/ $$$$$$/ \n $$ | $$ | $$ | $$ |__ $$ \\/$$/ $$ | $$ |$$ |/$$/ $$ | \n $$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |$$ $$< $$ | \n $$ | $$ | $$ | $$$$$/ $$$$/ $$ | $$ |$$$$$ \\ $$ | \n $$ |_____ _$$ |_ $$ | $$ |_____ $$ | $$ \\__$$ |$$ |$$ \\ _$$ |_ \n $$ |/ $$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |/ $$ |\n $$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/ \n ' + '\x1b[0m')
-```
-
-
-### ***class*** `LiteyukiBot`
-
-
-
-### ***def*** `__init__(self) -> None`
-
- 初始化轻雪实例
-
-Args:
-
- *args:
-
- **kwargs: 配置
-
-
-源代码
-
-```python
-def __init__(self, *args, **kwargs) -> None:
- """
- 初始化轻雪实例
- Args:
- *args:
- **kwargs: 配置
-
- """
- '常规操作'
- print_logo()
- global _BOT_INSTANCE
- _BOT_INSTANCE = self
- '配置'
- self.config: dict[str, Any] = kwargs
- '初始化'
- self.init(**self.config)
- logger.info('Liteyuki is initializing...')
- '生命周期管理'
- self.lifespan = Lifespan()
- self.process_manager: ProcessManager = ProcessManager(lifespan=self.lifespan)
- '事件循环'
- self.loop = asyncio.new_event_loop()
- asyncio.set_event_loop(self.loop)
- self.stop_event = threading.Event()
- self.call_restart_count = 0
- '加载插件加载器'
- load_plugin('liteyuki.plugins.plugin_loader')
- '信号处理'
- signal.signal(signal.SIGINT, self._handle_exit)
- signal.signal(signal.SIGTERM, self._handle_exit)
- atexit.register(self.process_manager.terminate_all)
-```
-
-
-### ***def*** `run(self) -> None`
-
- 启动逻辑
-
-
-源代码
-
-```python
-def run(self):
- """
- 启动逻辑
- """
- self.lifespan.before_start()
- self.process_manager.start_all()
- self.lifespan.after_start()
- self.keep_alive()
-```
-
-
-### ***def*** `keep_alive(self) -> None`
-
- 保持轻雪运行
-
-Returns:
-
-
-源代码
-
-```python
-def keep_alive(self):
- """
- 保持轻雪运行
- Returns:
-
- """
- try:
- while not self.stop_event.is_set():
- time.sleep(0.5)
- except KeyboardInterrupt:
- logger.info('Liteyuki is stopping...')
- self.stop()
-```
-
-
-### ***def*** `restart(self, delay: int) -> None`
-
- 重启轻雪本体
-
-Returns:
-
-
-源代码
-
-```python
-def restart(self, delay: int=0):
- """
- 重启轻雪本体
- Returns:
-
- """
- if self.call_restart_count < 1:
- executable = sys.executable
- args = sys.argv
- logger.info('Restarting LiteyukiBot...')
- time.sleep(delay)
- if platform.system() == 'Windows':
- cmd = 'start'
- elif platform.system() == 'Linux':
- cmd = 'nohup'
- elif platform.system() == 'Darwin':
- cmd = 'open'
- else:
- cmd = 'nohup'
- self.process_manager.terminate_all()
- threading.Thread(target=os.system, args=(f"{cmd} {executable} {' '.join(args)}",)).start()
- sys.exit(0)
- self.call_restart_count += 1
-```
-
-
-### ***def*** `restart_process(self, name: Optional[str]) -> None`
-
- 停止轻雪
-
-Args:
-
- name: 进程名称, 默认为None, 所有进程
-
-Returns:
-
-
-源代码
-
-```python
-def restart_process(self, name: Optional[str]=None):
- """
- 停止轻雪
- Args:
- name: 进程名称, 默认为None, 所有进程
- Returns:
- """
- self.lifespan.before_process_shutdown()
- self.lifespan.before_process_shutdown()
- if name is not None:
- chan_active = get_channel(f'{name}-active')
- chan_active.send(1)
- else:
- for process_name in self.process_manager.processes:
- chan_active = get_channel(f'{process_name}-active')
- chan_active.send(1)
-```
-
-
-### ***def*** `init(self) -> None`
-
- 初始化轻雪, 自动调用
-
-Returns:
-
-
-源代码
-
-```python
-def init(self, *args, **kwargs):
- """
- 初始化轻雪, 自动调用
- Returns:
-
- """
- self.init_logger()
-```
-
-
-### ***def*** `init_logger(self) -> None`
-
-
-
-
-源代码
-
-```python
-def init_logger(self):
- init_log(config=self.config)
-```
-
-
-### ***def*** `stop(self) -> None`
-
- 停止轻雪
-
-Returns:
-
-
-源代码
-
-```python
-def stop(self):
- """
- 停止轻雪
- Returns:
-
- """
- self.stop_event.set()
- self.loop.stop()
-```
-
-
-### ***def*** `on_before_start(self, func: LIFESPAN_FUNC) -> None`
-
- 注册启动前的函数
-
-Args:
-
- func:
-
-
-
-Returns:
-
-
-源代码
-
-```python
-def on_before_start(self, func: LIFESPAN_FUNC):
- """
- 注册启动前的函数
- Args:
- func:
-
- Returns:
-
- """
- return self.lifespan.on_before_start(func)
-```
-
-
-### ***def*** `on_after_start(self, func: LIFESPAN_FUNC) -> None`
-
- 注册启动后的函数
-
-Args:
-
- func:
-
-
-
-Returns:
-
-
-源代码
-
-```python
-def on_after_start(self, func: LIFESPAN_FUNC):
- """
- 注册启动后的函数
- Args:
- func:
-
- Returns:
-
- """
- return self.lifespan.on_after_start(func)
-```
-
-
-### ***def*** `on_after_shutdown(self, func: LIFESPAN_FUNC) -> None`
-
- 注册停止后的函数:未实现
-
-Args:
-
- func:
-
-
-
-Returns:
-
-
-源代码
-
-```python
-def on_after_shutdown(self, func: LIFESPAN_FUNC):
- """
- 注册停止后的函数:未实现
- Args:
- func:
-
- Returns:
-
- """
- return self.lifespan.on_after_shutdown(func)
-```
-
-
-### ***def*** `on_before_process_shutdown(self, func: LIFESPAN_FUNC) -> None`
-
- 注册进程停止前的函数,为子进程停止时调用
-
-Args:
-
- func:
-
-
-
-Returns:
-
-
-源代码
-
-```python
-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) -> None`
-
- 注册进程重启前的函数,为子进程重启时调用
-
-Args:
-
- func:
-
-
-
-Returns:
-
-
-源代码
-
-```python
-def on_before_process_restart(self, func: LIFESPAN_FUNC):
- """
- 注册进程重启前的函数,为子进程重启时调用
- Args:
- func:
-
- Returns:
-
- """
- return self.lifespan.on_before_process_restart(func)
-```
-
-
-### ***def*** `on_after_restart(self, func: LIFESPAN_FUNC) -> None`
-
- 注册重启后的函数:未实现
-
-Args:
-
- func:
-
-
-
-Returns:
-
-
-源代码
-
-```python
-def on_after_restart(self, func: LIFESPAN_FUNC):
- """
- 注册重启后的函数:未实现
- Args:
- func:
-
- Returns:
-
- """
- return self.lifespan.on_after_restart(func)
-```
-
-
-### ***def*** `on_after_nonebot_init(self, func: LIFESPAN_FUNC) -> None`
-
- 注册nonebot初始化后的函数
-
-Args:
-
- func:
-
-
-
-Returns:
-
-
-源代码
-
-```python
-def on_after_nonebot_init(self, func: LIFESPAN_FUNC):
- """
- 注册nonebot初始化后的函数
- Args:
- func:
-
- Returns:
-
- """
- return self.lifespan.on_after_nonebot_init(func)
-```
-
-
-### ***var*** `executable = sys.executable`
-
-
-
-### ***var*** `args = sys.argv`
-
-
-
-### ***var*** `chan_active = get_channel(f'{name}-active')`
-
-
-
-### ***var*** `cmd = 'start'`
-
-
-
-### ***var*** `chan_active = get_channel(f'{process_name}-active')`
-
-
-
-### ***var*** `cmd = 'nohup'`
-
-
-
-### ***var*** `cmd = 'open'`
-
-
-
-### ***var*** `cmd = 'nohup'`
-
-
-
diff --git a/docs/dev/api/bot/lifespan.md b/docs/dev/api/bot/lifespan.md
deleted file mode 100644
index 6466bd52..00000000
--- a/docs/dev/api/bot/lifespan.md
+++ /dev/null
@@ -1,450 +0,0 @@
----
-title: liteyuki.bot.lifespan
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***def*** `run_funcs(funcs: list[LIFESPAN_FUNC | PROCESS_LIFESPAN_FUNC]) -> None`
-
-运行函数
-
-Args:
-
- funcs:
-
-Returns:
-
-
-源代码
-
-```python
-@staticmethod
-def run_funcs(funcs: list[LIFESPAN_FUNC | PROCESS_LIFESPAN_FUNC], *args, **kwargs) -> None:
- """
- 运行函数
- Args:
- funcs:
- Returns:
- """
- try:
- loop = asyncio.get_event_loop()
- except RuntimeError:
- loop = asyncio.new_event_loop()
- asyncio.set_event_loop(loop)
- tasks = []
- for func in funcs:
- if is_coroutine_callable(func):
- tasks.append(func(*args, **kwargs))
- else:
- tasks.append(async_wrapper(func)(*args, **kwargs))
- loop.run_until_complete(asyncio.gather(*tasks))
-```
-
-
-### ***class*** `Lifespan`
-
-
-
-### ***def*** `__init__(self) -> None`
-
- 轻雪生命周期管理,启动、停止、重启
-
-
-源代码
-
-```python
-def __init__(self) -> None:
- """
- 轻雪生命周期管理,启动、停止、重启
- """
- self.life_flag: int = 0
- self._before_start_funcs: list[LIFESPAN_FUNC] = []
- self._after_start_funcs: list[LIFESPAN_FUNC] = []
- self._before_process_shutdown_funcs: list[LIFESPAN_FUNC] = []
- self._after_shutdown_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] = []
-```
-
-
-### ***@staticmethod***
-### ***def*** `run_funcs(funcs: list[LIFESPAN_FUNC | PROCESS_LIFESPAN_FUNC]) -> None`
-
- 运行函数
-
-Args:
-
- funcs:
-
-Returns:
-
-
-源代码
-
-```python
-@staticmethod
-def run_funcs(funcs: list[LIFESPAN_FUNC | PROCESS_LIFESPAN_FUNC], *args, **kwargs) -> None:
- """
- 运行函数
- Args:
- funcs:
- Returns:
- """
- try:
- loop = asyncio.get_event_loop()
- except RuntimeError:
- loop = asyncio.new_event_loop()
- asyncio.set_event_loop(loop)
- tasks = []
- for func in funcs:
- if is_coroutine_callable(func):
- tasks.append(func(*args, **kwargs))
- else:
- tasks.append(async_wrapper(func)(*args, **kwargs))
- loop.run_until_complete(asyncio.gather(*tasks))
-```
-
-
-### ***def*** `on_before_start(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC`
-
- 注册启动时的函数
-
-Args:
-
- func:
-
-Returns:
-
- LIFESPAN_FUNC:
-
-
-源代码
-
-```python
-def on_before_start(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
- """
- 注册启动时的函数
- Args:
- func:
- Returns:
- LIFESPAN_FUNC:
- """
- self._before_start_funcs.append(func)
- return func
-```
-
-
-### ***def*** `on_after_start(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC`
-
- 注册启动时的函数
-
-Args:
-
- func:
-
-Returns:
-
- LIFESPAN_FUNC:
-
-
-源代码
-
-```python
-def on_after_start(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
- """
- 注册启动时的函数
- Args:
- func:
- Returns:
- LIFESPAN_FUNC:
- """
- self._after_start_funcs.append(func)
- return func
-```
-
-
-### ***def*** `on_before_process_shutdown(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC`
-
- 注册停止前的函数
-
-Args:
-
- func:
-
-Returns:
-
- LIFESPAN_FUNC:
-
-
-源代码
-
-```python
-def on_before_process_shutdown(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
- """
- 注册停止前的函数
- Args:
- func:
- Returns:
- LIFESPAN_FUNC:
- """
- self._before_process_shutdown_funcs.append(func)
- return func
-```
-
-
-### ***def*** `on_after_shutdown(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC`
-
- 注册停止后的函数
-
-Args:
-
- func:
-
-
-
-Returns:
-
- LIFESPAN_FUNC:
-
-
-源代码
-
-```python
-def on_after_shutdown(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
- """
- 注册停止后的函数
- Args:
- func:
-
- Returns:
- LIFESPAN_FUNC:
-
- """
- self._after_shutdown_funcs.append(func)
- return func
-```
-
-
-### ***def*** `on_before_process_restart(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC`
-
- 注册重启时的函数
-
-Args:
-
- func:
-
-Returns:
-
- LIFESPAN_FUNC:
-
-
-源代码
-
-```python
-def on_before_process_restart(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
- """
- 注册重启时的函数
- Args:
- func:
- Returns:
- LIFESPAN_FUNC:
- """
- self._before_process_restart_funcs.append(func)
- return func
-```
-
-
-### ***def*** `on_after_restart(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC`
-
- 注册重启后的函数
-
-Args:
-
- func:
-
-Returns:
-
- LIFESPAN_FUNC:
-
-
-源代码
-
-```python
-def on_after_restart(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
- """
- 注册重启后的函数
- Args:
- func:
- Returns:
- LIFESPAN_FUNC:
- """
- self._after_restart_funcs.append(func)
- return func
-```
-
-
-### ***def*** `on_after_nonebot_init(self, func: Any) -> None`
-
- 注册 NoneBot 初始化后的函数
-
-Args:
-
- func:
-
-
-
-Returns:
-
-
-源代码
-
-```python
-def on_after_nonebot_init(self, func):
- """
- 注册 NoneBot 初始化后的函数
- Args:
- func:
-
- Returns:
-
- """
- self._after_nonebot_init_funcs.append(func)
- return func
-```
-
-
-### ***def*** `before_start(self) -> None`
-
- 启动前
-
-Returns:
-
-
-源代码
-
-```python
-def before_start(self) -> None:
- """
- 启动前
- Returns:
- """
- logger.debug('Running before_start functions')
- self.run_funcs(self._before_start_funcs)
-```
-
-
-### ***def*** `after_start(self) -> None`
-
- 启动后
-
-Returns:
-
-
-源代码
-
-```python
-def after_start(self) -> None:
- """
- 启动后
- Returns:
- """
- logger.debug('Running after_start functions')
- self.run_funcs(self._after_start_funcs)
-```
-
-
-### ***def*** `before_process_shutdown(self) -> None`
-
- 停止前
-
-Returns:
-
-
-源代码
-
-```python
-def before_process_shutdown(self) -> None:
- """
- 停止前
- Returns:
- """
- logger.debug('Running before_shutdown functions')
- self.run_funcs(self._before_process_shutdown_funcs)
-```
-
-
-### ***def*** `after_shutdown(self) -> None`
-
- 停止后
-
-Returns:
-
-
-源代码
-
-```python
-def after_shutdown(self) -> None:
- """
- 停止后
- Returns:
- """
- logger.debug('Running after_shutdown functions')
- self.run_funcs(self._after_shutdown_funcs)
-```
-
-
-### ***def*** `before_process_restart(self) -> None`
-
- 重启前
-
-Returns:
-
-
-源代码
-
-```python
-def before_process_restart(self) -> None:
- """
- 重启前
- Returns:
- """
- logger.debug('Running before_restart functions')
- self.run_funcs(self._before_process_restart_funcs)
-```
-
-
-### ***def*** `after_restart(self) -> None`
-
- 重启后
-
-Returns:
-
-
-源代码
-
-```python
-def after_restart(self) -> None:
- """
- 重启后
- Returns:
-
- """
- logger.debug('Running after_restart functions')
- self.run_funcs(self._after_restart_funcs)
-```
-
-
-### ***var*** `tasks = []`
-
-
-
-### ***var*** `loop = asyncio.get_event_loop()`
-
-
-
-### ***var*** `loop = asyncio.new_event_loop()`
-
-
-
diff --git a/docs/dev/api/comm/README.md b/docs/dev/api/comm/README.md
deleted file mode 100644
index 09bccc34..00000000
--- a/docs/dev/api/comm/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-title: liteyuki.comm
-index: true
-icon: laptop-code
-category: API
----
-
diff --git a/docs/dev/api/comm/channel.md b/docs/dev/api/comm/channel.md
deleted file mode 100644
index 8e5e170f..00000000
--- a/docs/dev/api/comm/channel.md
+++ /dev/null
@@ -1,427 +0,0 @@
----
-title: liteyuki.comm.channel
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***def*** `set_channel(name: str, channel: Channel) -> None`
-
-设置通道实例
-
-Args:
-
- name: 通道名称
-
- channel: 通道实例
-
-
-源代码
-
-```python
-def set_channel(name: str, channel: Channel):
- """
- 设置通道实例
- Args:
- name: 通道名称
- channel: 通道实例
- """
- if not isinstance(channel, Channel):
- raise TypeError(f'channel_ must be an instance of Channel, {type(channel)} found')
- if IS_MAIN_PROCESS:
- _channel[name] = channel
- else:
- channel_deliver_passive_channel.send(('set_channel', {'name': name, 'channel_': channel}))
-```
-
-
-### ***def*** `set_channels(channels: dict[str, Channel]) -> None`
-
-设置通道实例
-
-Args:
-
- channels: 通道名称
-
-
-源代码
-
-```python
-def set_channels(channels: dict[str, Channel]):
- """
- 设置通道实例
- Args:
- channels: 通道名称
- """
- for name, channel in channels.items():
- set_channel(name, channel)
-```
-
-
-### ***def*** `get_channel(name: str) -> Channel`
-
-获取通道实例
-
-Args:
-
- name: 通道名称
-
-Returns:
-
-
-源代码
-
-```python
-def get_channel(name: str) -> Channel:
- """
- 获取通道实例
- Args:
- name: 通道名称
- Returns:
- """
- if IS_MAIN_PROCESS:
- return _channel[name]
- else:
- recv_chan = Channel[Channel[Any]]('recv_chan')
- channel_deliver_passive_channel.send(('get_channel', {'name': name, 'recv_chan': recv_chan}))
- return recv_chan.receive()
-```
-
-
-### ***def*** `get_channels() -> dict[str, Channel]`
-
-获取通道实例
-
-Returns:
-
-
-源代码
-
-```python
-def get_channels() -> dict[str, Channel]:
- """
- 获取通道实例
- Returns:
- """
- if IS_MAIN_PROCESS:
- return _channel
- else:
- recv_chan = Channel[dict[str, Channel[Any]]]('recv_chan')
- channel_deliver_passive_channel.send(('get_channels', {'recv_chan': recv_chan}))
- return recv_chan.receive()
-```
-
-
-### ***def*** `on_set_channel(data: tuple[str, dict[str, Any]]) -> None`
-
-
-
-
-源代码
-
-```python
-@channel_deliver_passive_channel.on_receive(filter_func=lambda data: data[0] == 'set_channel')
-def on_set_channel(data: tuple[str, dict[str, Any]]):
- name, channel = (data[1]['name'], data[1]['channel_'])
- set_channel(name, channel)
-```
-
-
-### ***def*** `on_get_channel(data: tuple[str, dict[str, Any]]) -> None`
-
-
-
-
-源代码
-
-```python
-@channel_deliver_passive_channel.on_receive(filter_func=lambda data: data[0] == 'get_channel')
-def on_get_channel(data: tuple[str, dict[str, Any]]):
- name, recv_chan = (data[1]['name'], data[1]['recv_chan'])
- recv_chan.send(get_channel(name))
-```
-
-
-### ***def*** `on_get_channels(data: tuple[str, dict[str, Any]]) -> None`
-
-
-
-
-源代码
-
-```python
-@channel_deliver_passive_channel.on_receive(filter_func=lambda data: data[0] == 'get_channels')
-def on_get_channels(data: tuple[str, dict[str, Any]]):
- recv_chan = data[1]['recv_chan']
- recv_chan.send(get_channels())
-```
-
-
-### ***def*** `decorator(func: Callable[[T], Any]) -> Callable[[T], Any]`
-
-
-
-
-源代码
-
-```python
-def decorator(func: Callable[[T], Any]) -> Callable[[T], Any]:
- global _func_id
-
- async def wrapper(data: T) -> Any:
- if filter_func is not None:
- if is_coroutine_callable(filter_func):
- if not await filter_func(data):
- return
- elif not filter_func(data):
- return
- if is_coroutine_callable(func):
- return await func(data)
- else:
- return func(data)
- _callback_funcs[_func_id] = wrapper
- if IS_MAIN_PROCESS:
- self._on_main_receive_funcs.append(_func_id)
- else:
- self._on_sub_receive_funcs.append(_func_id)
- _func_id += 1
- return func
-```
-
-
-### ***async def*** `wrapper(data: T) -> Any`
-
-
-
-
-源代码
-
-```python
-async def wrapper(data: T) -> Any:
- if filter_func is not None:
- if is_coroutine_callable(filter_func):
- if not await filter_func(data):
- return
- elif not filter_func(data):
- return
- if is_coroutine_callable(func):
- return await func(data)
- else:
- return func(data)
-```
-
-
-### ***class*** `Channel(Generic[T])`
-
-通道类,可以在进程间和进程内通信,双向但同时只能有一个发送者和一个接收者
-
-有两种接收工作方式,但是只能选择一种,主动接收和被动接收,主动接收使用 `receive` 方法,被动接收使用 `on_receive` 装饰器
-
-### ***def*** `__init__(self, _id: str, type_check: Optional[bool]) -> None`
-
- 初始化通道
-
-Args:
-
- _id: 通道ID
-
- type_check: 是否开启类型检查, 若为空,则传入泛型默认开启,否则默认关闭
-
-
-源代码
-
-```python
-def __init__(self, _id: str, type_check: Optional[bool]=None):
- """
- 初始化通道
- Args:
- _id: 通道ID
- type_check: 是否开启类型检查, 若为空,则传入泛型默认开启,否则默认关闭
- """
- self.conn_send, self.conn_recv = Pipe()
- self._closed = False
- self._on_main_receive_funcs: list[int] = []
- self._on_sub_receive_funcs: list[int] = []
- self.name: str = _id
- self.is_main_receive_loop_running = False
- self.is_sub_receive_loop_running = False
- if type_check is None:
- type_check = self._get_generic_type() is not None
- elif type_check:
- if self._get_generic_type() is None:
- raise TypeError('Type hint is required for enforcing type check.')
- self.type_check = type_check
-```
-
-
-### ***def*** `send(self, data: T) -> None`
-
- 发送数据
-
-Args:
-
- data: 数据
-
-
-源代码
-
-```python
-def send(self, data: T):
- """
- 发送数据
- Args:
- data: 数据
- """
- if self.type_check:
- _type = self._get_generic_type()
- if _type is not None and (not self._validate_structure(data, _type)):
- raise TypeError(f'Data must be an instance of {_type}, {type(data)} found')
- if self._closed:
- raise RuntimeError('Cannot send to a closed channel_')
- self.conn_send.send(data)
-```
-
-
-### ***def*** `receive(self) -> T`
-
- 接收数据
-
-Args:
-
-
-源代码
-
-```python
-def receive(self) -> T:
- """
- 接收数据
- Args:
- """
- if self._closed:
- raise RuntimeError('Cannot receive from a closed channel_')
- while True:
- data = self.conn_recv.recv()
- return data
-```
-
-
-### ***def*** `close(self) -> None`
-
- 关闭通道
-
-
-源代码
-
-```python
-def close(self):
- """
- 关闭通道
- """
- self._closed = True
- self.conn_send.close()
- self.conn_recv.close()
-```
-
-
-### ***def*** `on_receive(self, filter_func: Optional[FILTER_FUNC]) -> Callable[[Callable[[T], Any]], Callable[[T], Any]]`
-
- 接收数据并执行函数
-
-Args:
-
- filter_func: 过滤函数,为None则不过滤
-
-Returns:
-
- 装饰器,装饰一个函数在接收到数据后执行
-
-
-源代码
-
-```python
-def on_receive(self, filter_func: Optional[FILTER_FUNC]=None) -> Callable[[Callable[[T], Any]], Callable[[T], Any]]:
- """
- 接收数据并执行函数
- Args:
- filter_func: 过滤函数,为None则不过滤
- Returns:
- 装饰器,装饰一个函数在接收到数据后执行
- """
- if not self.is_sub_receive_loop_running and (not IS_MAIN_PROCESS):
- threading.Thread(target=self._start_sub_receive_loop, daemon=True).start()
- if not self.is_main_receive_loop_running and IS_MAIN_PROCESS:
- threading.Thread(target=self._start_main_receive_loop, daemon=True).start()
-
- def decorator(func: Callable[[T], Any]) -> Callable[[T], Any]:
- global _func_id
-
- async def wrapper(data: T) -> Any:
- if filter_func is not None:
- if is_coroutine_callable(filter_func):
- if not await filter_func(data):
- return
- elif not filter_func(data):
- return
- if is_coroutine_callable(func):
- return await func(data)
- else:
- return func(data)
- _callback_funcs[_func_id] = wrapper
- if IS_MAIN_PROCESS:
- self._on_main_receive_funcs.append(_func_id)
- else:
- self._on_sub_receive_funcs.append(_func_id)
- _func_id += 1
- return func
- return decorator
-```
-
-
-### ***var*** `T = TypeVar('T')`
-
-
-
-### ***var*** `channel_deliver_active_channel = Channel(_id='channel_deliver_active_channel')`
-
-
-
-### ***var*** `channel_deliver_passive_channel = Channel(_id='channel_deliver_passive_channel')`
-
-
-
-### ***var*** `recv_chan = data[1]['recv_chan']`
-
-
-
-### ***var*** `recv_chan = Channel[Channel[Any]]('recv_chan')`
-
-
-
-### ***var*** `recv_chan = Channel[dict[str, Channel[Any]]]('recv_chan')`
-
-
-
-### ***var*** `type_check = self._get_generic_type() is not None`
-
-
-
-### ***var*** `data = self.conn_recv.recv()`
-
-
-
-### ***var*** `func = _callback_funcs[func_id]`
-
-
-
-### ***var*** `func = _callback_funcs[func_id]`
-
-
-
-### ***var*** `data = self.conn_recv.recv()`
-
-
-
-### ***var*** `data = self.conn_recv.recv()`
-
-
-
diff --git a/docs/dev/api/comm/event.md b/docs/dev/api/comm/event.md
deleted file mode 100644
index a2a15f55..00000000
--- a/docs/dev/api/comm/event.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: liteyuki.comm.event
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***class*** `Event`
-
-事件类
-
-### ***def*** `__init__(self, name: str, data: dict[str, Any]) -> None`
-
-
-
-
-源代码
-
-```python
-def __init__(self, name: str, data: dict[str, Any]):
- self.name = name
- self.data = data
-```
-
-
diff --git a/docs/dev/api/comm/storage.md b/docs/dev/api/comm/storage.md
deleted file mode 100644
index cd19dbb7..00000000
--- a/docs/dev/api/comm/storage.md
+++ /dev/null
@@ -1,563 +0,0 @@
----
-title: liteyuki.comm.storage
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***def*** `run_subscriber_receive_funcs(channel_: str, data: Any) -> None`
-
-运行订阅者接收函数
-
-Args:
-
- channel_: 频道
-
- data: 数据
-
-
-源代码
-
-```python
-@staticmethod
-def run_subscriber_receive_funcs(channel_: str, data: Any):
- """
- 运行订阅者接收函数
- Args:
- channel_: 频道
- data: 数据
- """
- if IS_MAIN_PROCESS:
- if channel_ in _on_main_subscriber_receive_funcs and _on_main_subscriber_receive_funcs[channel_]:
- run_coroutine(*[func(data) for func in _on_main_subscriber_receive_funcs[channel_]])
- elif channel_ in _on_sub_subscriber_receive_funcs and _on_sub_subscriber_receive_funcs[channel_]:
- run_coroutine(*[func(data) for func in _on_sub_subscriber_receive_funcs[channel_]])
-```
-
-
-### ***def*** `on_get(data: tuple[str, dict[str, Any]]) -> None`
-
-
-
-
-源代码
-
-```python
-@shared_memory.passive_chan.on_receive(lambda d: d[0] == 'get')
-def on_get(data: tuple[str, dict[str, Any]]):
- key = data[1]['key']
- default = data[1]['default']
- recv_chan = data[1]['recv_chan']
- recv_chan.send(shared_memory.get(key, default))
-```
-
-
-### ***def*** `on_set(data: tuple[str, dict[str, Any]]) -> None`
-
-
-
-
-源代码
-
-```python
-@shared_memory.passive_chan.on_receive(lambda d: d[0] == 'set')
-def on_set(data: tuple[str, dict[str, Any]]):
- key = data[1]['key']
- value = data[1]['value']
- shared_memory.set(key, value)
-```
-
-
-### ***def*** `on_delete(data: tuple[str, dict[str, Any]]) -> None`
-
-
-
-
-源代码
-
-```python
-@shared_memory.passive_chan.on_receive(lambda d: d[0] == 'delete')
-def on_delete(data: tuple[str, dict[str, Any]]):
- key = data[1]['key']
- shared_memory.delete(key)
-```
-
-
-### ***def*** `on_get_all(data: tuple[str, dict[str, Any]]) -> None`
-
-
-
-
-源代码
-
-```python
-@shared_memory.passive_chan.on_receive(lambda d: d[0] == 'get_all')
-def on_get_all(data: tuple[str, dict[str, Any]]):
- recv_chan = data[1]['recv_chan']
- recv_chan.send(shared_memory.get_all())
-```
-
-
-### ***def*** `on_publish(data: tuple[str, Any]) -> None`
-
-
-
-
-源代码
-
-```python
-@channel.publish_channel.on_receive()
-def on_publish(data: tuple[str, Any]):
- channel_, data = data
- shared_memory.run_subscriber_receive_funcs(channel_, data)
-```
-
-
-### ***def*** `decorator(func: ON_RECEIVE_FUNC) -> ON_RECEIVE_FUNC`
-
-
-
-
-源代码
-
-```python
-def decorator(func: ON_RECEIVE_FUNC) -> ON_RECEIVE_FUNC:
-
- async def wrapper(data: Any):
- if is_coroutine_callable(func):
- await func(data)
- else:
- func(data)
- if IS_MAIN_PROCESS:
- if channel_ not in _on_main_subscriber_receive_funcs:
- _on_main_subscriber_receive_funcs[channel_] = []
- _on_main_subscriber_receive_funcs[channel_].append(wrapper)
- else:
- if channel_ not in _on_sub_subscriber_receive_funcs:
- _on_sub_subscriber_receive_funcs[channel_] = []
- _on_sub_subscriber_receive_funcs[channel_].append(wrapper)
- return wrapper
-```
-
-
-### ***async def*** `wrapper(data: Any) -> None`
-
-
-
-
-源代码
-
-```python
-async def wrapper(data: Any):
- if is_coroutine_callable(func):
- await func(data)
- else:
- func(data)
-```
-
-
-### ***class*** `Subscriber`
-
-
-
-### ***def*** `__init__(self) -> None`
-
-
-
-
-源代码
-
-```python
-def __init__(self):
- self._subscribers = {}
-```
-
-
-### ***def*** `receive(self) -> Any`
-
-
-
-
-源代码
-
-```python
-def receive(self) -> Any:
- pass
-```
-
-
-### ***def*** `unsubscribe(self) -> None`
-
-
-
-
-源代码
-
-```python
-def unsubscribe(self) -> None:
- pass
-```
-
-
-### ***class*** `KeyValueStore`
-
-
-
-### ***def*** `__init__(self) -> None`
-
-
-
-
-源代码
-
-```python
-def __init__(self):
- self._store = {}
- self.active_chan = Channel[tuple[str, Optional[dict[str, Any]]]](_id='shared_memory-active')
- self.passive_chan = Channel[tuple[str, Optional[dict[str, Any]]]](_id='shared_memory-passive')
- self.publish_channel = Channel[tuple[str, Any]](_id='shared_memory-publish')
- self.is_main_receive_loop_running = False
- self.is_sub_receive_loop_running = False
-```
-
-
-### ***def*** `set(self, key: str, value: Any) -> None`
-
- 设置键值对
-
-Args:
-
- key: 键
-
- value: 值
-
-
-源代码
-
-```python
-def set(self, key: str, value: Any) -> None:
- """
- 设置键值对
- Args:
- key: 键
- value: 值
-
- """
- if IS_MAIN_PROCESS:
- lock = _get_lock(key)
- with lock:
- self._store[key] = value
- else:
- self.passive_chan.send(('set', {'key': key, 'value': value}))
-```
-
-
-### ***def*** `get(self, key: str, default: Optional[Any]) -> Optional[Any]`
-
- 获取键值对
-
-Args:
-
- key: 键
-
- default: 默认值
-
-
-
-Returns:
-
- Any: 值
-
-
-源代码
-
-```python
-def get(self, key: str, default: Optional[Any]=None) -> Optional[Any]:
- """
- 获取键值对
- Args:
- key: 键
- default: 默认值
-
- Returns:
- Any: 值
- """
- if IS_MAIN_PROCESS:
- lock = _get_lock(key)
- with lock:
- return self._store.get(key, default)
- else:
- recv_chan = Channel[Optional[Any]]('recv_chan')
- self.passive_chan.send(('get', {'key': key, 'default': default, 'recv_chan': recv_chan}))
- return recv_chan.receive()
-```
-
-
-### ***def*** `delete(self, key: str, ignore_key_error: bool) -> None`
-
- 删除键值对
-
-Args:
-
- key: 键
-
- ignore_key_error: 是否忽略键不存在的错误
-
-
-
-Returns:
-
-
-源代码
-
-```python
-def delete(self, key: str, ignore_key_error: bool=True) -> None:
- """
- 删除键值对
- Args:
- key: 键
- ignore_key_error: 是否忽略键不存在的错误
-
- Returns:
- """
- if IS_MAIN_PROCESS:
- lock = _get_lock(key)
- with lock:
- if key in self._store:
- try:
- del self._store[key]
- del _locks[key]
- except KeyError as e:
- if not ignore_key_error:
- raise e
- else:
- self.passive_chan.send(('delete', {'key': key}))
-```
-
-
-### ***def*** `get_all(self) -> dict[str, Any]`
-
- 获取所有键值对
-
-Returns:
-
- dict[str, Any]: 键值对
-
-
-源代码
-
-```python
-def get_all(self) -> dict[str, Any]:
- """
- 获取所有键值对
- Returns:
- dict[str, Any]: 键值对
- """
- if IS_MAIN_PROCESS:
- return self._store
- else:
- recv_chan = Channel[dict[str, Any]]('recv_chan')
- self.passive_chan.send(('get_all', {'recv_chan': recv_chan}))
- return recv_chan.receive()
-```
-
-
-### ***def*** `publish(self, channel_: str, data: Any) -> None`
-
- 发布消息
-
-Args:
-
- channel_: 频道
-
- data: 数据
-
-
-
-Returns:
-
-
-源代码
-
-```python
-def publish(self, channel_: str, data: Any) -> None:
- """
- 发布消息
- Args:
- channel_: 频道
- data: 数据
-
- Returns:
- """
- self.active_chan.send(('publish', {'channel': channel_, 'data': data}))
-```
-
-
-### ***def*** `on_subscriber_receive(self, channel_: str) -> Callable[[ON_RECEIVE_FUNC], ON_RECEIVE_FUNC]`
-
- 订阅者接收消息时的回调
-
-Args:
-
- channel_: 频道
-
-
-
-Returns:
-
- 装饰器
-
-
-源代码
-
-```python
-def on_subscriber_receive(self, channel_: str) -> Callable[[ON_RECEIVE_FUNC], ON_RECEIVE_FUNC]:
- """
- 订阅者接收消息时的回调
- Args:
- channel_: 频道
-
- Returns:
- 装饰器
- """
- if IS_MAIN_PROCESS and (not self.is_main_receive_loop_running):
- threading.Thread(target=self._start_receive_loop, daemon=True).start()
- shared_memory.is_main_receive_loop_running = True
- elif not IS_MAIN_PROCESS and (not self.is_sub_receive_loop_running):
- threading.Thread(target=self._start_receive_loop, daemon=True).start()
- shared_memory.is_sub_receive_loop_running = True
-
- def decorator(func: ON_RECEIVE_FUNC) -> ON_RECEIVE_FUNC:
-
- async def wrapper(data: Any):
- if is_coroutine_callable(func):
- await func(data)
- else:
- func(data)
- if IS_MAIN_PROCESS:
- if channel_ not in _on_main_subscriber_receive_funcs:
- _on_main_subscriber_receive_funcs[channel_] = []
- _on_main_subscriber_receive_funcs[channel_].append(wrapper)
- else:
- if channel_ not in _on_sub_subscriber_receive_funcs:
- _on_sub_subscriber_receive_funcs[channel_] = []
- _on_sub_subscriber_receive_funcs[channel_].append(wrapper)
- return wrapper
- return decorator
-```
-
-
-### ***@staticmethod***
-### ***def*** `run_subscriber_receive_funcs(channel_: str, data: Any) -> None`
-
- 运行订阅者接收函数
-
-Args:
-
- channel_: 频道
-
- data: 数据
-
-
-源代码
-
-```python
-@staticmethod
-def run_subscriber_receive_funcs(channel_: str, data: Any):
- """
- 运行订阅者接收函数
- Args:
- channel_: 频道
- data: 数据
- """
- if IS_MAIN_PROCESS:
- if channel_ in _on_main_subscriber_receive_funcs and _on_main_subscriber_receive_funcs[channel_]:
- run_coroutine(*[func(data) for func in _on_main_subscriber_receive_funcs[channel_]])
- elif channel_ in _on_sub_subscriber_receive_funcs and _on_sub_subscriber_receive_funcs[channel_]:
- run_coroutine(*[func(data) for func in _on_sub_subscriber_receive_funcs[channel_]])
-```
-
-
-### ***class*** `GlobalKeyValueStore`
-
-
-
-### ***@classmethod***
-### ***def*** `get_instance(cls: Any) -> None`
-
-
-
-
-源代码
-
-```python
-@classmethod
-def get_instance(cls):
- if cls._instance is None:
- with cls._lock:
- if cls._instance is None:
- cls._instance = KeyValueStore()
- return cls._instance
-```
-
-
-### ***attr*** `_instance: None`
-
-### ***attr*** `_lock: threading.Lock()`
-
-### ***var*** `key = data[1]['key']`
-
-
-
-### ***var*** `default = data[1]['default']`
-
-
-
-### ***var*** `recv_chan = data[1]['recv_chan']`
-
-
-
-### ***var*** `key = data[1]['key']`
-
-
-
-### ***var*** `value = data[1]['value']`
-
-
-
-### ***var*** `key = data[1]['key']`
-
-
-
-### ***var*** `recv_chan = data[1]['recv_chan']`
-
-
-
-### ***var*** `lock = _get_lock(key)`
-
-
-
-### ***var*** `lock = _get_lock(key)`
-
-
-
-### ***var*** `recv_chan = Channel[Optional[Any]]('recv_chan')`
-
-
-
-### ***var*** `lock = _get_lock(key)`
-
-
-
-### ***var*** `recv_chan = Channel[dict[str, Any]]('recv_chan')`
-
-
-
-### ***var*** `data = self.active_chan.receive()`
-
-
-
-### ***var*** `data = self.publish_channel.receive()`
-
-
-
diff --git a/docs/dev/api/config.md b/docs/dev/api/config.md
deleted file mode 100644
index 24afd6c9..00000000
--- a/docs/dev/api/config.md
+++ /dev/null
@@ -1,231 +0,0 @@
----
-title: liteyuki.config
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***def*** `flat_config(config: dict[str, Any]) -> dict[str, Any]`
-
-扁平化配置文件
-
-
-
-{a:{b:{c:1}}} -> {"a.b.c": 1}
-
-Args:
-
- config: 配置项目
-
-
-
-Returns:
-
- 扁平化后的配置文件,但也包含原有的键值对
-
-
-源代码
-
-```python
-def flat_config(config: dict[str, Any]) -> dict[str, Any]:
- """
- 扁平化配置文件
-
- {a:{b:{c:1}}} -> {"a.b.c": 1}
- Args:
- config: 配置项目
-
- Returns:
- 扁平化后的配置文件,但也包含原有的键值对
- """
- new_config = copy.deepcopy(config)
- for key, value in config.items():
- if isinstance(value, dict):
- for k, v in flat_config(value).items():
- new_config[f'{key}.{k}'] = v
- return new_config
-```
-
-
-### ***def*** `load_from_yaml(file: str) -> dict[str, Any]`
-
-Load config from yaml file
-
-
-源代码
-
-```python
-def load_from_yaml(file: str) -> dict[str, Any]:
- """
- Load config from yaml file
-
- """
- logger.debug(f'Loading YAML config from {file}')
- config = yaml.safe_load(open(file, 'r', encoding='utf-8'))
- return flat_config(config if config is not None else {})
-```
-
-
-### ***def*** `load_from_json(file: str) -> dict[str, Any]`
-
-Load config from json file
-
-
-源代码
-
-```python
-def load_from_json(file: str) -> dict[str, Any]:
- """
- Load config from json file
- """
- logger.debug(f'Loading JSON config from {file}')
- config = json.load(open(file, 'r', encoding='utf-8'))
- return flat_config(config if config is not None else {})
-```
-
-
-### ***def*** `load_from_toml(file: str) -> dict[str, Any]`
-
-Load config from toml file
-
-
-源代码
-
-```python
-def load_from_toml(file: str) -> dict[str, Any]:
- """
- Load config from toml file
- """
- logger.debug(f'Loading TOML config from {file}')
- config = toml.load(open(file, 'r', encoding='utf-8'))
- return flat_config(config if config is not None else {})
-```
-
-
-### ***def*** `load_from_files() -> dict[str, Any]`
-
-从指定文件加载配置项,会自动识别文件格式
-
-默认执行扁平化选项
-
-
-源代码
-
-```python
-def load_from_files(*files: str, no_warning: bool=False) -> dict[str, Any]:
- """
- 从指定文件加载配置项,会自动识别文件格式
- 默认执行扁平化选项
- """
- config = {}
- for file in files:
- if os.path.exists(file):
- if file.endswith(('.yaml', 'yml')):
- config.update(load_from_yaml(file))
- elif file.endswith('.json'):
- config.update(load_from_json(file))
- elif file.endswith('.toml'):
- config.update(load_from_toml(file))
- elif not no_warning:
- logger.warning(f'Unsupported config file format: {file}')
- elif not no_warning:
- logger.warning(f'Config file not found: {file}')
- return config
-```
-
-
-### ***def*** `load_configs_from_dirs() -> dict[str, Any]`
-
-从目录下加载配置文件,不递归
-
-按照读取文件的优先级反向覆盖
-
-默认执行扁平化选项
-
-
-源代码
-
-```python
-def load_configs_from_dirs(*directories: str, no_waring: bool=False) -> dict[str, Any]:
- """
- 从目录下加载配置文件,不递归
- 按照读取文件的优先级反向覆盖
- 默认执行扁平化选项
- """
- config = {}
- for directory in directories:
- if not os.path.exists(directory):
- if not no_waring:
- logger.warning(f'Directory not found: {directory}')
- continue
- for file in os.listdir(directory):
- if file.endswith(_SUPPORTED_CONFIG_FORMATS):
- config.update(load_from_files(os.path.join(directory, file), no_warning=no_waring))
- return config
-```
-
-
-### ***def*** `load_config_in_default(no_waring: bool) -> dict[str, Any]`
-
-从一个标准的轻雪项目加载配置文件
-
-项目目录下的config.*和config目录下的所有配置文件
-
-项目目录下的配置文件优先
-
-
-源代码
-
-```python
-def load_config_in_default(no_waring: bool=False) -> dict[str, Any]:
- """
- 从一个标准的轻雪项目加载配置文件
- 项目目录下的config.*和config目录下的所有配置文件
- 项目目录下的配置文件优先
- """
- config = load_configs_from_dirs('config', no_waring=no_waring)
- config.update(load_from_files('config.yaml', 'config.toml', 'config.json', 'config.yml', no_warning=no_waring))
- return config
-```
-
-
-### ***class*** `SatoriNodeConfig(BaseModel)`
-
-
-
-### ***class*** `SatoriConfig(BaseModel)`
-
-
-
-### ***class*** `BasicConfig(BaseModel)`
-
-
-
-### ***var*** `new_config = copy.deepcopy(config)`
-
-
-
-### ***var*** `config = yaml.safe_load(open(file, 'r', encoding='utf-8'))`
-
-
-
-### ***var*** `config = json.load(open(file, 'r', encoding='utf-8'))`
-
-
-
-### ***var*** `config = toml.load(open(file, 'r', encoding='utf-8'))`
-
-
-
-### ***var*** `config = {}`
-
-
-
-### ***var*** `config = {}`
-
-
-
-### ***var*** `config = load_configs_from_dirs('config', no_waring=no_waring)`
-
-
-
diff --git a/docs/dev/api/core/README.md b/docs/dev/api/core/README.md
deleted file mode 100644
index 26c3500b..00000000
--- a/docs/dev/api/core/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-title: liteyuki.core
-index: true
-icon: laptop-code
-category: API
----
-
diff --git a/docs/dev/api/core/manager.md b/docs/dev/api/core/manager.md
deleted file mode 100644
index 52397375..00000000
--- a/docs/dev/api/core/manager.md
+++ /dev/null
@@ -1,275 +0,0 @@
----
-title: liteyuki.core.manager
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***class*** `ChannelDeliver`
-
-
-
-### ***def*** `__init__(self, active: Channel[Any], passive: Channel[Any], channel_deliver_active: Channel[Channel[Any]], channel_deliver_passive: Channel[tuple[str, dict]], publish: Channel[tuple[str, Any]]) -> None`
-
-
-
-
-源代码
-
-```python
-def __init__(self, active: Channel[Any], passive: Channel[Any], channel_deliver_active: Channel[Channel[Any]], channel_deliver_passive: Channel[tuple[str, dict]], publish: Channel[tuple[str, Any]]):
- self.active = active
- self.passive = passive
- self.channel_deliver_active = channel_deliver_active
- self.channel_deliver_passive = channel_deliver_passive
- self.publish = publish
-```
-
-
-### ***class*** `ProcessManager`
-
-进程管理器
-
-### ***def*** `__init__(self, lifespan: 'Lifespan') -> None`
-
-
-
-
-源代码
-
-```python
-def __init__(self, lifespan: 'Lifespan'):
- self.lifespan = lifespan
- self.targets: dict[str, tuple[Callable, tuple, dict]] = {}
- self.processes: dict[str, Process] = {}
-```
-
-
-### ***def*** `start(self, name: str) -> None`
-
- 开启后自动监控进程,并添加到进程字典中
-
-Args:
-
- name:
-
-Returns:
-
-
-源代码
-
-```python
-def start(self, name: str):
- """
- 开启后自动监控进程,并添加到进程字典中
- Args:
- name:
- Returns:
-
- """
- if name not in self.targets:
- raise KeyError(f'Process {name} not found.')
- chan_active = get_channel(f'{name}-active')
-
- def _start_process():
- process = Process(target=self.targets[name][0], args=self.targets[name][1], kwargs=self.targets[name][2], daemon=True)
- self.processes[name] = process
- process.start()
- _start_process()
- while True:
- data = chan_active.receive()
- if data == 0:
- logger.info(f'Stopping process {name}')
- self.lifespan.before_process_shutdown()
- self.terminate(name)
- break
- elif data == 1:
- logger.info(f'Restarting process {name}')
- self.lifespan.before_process_shutdown()
- self.lifespan.before_process_restart()
- self.terminate(name)
- _start_process()
- continue
- else:
- logger.warning('Unknown data received, ignored.')
-```
-
-
-### ***def*** `start_all(self) -> None`
-
- 启动所有进程
-
-
-源代码
-
-```python
-def start_all(self):
- """
- 启动所有进程
- """
- for name in self.targets:
- threading.Thread(target=self.start, args=(name,), daemon=True).start()
-```
-
-
-### ***def*** `add_target(self, name: str, target: TARGET_FUNC, args: tuple, kwargs: Any) -> None`
-
- 添加进程
-
-Args:
-
- name: 进程名,用于获取和唯一标识
-
- target: 进程函数
-
- args: 进程函数参数
-
- kwargs: 进程函数关键字参数,通常会默认传入chan_active和chan_passive
-
-
-源代码
-
-```python
-def add_target(self, name: str, target: TARGET_FUNC, args: tuple=(), kwargs=None):
- """
- 添加进程
- Args:
- name: 进程名,用于获取和唯一标识
- target: 进程函数
- args: 进程函数参数
- kwargs: 进程函数关键字参数,通常会默认传入chan_active和chan_passive
- """
- if kwargs is None:
- kwargs = {}
- chan_active: Channel = Channel(_id=f'{name}-active')
- chan_passive: Channel = Channel(_id=f'{name}-passive')
- channel_deliver = ChannelDeliver(active=chan_active, passive=chan_passive, channel_deliver_active=channel_deliver_active_channel, channel_deliver_passive=channel_deliver_passive_channel, publish=publish_channel)
- self.targets[name] = (_delivery_channel_wrapper, (target, channel_deliver, shared_memory, *args), kwargs)
- set_channels({f'{name}-active': chan_active, f'{name}-passive': chan_passive})
-```
-
-
-### ***def*** `join_all(self) -> None`
-
-
-
-
-源代码
-
-```python
-def join_all(self):
- for name, process in self.targets:
- process.join()
-```
-
-
-### ***def*** `terminate(self, name: str) -> None`
-
- 终止进程并从进程字典中删除
-
-Args:
-
- name:
-
-
-
-Returns:
-
-
-源代码
-
-```python
-def terminate(self, name: str):
- """
- 终止进程并从进程字典中删除
- Args:
- name:
-
- Returns:
-
- """
- if name not in self.processes:
- logger.warning(f'Process {name} not found.')
- return
- process = self.processes[name]
- process.terminate()
- process.join(TIMEOUT)
- if process.is_alive():
- process.kill()
- logger.success(f'Process {name} terminated.')
-```
-
-
-### ***def*** `terminate_all(self) -> None`
-
-
-
-
-源代码
-
-```python
-def terminate_all(self):
- for name in self.targets:
- self.terminate(name)
-```
-
-
-### ***def*** `is_process_alive(self, name: str) -> bool`
-
- 检查进程是否存活
-
-Args:
-
- name:
-
-
-
-Returns:
-
-
-源代码
-
-```python
-def is_process_alive(self, name: str) -> bool:
- """
- 检查进程是否存活
- Args:
- name:
-
- Returns:
-
- """
- if name not in self.targets:
- logger.warning(f'Process {name} not found.')
- return self.processes[name].is_alive()
-```
-
-
-### ***var*** `TIMEOUT = 10`
-
-
-
-### ***var*** `chan_active = get_channel(f'{name}-active')`
-
-
-
-### ***var*** `channel_deliver = ChannelDeliver(active=chan_active, passive=chan_passive, channel_deliver_active=channel_deliver_active_channel, channel_deliver_passive=channel_deliver_passive_channel, publish=publish_channel)`
-
-
-
-### ***var*** `process = self.processes[name]`
-
-
-
-### ***var*** `process = Process(target=self.targets[name][0], args=self.targets[name][1], kwargs=self.targets[name][2], daemon=True)`
-
-
-
-### ***var*** `data = chan_active.receive()`
-
-
-
-### ***var*** `kwargs = {}`
-
-
-
diff --git a/docs/dev/api/dev/README.md b/docs/dev/api/dev/README.md
deleted file mode 100644
index 6d883442..00000000
--- a/docs/dev/api/dev/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-title: liteyuki.dev
-index: true
-icon: laptop-code
-category: API
----
-
diff --git a/docs/dev/api/dev/observer.md b/docs/dev/api/dev/observer.md
deleted file mode 100644
index 2005bbf2..00000000
--- a/docs/dev/api/dev/observer.md
+++ /dev/null
@@ -1,249 +0,0 @@
----
-title: liteyuki.dev.observer
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***def*** `debounce(wait: Any) -> None`
-
-防抖函数
-
-
-源代码
-
-```python
-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
-```
-
-
-### ***def*** `on_file_system_event(directories: tuple[str], recursive: bool, event_filter: FILTER_FUNC) -> Callable[[CALLBACK_FUNC], CALLBACK_FUNC]`
-
-注册文件系统变化监听器
-
-Args:
-
- directories: 监听目录们
-
- recursive: 是否递归监听子目录
-
- event_filter: 事件过滤器, 返回True则执行回调函数
-
-Returns:
-
- 装饰器,装饰一个函数在接收到数据后执行
-
-
-源代码
-
-```python
-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
-```
-
-
-### ***def*** `decorator(func: Any) -> None`
-
-
-
-
-源代码
-
-```python
-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
-```
-
-
-### ***def*** `decorator(func: CALLBACK_FUNC) -> CALLBACK_FUNC`
-
-
-
-
-源代码
-
-```python
-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
-```
-
-
-### ***def*** `wrapper() -> None`
-
-
-
-
-源代码
-
-```python
-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)
-```
-
-
-### ***def*** `wrapper(event: FileSystemEvent) -> None`
-
-
-
-
-源代码
-
-```python
-def wrapper(event: FileSystemEvent):
- if event_filter is not None and (not event_filter(event)):
- return
- func(event)
-```
-
-
-### ***class*** `CodeModifiedHandler(FileSystemEventHandler)`
-
-Handler for code file changes
-
-### ***def*** `on_modified(self, event: Any) -> None`
-
-
-
-
-源代码
-
-```python
-@debounce(1)
-def on_modified(self, event):
- raise NotImplementedError('on_modified must be implemented')
-```
-
-
-### ***def*** `on_created(self, event: Any) -> None`
-
-
-
-
-源代码
-
-```python
-def on_created(self, event):
- self.on_modified(event)
-```
-
-
-### ***def*** `on_deleted(self, event: Any) -> None`
-
-
-
-
-源代码
-
-```python
-def on_deleted(self, event):
- self.on_modified(event)
-```
-
-
-### ***def*** `on_moved(self, event: Any) -> None`
-
-
-
-
-源代码
-
-```python
-def on_moved(self, event):
- self.on_modified(event)
-```
-
-
-### ***def*** `on_any_event(self, event: Any) -> None`
-
-
-
-
-源代码
-
-```python
-def on_any_event(self, event):
- self.on_modified(event)
-```
-
-
-### ***var*** `liteyuki_bot = get_bot()`
-
-
-
-### ***var*** `observer = Observer()`
-
-
-
-### ***var*** `last_call_time = None`
-
-
-
-### ***var*** `code_modified_handler = CodeModifiedHandler()`
-
-
-
-### ***var*** `current_time = time.time()`
-
-
-
-### ***var*** `last_call_time = current_time`
-
-
-
diff --git a/docs/dev/api/dev/plugin.md b/docs/dev/api/dev/plugin.md
deleted file mode 100644
index caafa5ea..00000000
--- a/docs/dev/api/dev/plugin.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-title: liteyuki.dev.plugin
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***def*** `run_plugins() -> None`
-
-运行插件,无需手动初始化bot
-
-Args:
-
- module_path: 插件路径,参考`liteyuki.load_plugin`的函数签名
-
-
-源代码
-
-```python
-def run_plugins(*module_path: str | Path):
- """
- 运行插件,无需手动初始化bot
- Args:
- module_path: 插件路径,参考`liteyuki.load_plugin`的函数签名
- """
- cfg = load_config_in_default()
- plugins = cfg.get('liteyuki.plugins', [])
- plugins.extend(module_path)
- cfg['liteyuki.plugins'] = plugins
- bot = LiteyukiBot(**cfg)
- bot.run()
-```
-
-
-### ***var*** `cfg = load_config_in_default()`
-
-
-
-### ***var*** `plugins = cfg.get('liteyuki.plugins', [])`
-
-
-
-### ***var*** `bot = LiteyukiBot(**cfg)`
-
-
-
diff --git a/docs/dev/api/exception.md b/docs/dev/api/exception.md
deleted file mode 100644
index 469c00d6..00000000
--- a/docs/dev/api/exception.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-title: liteyuki.exception
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***class*** `LiteyukiException(BaseException)`
-
-Liteyuki的异常基类。
-
diff --git a/docs/dev/api/log.md b/docs/dev/api/log.md
deleted file mode 100644
index af382275..00000000
--- a/docs/dev/api/log.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-title: liteyuki.log
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***def*** `get_format(level: str) -> str`
-
-
-
-
-源代码
-
-```python
-def get_format(level: str) -> str:
- if level == 'DEBUG':
- return debug_format
- else:
- return default_format
-```
-
-
-### ***def*** `init_log(config: dict) -> None`
-
-在语言加载完成后执行
-
-Returns:
-
-
-源代码
-
-```python
-def init_log(config: dict):
- """
- 在语言加载完成后执行
- Returns:
-
- """
- logger.remove()
- logger.add(sys.stdout, level=0, diagnose=False, 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")
-```
-
-
-### ***var*** `logger = loguru.logger`
-
-
-
-### ***var*** `show_icon = config.get('log_icon', True)`
-
-
-
diff --git a/docs/dev/api/message/README.md b/docs/dev/api/message/README.md
deleted file mode 100644
index 0d664851..00000000
--- a/docs/dev/api/message/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-title: liteyuki.message
-index: true
-icon: laptop-code
-category: API
----
-
diff --git a/docs/dev/api/message/event.md b/docs/dev/api/message/event.md
deleted file mode 100644
index 740ff8bd..00000000
--- a/docs/dev/api/message/event.md
+++ /dev/null
@@ -1,106 +0,0 @@
----
-title: liteyuki.message.event
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***class*** `MessageEvent`
-
-
-
-### ***def*** `__init__(self, bot_id: str, message: list[dict[str, Any]] | str, message_type: str, raw_message: str, session_id: str, session_type: str, receive_channel: str, data: Optional[dict[str, Any]]) -> None`
-
- 轻雪抽象消息事件
-
-Args:
-
-
-
- bot_id: 机器人ID
-
- message: 消息,消息段数组[{type: str, data: dict[str, Any]}]
-
- raw_message: 原始消息(通常为纯文本的格式)
-
- message_type: 消息类型(private, group, other)
-
-
-
- session_id: 会话ID(私聊通常为用户ID,群聊通常为群ID)
-
- session_type: 会话类型(private, group)
-
- receive_channel: 接收频道(用于回复消息)
-
-
-
- data: 附加数据
-
-
-源代码
-
-```python
-def __init__(self, bot_id: str, message: list[dict[str, Any]] | str, message_type: str, raw_message: str, session_id: str, session_type: str, receive_channel: str, data: Optional[dict[str, Any]]=None):
- """
- 轻雪抽象消息事件
- Args:
-
- bot_id: 机器人ID
- message: 消息,消息段数组[{type: str, data: dict[str, Any]}]
- raw_message: 原始消息(通常为纯文本的格式)
- message_type: 消息类型(private, group, other)
-
- session_id: 会话ID(私聊通常为用户ID,群聊通常为群ID)
- session_type: 会话类型(private, group)
- receive_channel: 接收频道(用于回复消息)
-
- data: 附加数据
- """
- if data is None:
- data = {}
- self.message_type = message_type
- self.data = data
- self.bot_id = bot_id
- self.message = message
- self.raw_message = raw_message
- self.session_id = session_id
- self.session_type = session_type
- self.receive_channel = receive_channel
-```
-
-
-### ***def*** `reply(self, message: str | dict[str, Any]) -> None`
-
- 回复消息
-
-Args:
-
- message:
-
-Returns:
-
-
-源代码
-
-```python
-def reply(self, message: str | dict[str, Any]):
- """
- 回复消息
- Args:
- message:
- Returns:
- """
- reply_event = MessageEvent(message_type=self.session_type, message=message, raw_message='', data={'message': message}, bot_id=self.bot_id, session_id=self.session_id, session_type=self.session_type, receive_channel='_')
- shared_memory.publish(self.receive_channel, reply_event)
-```
-
-
-### ***var*** `reply_event = MessageEvent(message_type=self.session_type, message=message, raw_message='', data={'message': message}, bot_id=self.bot_id, session_id=self.session_id, session_type=self.session_type, receive_channel='_')`
-
-
-
-### ***var*** `data = {}`
-
-
-
diff --git a/docs/dev/api/message/matcher.md b/docs/dev/api/message/matcher.md
deleted file mode 100644
index 4a6341b6..00000000
--- a/docs/dev/api/message/matcher.md
+++ /dev/null
@@ -1,71 +0,0 @@
----
-title: liteyuki.message.matcher
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***class*** `Matcher`
-
-
-
-### ***def*** `__init__(self, rule: Rule, priority: int, block: bool) -> None`
-
- 匹配器
-
-Args:
-
- rule: 规则
-
- priority: 优先级 >= 0
-
- block: 是否阻断后续优先级更低的匹配器
-
-
-源代码
-
-```python
-def __init__(self, rule: Rule, priority: int, block: bool):
- """
- 匹配器
- Args:
- rule: 规则
- priority: 优先级 >= 0
- block: 是否阻断后续优先级更低的匹配器
- """
- self.rule = rule
- self.priority = priority
- self.block = block
- self.handlers: list[EventHandler] = []
-```
-
-
-### ***def*** `handle(self, handler: EventHandler) -> EventHandler`
-
- 添加处理函数,装饰器
-
-Args:
-
- handler:
-
-Returns:
-
- EventHandler
-
-
-源代码
-
-```python
-def handle(self, handler: EventHandler) -> EventHandler:
- """
- 添加处理函数,装饰器
- Args:
- handler:
- Returns:
- EventHandler
- """
- self.handlers.append(handler)
- return handler
-```
-
-
diff --git a/docs/dev/api/message/on.md b/docs/dev/api/message/on.md
deleted file mode 100644
index 4f3c7230..00000000
--- a/docs/dev/api/message/on.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-title: liteyuki.message.on
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***def*** `on_message(rule: Rule, priority: int, block: bool) -> Matcher`
-
-
-
-
-源代码
-
-```python
-def on_message(rule: Rule=Rule(), priority: int=0, block: bool=True) -> Matcher:
- matcher = Matcher(rule, priority, block)
- for i, m in enumerate(_matcher_list):
- if m.priority < matcher.priority:
- _matcher_list.insert(i, matcher)
- break
- else:
- _matcher_list.append(matcher)
- return matcher
-```
-
-
-### ***var*** `current_priority = -1`
-
-
-
-### ***var*** `matcher = Matcher(rule, priority, block)`
-
-
-
-### ***var*** `current_priority = matcher.priority`
-
-
-
diff --git a/docs/dev/api/message/rule.md b/docs/dev/api/message/rule.md
deleted file mode 100644
index a135f740..00000000
--- a/docs/dev/api/message/rule.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: liteyuki.message.rule
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***class*** `Rule`
-
-
-
-### ***def*** `__init__(self, handler: Optional[RuleHandler]) -> None`
-
-
-
-
-源代码
-
-```python
-def __init__(self, handler: Optional[RuleHandler]=None):
- self.handler = handler
-```
-
-
diff --git a/docs/dev/api/message/session.md b/docs/dev/api/message/session.md
deleted file mode 100644
index f8fcad6f..00000000
--- a/docs/dev/api/message/session.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-title: liteyuki.message.session
-order: 1
-icon: laptop-code
-category: API
----
-
diff --git a/docs/dev/api/mkdoc.md b/docs/dev/api/mkdoc.md
deleted file mode 100644
index 802aff3c..00000000
--- a/docs/dev/api/mkdoc.md
+++ /dev/null
@@ -1,473 +0,0 @@
----
-title: liteyuki.mkdoc
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***def*** `get_relative_path(base_path: str, target_path: str) -> str`
-
-获取相对路径
-
-Args:
-
- base_path: 基础路径
-
- target_path: 目标路径
-
-
-源代码
-
-```python
-def get_relative_path(base_path: str, target_path: str) -> str:
- """
- 获取相对路径
- Args:
- base_path: 基础路径
- target_path: 目标路径
- """
- return os.path.relpath(target_path, base_path)
-```
-
-
-### ***def*** `write_to_files(file_data: dict[str, str]) -> None`
-
-输出文件
-
-Args:
-
- file_data: 文件数据 相对路径
-
-
-源代码
-
-```python
-def write_to_files(file_data: dict[str, str]):
- """
- 输出文件
- Args:
- file_data: 文件数据 相对路径
- """
- for rp, data in file_data.items():
- if not os.path.exists(os.path.dirname(rp)):
- os.makedirs(os.path.dirname(rp))
- with open(rp, 'w', encoding='utf-8') as f:
- f.write(data)
-```
-
-
-### ***def*** `get_file_list(module_folder: str) -> None`
-
-
-
-
-源代码
-
-```python
-def get_file_list(module_folder: str):
- file_list = []
- for root, dirs, files in os.walk(module_folder):
- for file in files:
- if file.endswith(('.py', '.pyi')):
- file_list.append(os.path.join(root, file))
- return file_list
-```
-
-
-### ***def*** `get_module_info_normal(file_path: str, ignore_private: bool) -> ModuleInfo`
-
-获取函数和类
-
-Args:
-
- file_path: Python 文件路径
-
- ignore_private: 忽略私有函数和类
-
-Returns:
-
- 模块信息
-
-
-源代码
-
-```python
-def get_module_info_normal(file_path: str, ignore_private: bool=True) -> ModuleInfo:
- """
- 获取函数和类
- Args:
- file_path: Python 文件路径
- ignore_private: 忽略私有函数和类
- Returns:
- 模块信息
- """
- with open(file_path, 'r', encoding='utf-8') as file:
- file_content = file.read()
- tree = ast.parse(file_content)
- dot_sep_module_path = file_path.replace(os.sep, '.').replace('.py', '').replace('.pyi', '')
- module_docstring = ast.get_docstring(tree)
- module_info = ModuleInfo(module_path=dot_sep_module_path, functions=[], classes=[], attributes=[], docstring=module_docstring if module_docstring else '')
- for node in ast.walk(tree):
- if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
- if not any((isinstance(parent, ast.ClassDef) for parent in ast.iter_child_nodes(node))) and (not ignore_private or not node.name.startswith('_')):
- if node.args.args:
- first_arg = node.args.args[0]
- if first_arg.arg in ('self', 'cls'):
- continue
- function_docstring = ast.get_docstring(node)
- func_info = FunctionInfo(name=node.name, args=[(arg.arg, ast.unparse(arg.annotation) if arg.annotation else NO_TYPE_ANY) for arg in node.args.args], return_type=ast.unparse(node.returns) if node.returns else 'None', docstring=function_docstring if function_docstring else '', type=DefType.FUNCTION, is_async=isinstance(node, ast.AsyncFunctionDef), source_code=ast.unparse(node))
- module_info.functions.append(func_info)
- elif isinstance(node, ast.ClassDef):
- class_docstring = ast.get_docstring(node)
- class_info = ClassInfo(name=node.name, docstring=class_docstring if class_docstring else '', methods=[], attributes=[], inherit=[ast.unparse(base) for base in node.bases])
- for class_node in node.body:
- if isinstance(class_node, ast.FunctionDef) and (not ignore_private or not class_node.name.startswith('_') or class_node.name == '__init__'):
- method_docstring = ast.get_docstring(class_node)
- def_type = DefType.METHOD
- if class_node.decorator_list:
- if any((isinstance(decorator, ast.Name) and decorator.id == 'staticmethod' for decorator in class_node.decorator_list)):
- def_type = DefType.STATIC_METHOD
- elif any((isinstance(decorator, ast.Name) and decorator.id == 'classmethod' for decorator in class_node.decorator_list)):
- def_type = DefType.CLASS_METHOD
- elif any((isinstance(decorator, ast.Name) and decorator.id == 'property' for decorator in class_node.decorator_list)):
- def_type = DefType.PROPERTY
- class_info.methods.append(FunctionInfo(name=class_node.name, args=[(arg.arg, ast.unparse(arg.annotation) if arg.annotation else NO_TYPE_ANY) for arg in class_node.args.args], return_type=ast.unparse(class_node.returns) if class_node.returns else 'None', docstring=method_docstring if method_docstring else '', type=def_type, is_async=isinstance(class_node, ast.AsyncFunctionDef), source_code=ast.unparse(class_node)))
- elif isinstance(class_node, ast.Assign):
- for target in class_node.targets:
- if isinstance(target, ast.Name):
- class_info.attributes.append(AttributeInfo(name=target.id, type=ast.unparse(class_node.value)))
- module_info.classes.append(class_info)
- elif isinstance(node, ast.Assign):
- if not any((isinstance(parent, (ast.ClassDef, ast.FunctionDef)) for parent in ast.iter_child_nodes(node))):
- for target in node.targets:
- if isinstance(target, ast.Name) and (not ignore_private or not target.id.startswith('_')):
- attr_type = NO_TYPE_HINT
- if isinstance(node.value, ast.AnnAssign) and node.value.annotation:
- attr_type = ast.unparse(node.value.annotation)
- module_info.attributes.append(AttributeInfo(name=target.id, type=attr_type, value=ast.unparse(node.value) if node.value else None))
- return module_info
-```
-
-
-### ***def*** `generate_markdown(module_info: ModuleInfo, front_matter: Any) -> str`
-
-生成模块的Markdown
-
-你可在此自定义生成的Markdown格式
-
-Args:
-
- module_info: 模块信息
-
- front_matter: 自定义选项title, index, icon, category
-
-Returns:
-
- Markdown 字符串
-
-
-源代码
-
-```python
-def generate_markdown(module_info: ModuleInfo, front_matter=None) -> str:
- """
- 生成模块的Markdown
- 你可在此自定义生成的Markdown格式
- Args:
- module_info: 模块信息
- front_matter: 自定义选项title, index, icon, category
- Returns:
- Markdown 字符串
- """
- content = ''
- front_matter = '---\n' + '\n'.join([f'{k}: {v}' for k, v in front_matter.items()]) + '\n---\n\n'
- content += front_matter
- for func in module_info.functions:
- args_with_type = [f'{arg[0]}: {arg[1]}' if arg[1] else arg[0] for arg in func.args]
- content += f"### ***{('async ' if func.is_async else '')}def*** `{func.name}({', '.join(args_with_type)}) -> {func.return_type}`\n\n"
- func.docstring = func.docstring.replace('\n', '\n\n')
- content += f'{func.docstring}\n\n'
- content += f'\n源代码
\n\n```python\n{func.source_code}\n```\n \n\n'
- for cls in module_info.classes:
- if cls.inherit:
- inherit = f"({', '.join(cls.inherit)})" if cls.inherit else ''
- content += f'### ***class*** `{cls.name}{inherit}`\n\n'
- else:
- content += f'### ***class*** `{cls.name}`\n\n'
- cls.docstring = cls.docstring.replace('\n', '\n\n')
- content += f'{cls.docstring}\n\n'
- for method in cls.methods:
- if method.type != DefType.METHOD:
- args_with_type = [f'{arg[0]}: {arg[1]}' if arg[1] else arg[0] for arg in method.args]
- content += f'### ***@{method.type.value}***\n'
- else:
- args_with_type = [f'{arg[0]}: {arg[1]}' if arg[1] and arg[0] != 'self' else arg[0] for arg in method.args]
- content += f"### ***{('async ' if method.is_async else '')}def*** `{method.name}({', '.join(args_with_type)}) -> {method.return_type}`\n\n"
- method.docstring = method.docstring.replace('\n', '\n\n')
- content += f' {method.docstring}\n\n'
- content += f'\n源代码
\n\n```python\n{method.source_code}\n```\n \n\n'
- for attr in cls.attributes:
- content += f'### ***attr*** `{attr.name}: {attr.type}`\n\n'
- for attr in module_info.attributes:
- if attr.type == NO_TYPE_HINT:
- content += f'### ***var*** `{attr.name} = {attr.value}`\n\n'
- else:
- content += f'### ***var*** `{attr.name}: {attr.type} = {attr.value}`\n\n'
- attr.docstring = attr.docstring.replace('\n', '\n\n')
- content += f'{attr.docstring}\n\n'
- return content
-```
-
-
-### ***def*** `generate_docs(module_folder: str, output_dir: str, with_top: bool, ignored_paths: Any) -> None`
-
-生成文档
-
-Args:
-
- module_folder: 模块文件夹
-
- output_dir: 输出文件夹
-
- with_top: 是否包含顶层文件夹 False时例如docs/api/module_a, docs/api/module_b, True时例如docs/api/module/module_a.md, docs/api/module/module_b.md
-
- ignored_paths: 忽略的路径
-
-
-源代码
-
-```python
-def generate_docs(module_folder: str, output_dir: str, with_top: bool=False, ignored_paths=None):
- """
- 生成文档
- Args:
- module_folder: 模块文件夹
- output_dir: 输出文件夹
- with_top: 是否包含顶层文件夹 False时例如docs/api/module_a, docs/api/module_b, True时例如docs/api/module/module_a.md, docs/api/module/module_b.md
- ignored_paths: 忽略的路径
- """
- if ignored_paths is None:
- ignored_paths = []
- file_data: dict[str, str] = {}
- file_list = get_file_list(module_folder)
- shutil.rmtree(output_dir, ignore_errors=True)
- os.mkdir(output_dir)
- replace_data = {'__init__': 'README', '.py': '.md'}
- for pyfile_path in file_list:
- if any((ignored_path.replace('\\', '/') in pyfile_path.replace('\\', '/') for ignored_path in ignored_paths)):
- continue
- no_module_name_pyfile_path = get_relative_path(module_folder, pyfile_path)
- rel_md_path = pyfile_path if with_top else no_module_name_pyfile_path
- for rk, rv in replace_data.items():
- rel_md_path = rel_md_path.replace(rk, rv)
- abs_md_path = os.path.join(output_dir, rel_md_path)
- module_info = get_module_info_normal(pyfile_path)
- if 'README' in abs_md_path:
- front_matter = {'title': module_info.module_path.replace('.__init__', '').replace('_', '\\n'), 'index': 'true', 'icon': 'laptop-code', 'category': 'API'}
- else:
- front_matter = {'title': module_info.module_path.replace('_', '\\n'), 'order': '1', 'icon': 'laptop-code', 'category': 'API'}
- md_content = generate_markdown(module_info, front_matter)
- print(f'Generate {pyfile_path} -> {abs_md_path}')
- file_data[abs_md_path] = md_content
- write_to_files(file_data)
-```
-
-
-### ***class*** `DefType(Enum)`
-
-
-
-### ***attr*** `FUNCTION: 'function'`
-
-### ***attr*** `METHOD: 'method'`
-
-### ***attr*** `STATIC_METHOD: 'staticmethod'`
-
-### ***attr*** `CLASS_METHOD: 'classmethod'`
-
-### ***attr*** `PROPERTY: 'property'`
-
-### ***class*** `FunctionInfo(BaseModel)`
-
-
-
-### ***class*** `AttributeInfo(BaseModel)`
-
-
-
-### ***class*** `ClassInfo(BaseModel)`
-
-
-
-### ***class*** `ModuleInfo(BaseModel)`
-
-
-
-### ***var*** `NO_TYPE_ANY = 'Any'`
-
-
-
-### ***var*** `NO_TYPE_HINT = 'NoTypeHint'`
-
-
-
-### ***var*** `FUNCTION = 'function'`
-
-
-
-### ***var*** `METHOD = 'method'`
-
-
-
-### ***var*** `STATIC_METHOD = 'staticmethod'`
-
-
-
-### ***var*** `CLASS_METHOD = 'classmethod'`
-
-
-
-### ***var*** `PROPERTY = 'property'`
-
-
-
-### ***var*** `file_list = []`
-
-
-
-### ***var*** `dot_sep_module_path = file_path.replace(os.sep, '.').replace('.py', '').replace('.pyi', '')`
-
-
-
-### ***var*** `module_docstring = ast.get_docstring(tree)`
-
-
-
-### ***var*** `module_info = ModuleInfo(module_path=dot_sep_module_path, functions=[], classes=[], attributes=[], docstring=module_docstring if module_docstring else '')`
-
-
-
-### ***var*** `content = ''`
-
-
-
-### ***var*** `front_matter = '---\n' + '\n'.join([f'{k}: {v}' for k, v in front_matter.items()]) + '\n---\n\n'`
-
-
-
-### ***var*** `file_list = get_file_list(module_folder)`
-
-
-
-### ***var*** `replace_data = {'__init__': 'README', '.py': '.md'}`
-
-
-
-### ***var*** `file_content = file.read()`
-
-
-
-### ***var*** `tree = ast.parse(file_content)`
-
-
-
-### ***var*** `args_with_type = [f'{arg[0]}: {arg[1]}' if arg[1] else arg[0] for arg in func.args]`
-
-
-
-### ***var*** `ignored_paths = []`
-
-
-
-### ***var*** `no_module_name_pyfile_path = get_relative_path(module_folder, pyfile_path)`
-
-
-
-### ***var*** `rel_md_path = pyfile_path if with_top else no_module_name_pyfile_path`
-
-
-
-### ***var*** `abs_md_path = os.path.join(output_dir, rel_md_path)`
-
-
-
-### ***var*** `module_info = get_module_info_normal(pyfile_path)`
-
-
-
-### ***var*** `md_content = generate_markdown(module_info, front_matter)`
-
-
-
-### ***var*** `inherit = f"({', '.join(cls.inherit)})" if cls.inherit else ''`
-
-
-
-### ***var*** `rel_md_path = rel_md_path.replace(rk, rv)`
-
-
-
-### ***var*** `front_matter = {'title': module_info.module_path.replace('.__init__', '').replace('_', '\\n'), 'index': 'true', 'icon': 'laptop-code', 'category': 'API'}`
-
-
-
-### ***var*** `front_matter = {'title': module_info.module_path.replace('_', '\\n'), 'order': '1', 'icon': 'laptop-code', 'category': 'API'}`
-
-
-
-### ***var*** `function_docstring = ast.get_docstring(node)`
-
-
-
-### ***var*** `func_info = FunctionInfo(name=node.name, args=[(arg.arg, ast.unparse(arg.annotation) if arg.annotation else NO_TYPE_ANY) for arg in node.args.args], return_type=ast.unparse(node.returns) if node.returns else 'None', docstring=function_docstring if function_docstring else '', type=DefType.FUNCTION, is_async=isinstance(node, ast.AsyncFunctionDef), source_code=ast.unparse(node))`
-
-
-
-### ***var*** `class_docstring = ast.get_docstring(node)`
-
-
-
-### ***var*** `class_info = ClassInfo(name=node.name, docstring=class_docstring if class_docstring else '', methods=[], attributes=[], inherit=[ast.unparse(base) for base in node.bases])`
-
-
-
-### ***var*** `args_with_type = [f'{arg[0]}: {arg[1]}' if arg[1] else arg[0] for arg in method.args]`
-
-
-
-### ***var*** `args_with_type = [f'{arg[0]}: {arg[1]}' if arg[1] and arg[0] != 'self' else arg[0] for arg in method.args]`
-
-
-
-### ***var*** `first_arg = node.args.args[0]`
-
-
-
-### ***var*** `method_docstring = ast.get_docstring(class_node)`
-
-
-
-### ***var*** `def_type = DefType.METHOD`
-
-
-
-### ***var*** `def_type = DefType.STATIC_METHOD`
-
-
-
-### ***var*** `attr_type = NO_TYPE_HINT`
-
-
-
-### ***var*** `def_type = DefType.CLASS_METHOD`
-
-
-
-### ***var*** `attr_type = ast.unparse(node.value.annotation)`
-
-
-
-### ***var*** `def_type = DefType.PROPERTY`
-
-
-
diff --git a/docs/dev/api/plugin/README.md b/docs/dev/api/plugin/README.md
deleted file mode 100644
index 6c67f485..00000000
--- a/docs/dev/api/plugin/README.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: liteyuki.plugin
-index: true
-icon: laptop-code
-category: API
----
-
-### ***def*** `get_loaded_plugins() -> dict[str, Plugin]`
-
-获取已加载的插件
-
-Returns:
-
- dict[str, Plugin]: 插件字典
-
-
-源代码
-
-```python
-def get_loaded_plugins() -> dict[str, Plugin]:
- """
- 获取已加载的插件
- Returns:
- dict[str, Plugin]: 插件字典
- """
- return _plugins
-```
-
-
diff --git a/docs/dev/api/plugin/load.md b/docs/dev/api/plugin/load.md
deleted file mode 100644
index b999f5e1..00000000
--- a/docs/dev/api/plugin/load.md
+++ /dev/null
@@ -1,199 +0,0 @@
----
-title: liteyuki.plugin.load
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***def*** `load_plugin(module_path: str | Path) -> Optional[Plugin]`
-
-加载单个插件,可以是本地插件或是通过 `pip` 安装的插件。
-
-
-
-参数:
-
- module_path: 插件名称 `path.to.your.plugin`
-
- 或插件路径 `pathlib.Path(path/to/your/plugin)`
-
-
-源代码
-
-```python
-def load_plugin(module_path: str | Path) -> Optional[Plugin]:
- """加载单个插件,可以是本地插件或是通过 `pip` 安装的插件。
-
- 参数:
- module_path: 插件名称 `path.to.your.plugin`
- 或插件路径 `pathlib.Path(path/to/your/plugin)`
- """
- module_path = path_to_module_name(Path(module_path)) if isinstance(module_path, Path) else module_path
- try:
- module = import_module(module_path)
- _plugins[module.__name__] = Plugin(name=module.__name__, module=module, module_name=module_path, metadata=module.__dict__.get('__plugin_metadata__', None))
- display_name = module.__name__.split('.')[-1]
- if module.__dict__.get('__plugin_meta__'):
- metadata: 'PluginMetadata' = module.__dict__['__plugin_meta__']
- display_name = format_display_name(f"{metadata.name}({module.__name__.split('.')[-1]})", metadata.type)
- logger.opt(colors=True).success(f'Succeeded to load liteyuki plugin "{display_name}"')
- return _plugins[module.__name__]
- except Exception as e:
- logger.opt(colors=True).success(f'Failed to load liteyuki plugin "{module_path}"')
- traceback.print_exc()
- return None
-```
-
-
-### ***def*** `load_plugins() -> set[Plugin]`
-
-导入文件夹下多个插件
-
-
-
-参数:
-
- plugin_dir: 文件夹路径
-
- ignore_warning: 是否忽略警告,通常是目录不存在或目录为空
-
-
-源代码
-
-```python
-def load_plugins(*plugin_dir: str, ignore_warning: bool=True) -> set[Plugin]:
- """导入文件夹下多个插件
-
- 参数:
- plugin_dir: 文件夹路径
- ignore_warning: 是否忽略警告,通常是目录不存在或目录为空
- """
- plugins = set()
- for dir_path in plugin_dir:
- if not os.path.exists(dir_path):
- if not ignore_warning:
- logger.warning(f"Plugins dir '{dir_path}' does not exist.")
- continue
- if not os.listdir(dir_path):
- if not ignore_warning:
- logger.warning(f"Plugins dir '{dir_path}' is empty.")
- continue
- if not os.path.isdir(dir_path):
- if not ignore_warning:
- logger.warning(f"Plugins dir '{dir_path}' is not a directory.")
- continue
- for f in os.listdir(dir_path):
- path = Path(os.path.join(dir_path, f))
- module_name = None
- if os.path.isfile(path) and f.endswith('.py') and (f != '__init__.py'):
- module_name = f'{path_to_module_name(Path(dir_path))}.{f[:-3]}'
- elif os.path.isdir(path) and os.path.exists(os.path.join(path, '__init__.py')):
- module_name = path_to_module_name(path)
- if module_name:
- load_plugin(module_name)
- if _plugins.get(module_name):
- plugins.add(_plugins[module_name])
- return plugins
-```
-
-
-### ***def*** `format_display_name(display_name: str, plugin_type: PluginType) -> str`
-
-设置插件名称颜色,根据不同类型插件设置颜色
-
-Args:
-
- display_name: 插件名称
-
- plugin_type: 插件类型
-
-
-
-Returns:
-
- str: 设置后的插件名称 name
-
-
-源代码
-
-```python
-def format_display_name(display_name: str, plugin_type: PluginType) -> str:
- """
- 设置插件名称颜色,根据不同类型插件设置颜色
- Args:
- display_name: 插件名称
- plugin_type: 插件类型
-
- Returns:
- str: 设置后的插件名称 name
- """
- color = 'y'
- match plugin_type:
- case PluginType.APPLICATION:
- color = 'm'
- case PluginType.TEST:
- color = 'g'
- case PluginType.MODULE:
- color = 'e'
- case PluginType.SERVICE:
- color = 'c'
- return f'<{color}>{display_name} [{plugin_type.name}]{color}>'
-```
-
-
-### ***var*** `module_path = path_to_module_name(Path(module_path)) if isinstance(module_path, Path) else module_path`
-
-
-
-### ***var*** `plugins = set()`
-
-
-
-### ***var*** `color = 'y'`
-
-
-
-### ***var*** `module = import_module(module_path)`
-
-
-
-### ***var*** `display_name = module.__name__.split('.')[-1]`
-
-
-
-### ***var*** `display_name = format_display_name(f"{metadata.name}({module.__name__.split('.')[-1]})", metadata.type)`
-
-
-
-### ***var*** `path = Path(os.path.join(dir_path, f))`
-
-
-
-### ***var*** `module_name = None`
-
-
-
-### ***var*** `color = 'm'`
-
-
-
-### ***var*** `color = 'g'`
-
-
-
-### ***var*** `color = 'e'`
-
-
-
-### ***var*** `color = 'c'`
-
-
-
-### ***var*** `module_name = f'{path_to_module_name(Path(dir_path))}.{f[:-3]}'`
-
-
-
-### ***var*** `module_name = path_to_module_name(path)`
-
-
-
diff --git a/docs/dev/api/plugin/manager.md b/docs/dev/api/plugin/manager.md
deleted file mode 100644
index 7d4d951c..00000000
--- a/docs/dev/api/plugin/manager.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-title: liteyuki.plugin.manager
-order: 1
-icon: laptop-code
-category: API
----
-
diff --git a/docs/dev/api/plugin/model.md b/docs/dev/api/plugin/model.md
deleted file mode 100644
index 6f986049..00000000
--- a/docs/dev/api/plugin/model.md
+++ /dev/null
@@ -1,89 +0,0 @@
----
-title: liteyuki.plugin.model
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***class*** `PluginType(Enum)`
-
-插件类型枚举值
-
-### ***attr*** `APPLICATION: 'application'`
-
-### ***attr*** `SERVICE: 'service'`
-
-### ***attr*** `MODULE: 'module'`
-
-### ***attr*** `UNCLASSIFIED: 'unclassified'`
-
-### ***attr*** `TEST: 'test'`
-
-### ***class*** `PluginMetadata(BaseModel)`
-
-轻雪插件元数据,由插件编写者提供,name为必填项
-
-Attributes:
-
-----------
-
-
-
-name: str
-
- 插件名称
-
-description: str
-
- 插件描述
-
-usage: str
-
- 插件使用方法
-
-type: str
-
- 插件类型
-
-author: str
-
- 插件作者
-
-homepage: str
-
- 插件主页
-
-extra: dict[str, Any]
-
- 额外信息
-
-### ***class*** `Plugin(BaseModel)`
-
-存储插件信息
-
-### ***attr*** `model_config: {'arbitrary_types_allowed': True}`
-
-### ***var*** `APPLICATION = 'application'`
-
-
-
-### ***var*** `SERVICE = 'service'`
-
-
-
-### ***var*** `MODULE = 'module'`
-
-
-
-### ***var*** `UNCLASSIFIED = 'unclassified'`
-
-
-
-### ***var*** `TEST = 'test'`
-
-
-
-### ***var*** `model_config = {'arbitrary_types_allowed': True}`
-
-
-
diff --git a/docs/dev/api/utils.md b/docs/dev/api/utils.md
deleted file mode 100644
index 84532f46..00000000
--- a/docs/dev/api/utils.md
+++ /dev/null
@@ -1,180 +0,0 @@
----
-title: liteyuki.utils
-order: 1
-icon: laptop-code
-category: API
----
-
-### ***def*** `is_coroutine_callable(call: Callable[..., Any]) -> bool`
-
-判断是否为协程可调用对象
-
-Args:
-
- call: 可调用对象
-
-Returns:
-
- bool: 是否为协程可调用对象
-
-
-源代码
-
-```python
-def is_coroutine_callable(call: Callable[..., Any]) -> bool:
- """
- 判断是否为协程可调用对象
- Args:
- call: 可调用对象
- Returns:
- bool: 是否为协程可调用对象
- """
- if inspect.isroutine(call):
- return inspect.iscoroutinefunction(call)
- if inspect.isclass(call):
- return False
- func_ = getattr(call, '__call__', None)
- return inspect.iscoroutinefunction(func_)
-```
-
-
-### ***def*** `run_coroutine() -> None`
-
-运行协程
-
-Args:
-
- coro:
-
-
-
-Returns:
-
-
-源代码
-
-```python
-def run_coroutine(*coro: Coroutine):
- """
- 运行协程
- Args:
- coro:
-
- Returns:
-
- """
- try:
- loop = asyncio.get_event_loop()
- if loop.is_running():
- for c in coro:
- asyncio.ensure_future(c)
- else:
- for c in coro:
- loop.run_until_complete(c)
- except RuntimeError:
- loop = asyncio.new_event_loop()
- asyncio.set_event_loop(loop)
- loop.run_until_complete(asyncio.gather(*coro))
- loop.close()
- except Exception as e:
- logger.error(f'Exception occurred: {e}')
-```
-
-
-### ***def*** `path_to_module_name(path: Path) -> str`
-
-转换路径为模块名
-
-Args:
-
- path: 路径a/b/c/d -> a.b.c.d
-
-Returns:
-
- str: 模块名
-
-
-源代码
-
-```python
-def path_to_module_name(path: Path) -> str:
- """
- 转换路径为模块名
- Args:
- path: 路径a/b/c/d -> a.b.c.d
- Returns:
- str: 模块名
- """
- rel_path = path.resolve().relative_to(Path.cwd().resolve())
- if rel_path.stem == '__init__':
- return '.'.join(rel_path.parts[:-1])
- else:
- return '.'.join(rel_path.parts[:-1] + (rel_path.stem,))
-```
-
-
-### ***def*** `async_wrapper(func: Callable[..., Any]) -> Callable[..., Coroutine]`
-
-异步包装器
-
-Args:
-
- func: Sync Callable
-
-Returns:
-
- Coroutine: Asynchronous Callable
-
-
-源代码
-
-```python
-def async_wrapper(func: Callable[..., Any]) -> Callable[..., Coroutine]:
- """
- 异步包装器
- Args:
- func: Sync Callable
- Returns:
- Coroutine: Asynchronous Callable
- """
-
- async def wrapper(*args, **kwargs):
- return func(*args, **kwargs)
- wrapper.__signature__ = inspect.signature(func)
- return wrapper
-```
-
-
-### ***async def*** `wrapper() -> None`
-
-
-
-
-源代码
-
-```python
-async def wrapper(*args, **kwargs):
- return func(*args, **kwargs)
-```
-
-
-### ***var*** `IS_MAIN_PROCESS = multiprocessing.current_process().name == 'MainProcess'`
-
-
-
-### ***var*** `func_ = getattr(call, '__call__', None)`
-
-
-
-### ***var*** `rel_path = path.resolve().relative_to(Path.cwd().resolve())`
-
-
-
-### ***var*** `loop = asyncio.get_event_loop()`
-
-
-
-### ***var*** `loop = asyncio.new_event_loop()`
-
-
-
diff --git a/docs/dev/dev_comm.md b/docs/dev/dev_comm.md
deleted file mode 100644
index b2011e35..00000000
--- a/docs/dev/dev_comm.md
+++ /dev/null
@@ -1,99 +0,0 @@
----
-title: 进程通信
-icon: exchange-alt
-order: 4
-category: 开发
----
-
-## **通道通信**
-
-### 简介
-
-轻雪运行在主进程 MainProcess 里,其他插件框架进程是伴随的子进程,因此无法通过内存共享和直接对象传递的方式进行通信,轻雪提供了一个通道`Channel`用于跨进程通信,你可以通过`Channel`发送消息给其他进程,也可以监听其他进程的消息。
-
-例如子进程接收到用户信息需要重启机器人,这时可以通过通道对主进程发送消息,主进程接收到消息后重启对应子进程。
-
-### 示例
-
-通道是全双工的,有两种接收模式,但一个通道只能使用一种,即被动模式和主动模式,被动模式由`chan.on_receive()`装饰回调函数实现,主动模式需调用`chan.receive()`实现
-
-- 创建子进程的同时会初始化一个被动通道和一个主动通道,且通道标识为`{process_name}-active`和`{process_name}-passive`,
-- 主进程中通过`get_channel`函数获取通道对象
-- 子进程中导入单例`active_channel`及`passive_channel`即可
-
-> 在轻雪插件中(主进程中)
-
-```python
-import asyncio
-
-from liteyuki.comm import get_channel, Channel
-from liteyuki import get_bot
-
-# get_channel函数获取通道对象,参数为调用set_channel时的通道标识
-channel_passive = get_channel("nonebot-passive") # 获取被动通道
-channel_active = get_channel("nonebot-active") # 获取主动通道
-liteyuki_bot = get_bot()
-
-
-# 注册一个函数在轻雪启动后运行
-@liteyuki_bot.on_after_start
-async def send_data():
- while True:
- channel_passive.send("I am liteyuki main process passive")
- channel_active.send("I am liteyuki main process active")
- await asyncio.sleep(3) # 每3秒发送一次消息
-```
-
-> 在子进程中(例如NoneBot插件中)
-
-```python
-from nonebot import get_driver
-from liteyuki.comm import active_channel, passive_channel # 子进程中获取通道直接导入进程全局单例即可
-from liteyuki.log import logger
-
-driver = get_driver()
-
-
-# 被动模式,通过装饰器注册一个函数在接收到消息时运行,每次接收到字符串数据时都会运行
-@passive_channel.on_receive(filter_func=lambda data: isinstance(data, str))
-async def on_passive_receive(data):
- logger.info(f"Passive receive: {data}")
-
-
-# 注册一个函数在NoneBot启动后运行
-@driver.on_startup
-def on_startup():
- while True:
- data = active_channel.receive()
- logger.info(f"Active receive: {data}")
-```
-
-> 启动后控制台输出
-
-```log
-0000-00-00 00:00:00 [ℹ️信息] Passive receive: I am liteyuki main process passive
-0000-00-00 00:00:00 [ℹ️信息] Active receive: I am liteyuki main process active
-0000-00-00 00:00:03 [ℹ️信息] Passive receive: I am liteyuki main process passive
-0000-00-00 00:00:03 [ℹ️信息] Active receive: I am liteyuki main process active
-...
-```
-
-## **共享内存通信**
-
-### 简介
-
-- 相比于普通进程通信,内存共享使得代码编写更加简洁,轻雪框架提供了一个内存共享通信的接口,你可以通过`storage`模块实现内存共享通信,该模块封装通道实现
-- 内存共享是线程安全的,你可以在多个线程中读写共享内存,线程锁会自动保护共享内存的读写操作
-
-### 示例
-
-> 在任意进程中均可使用
-
-```python
-from liteyuki.comm.storage import shared_memory
-
-shared_memory.set("key", "value") # 设置共享内存
-value = shared_memory.get("key") # 获取共享内存
-```
-
-源代码:[liteyuki/comm/storage.py](https://github.com/LiteyukiStudio/LiteyukiBot/blob/main/liteyuki/comm/storage.py)
diff --git a/docs/dev/dev_lyfunc.md b/docs/dev/dev_lyfunc.md
deleted file mode 100644
index db33a2db..00000000
--- a/docs/dev/dev_lyfunc.md
+++ /dev/null
@@ -1,74 +0,0 @@
----
-title: 轻雪函数
-icon: code
-order: 2
-category: 开发
----
-
-## **轻雪函数**
-
-轻雪函数 Liteyuki Function 是轻雪的一个功能,它允许你在轻雪中运行一些自定义的由数据驱动的命令,类似于Minecraft的mcfunction,属于资源包的一部分,但需单独起篇幅.
-
-### **函数文件**
-
-函数文件放在资源包的`functions`目录下,文件名以`.mcfunction` `.lyfunction` `.lyf`结尾,例如`test.mcfunction`,文件内容为一系列的命令,每行一个命令,支持单行注释`#`(编辑时的语法高亮可采取`shell`格式),例如:
-
-```shell
-# 在发信器输出"hello world"
-cmd echo hello world
-
-# 如果你想同时输出多行内容可以尝试换行符(Python格式)
-cmd echo hello world\nLiteyuki bot
-```
-
-也支持句末注释,例如:
-```shell
-cmd echo hello world # 输出"hello world"
-```
-
-### **命令文档**
-
-```shell
-var [var2=value2] ... # 定义变量
-cmd # 在设备上执行命令
-api [var=value...] # 调用Bot API
-function # 调用函数,可递归
-sleep