2024-08-10 22:25:41 +08:00
import asyncio
2024-08-16 23:43:43 +08:00
import atexit
2024-08-10 22:25:41 +08:00
import os
import platform
2024-08-16 23:43:43 +08:00
import signal
2024-08-10 22:25:41 +08:00
import sys
2024-08-08 18:06:03 +08:00
import threading
2024-07-27 10:12:45 +08:00
import time
2024-08-15 16:40:29 +08:00
from typing import Any , Optional
2024-07-24 02:36:46 +08:00
2024-08-31 19:51:34 +08:00
from liteyuki . bot . lifespan import ( LIFESPAN_FUNC , Lifespan , PROCESS_LIFESPAN_FUNC )
2024-08-17 23:46:43 +08:00
from liteyuki . comm . channel import get_channel
2024-07-31 02:28:25 +08:00
from liteyuki . core . manager import ProcessManager
from liteyuki . log import init_log , logger
2024-08-18 04:37:58 +08:00
from liteyuki . plugin import load_plugin
2024-08-18 01:25:11 +08:00
from liteyuki . utils import IS_MAIN_PROCESS
2024-07-24 02:36:46 +08:00
__all__ = [
" LiteyukiBot " ,
2024-08-12 02:40:51 +08:00
" get_bot " ,
" get_config " ,
2024-08-12 05:26:36 +08:00
" get_config_with_compat " ,
2024-07-24 02:36:46 +08:00
]
class LiteyukiBot :
2024-08-31 19:51:34 +08:00
def __init__ ( self , * * kwargs ) - > None :
2024-08-17 23:46:43 +08:00
"""
初始化轻雪实例
Args :
* * kwargs : 配置
"""
""" 常规操作 """
2024-08-12 04:45:59 +08:00
print_logo ( )
2024-07-24 02:36:46 +08:00
global _BOT_INSTANCE
_BOT_INSTANCE = self # 引用
2024-08-12 02:40:51 +08:00
2024-08-17 23:46:43 +08:00
""" 配置 """
2024-07-31 02:28:25 +08:00
self . config : dict [ str , Any ] = kwargs
2024-08-17 23:46:43 +08:00
""" 初始化 """
2024-08-12 02:40:51 +08:00
self . init ( * * self . config ) # 初始化
2024-08-12 04:45:59 +08:00
logger . info ( " Liteyuki is initializing... " )
2024-08-17 23:46:43 +08:00
""" 生命周期管理 """
2024-08-12 04:45:59 +08:00
self . lifespan = Lifespan ( )
2024-08-17 23:46:43 +08:00
self . process_manager : ProcessManager = ProcessManager ( lifespan = self . lifespan )
2024-08-10 22:25:41 +08:00
2024-08-17 23:46:43 +08:00
""" 事件循环 """
2024-08-08 18:06:03 +08:00
self . loop = asyncio . new_event_loop ( )
asyncio . set_event_loop ( self . loop )
2024-08-12 02:40:51 +08:00
self . stop_event = threading . Event ( )
2024-08-10 22:25:41 +08:00
self . call_restart_count = 0
2024-07-31 02:28:25 +08:00
2024-08-18 04:37:58 +08:00
""" 加载插件加载器 """
load_plugin ( " liteyuki.plugins.plugin_loader " ) # 加载轻雪插件
2024-08-08 18:06:03 +08:00
2024-08-17 23:46:43 +08:00
""" 信号处理 """
2024-08-16 23:43:43 +08:00
signal . signal ( signal . SIGINT , self . _handle_exit )
signal . signal ( signal . SIGTERM , self . _handle_exit )
atexit . register ( self . process_manager . terminate_all ) # 注册退出时的函数
2024-08-29 13:50:12 +08:00
async def _run ( self ) :
2024-08-12 02:40:51 +08:00
"""
启动逻辑
"""
2024-08-29 13:50:12 +08:00
await self . lifespan . before_start ( ) # 启动前钩子
await self . process_manager . start_all ( )
await self . lifespan . after_start ( ) # 启动后钩子
await self . keep_alive ( )
2024-08-15 17:32:02 +08:00
2024-08-29 13:50:12 +08:00
def run ( self ) :
"""
外部启动接口
"""
try :
asyncio . run ( self . _run ( ) )
except KeyboardInterrupt :
logger . info ( " Liteyuki is stopping... " )
async def keep_alive ( self ) :
2024-08-15 17:32:02 +08:00
"""
保持轻雪运行
"""
try :
while not self . stop_event . is_set ( ) :
2024-08-16 23:43:43 +08:00
time . sleep ( 0.5 )
2024-08-15 17:32:02 +08:00
except KeyboardInterrupt :
logger . info ( " Liteyuki is stopping... " )
self . stop ( )
2024-08-16 23:43:43 +08:00
def _handle_exit ( self , signum , frame ) :
"""
2024-08-31 19:51:34 +08:00
@litedoc - hide
2024-08-16 23:43:43 +08:00
信号处理
Args :
2024-08-31 19:51:34 +08:00
signum : 信号
frame : 帧
2024-08-16 23:43:43 +08:00
"""
logger . info ( " Received signal, stopping all processes. " )
self . stop ( )
sys . exit ( 0 )
2024-08-10 22:25:41 +08:00
def restart ( self , delay : int = 0 ) :
"""
重启轻雪本体
2024-08-31 19:51:34 +08:00
Args :
delay ( [ ` int ` ] ( https % 3 A / / docs . python . org / 3 / library / functions . html #int), optional): 延迟重启时间. Defaults to 0.
2024-08-10 22:25:41 +08:00
"""
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 ) :
2024-07-24 02:36:46 +08:00
"""
停止轻雪
2024-07-31 02:28:25 +08:00
Args :
2024-08-31 19:51:34 +08:00
name ( [ ` Optional ` ] ( https % 3 A / / docs . python . org / 3 / library / typing . html #typing.Optional)[[`str`](https%3A//docs.python.org/3/library/stdtypes.html#str)]): 进程名. Defaults to None.
2024-07-24 02:36:46 +08:00
Returns :
"""
2024-08-12 04:45:59 +08:00
if name is not None :
2024-08-12 02:40:51 +08:00
chan_active = get_channel ( f " { name } -active " )
chan_active . send ( 1 )
2024-07-31 02:28:25 +08:00
else :
2024-08-12 02:40:51 +08:00
for process_name in self . process_manager . processes :
chan_active = get_channel ( f " { process_name } -active " )
chan_active . send ( 1 )
2024-07-24 02:36:46 +08:00
def init ( self , * args , * * kwargs ) :
"""
初始化轻雪 , 自动调用
2024-08-31 19:51:34 +08:00
Args :
* args : 参数
* * kwargs : 关键字参数
2024-07-24 02:36:46 +08:00
"""
self . init_logger ( )
def init_logger ( self ) :
2024-08-31 19:51:34 +08:00
"""
初始化日志
"""
2024-07-27 10:12:45 +08:00
init_log ( config = self . config )
2024-07-24 02:36:46 +08:00
2024-08-15 16:40:29 +08:00
def stop ( self ) :
"""
停止轻雪
"""
self . stop_event . set ( )
self . loop . stop ( )
2024-08-31 19:51:34 +08:00
def on_before_start ( self , func : LIFESPAN_FUNC ) - > LIFESPAN_FUNC :
2024-07-24 02:36:46 +08:00
"""
注册启动前的函数
Args :
2024-08-31 19:51:34 +08:00
func ( [ ` LIFESPAN_FUNC ` ] ( . / lifespan #var-lifespan-func)): 生命周期函数
2024-07-24 02:36:46 +08:00
Returns :
2024-08-31 19:51:34 +08:00
[ ` LIFESPAN_FUNC ` ] ( . / lifespan #var-lifespan-func): 生命周期函数
2024-07-24 02:36:46 +08:00
"""
return self . lifespan . on_before_start ( func )
def on_after_start ( self , func : LIFESPAN_FUNC ) :
"""
注册启动后的函数
Args :
2024-08-31 19:51:34 +08:00
func ( [ ` LIFESPAN_FUNC ` ] ( . / lifespan #var-lifespan-func)): 生命周期函数
2024-07-24 02:36:46 +08:00
Returns :
2024-08-31 19:51:34 +08:00
[ ` LIFESPAN_FUNC ` ] ( . / lifespan #var-lifespan-func): 生命周期函数
2024-07-24 02:36:46 +08:00
"""
return self . lifespan . on_after_start ( func )
2024-08-12 04:45:59 +08:00
def on_after_shutdown ( self , func : LIFESPAN_FUNC ) :
2024-07-24 02:36:46 +08:00
"""
2024-08-12 04:45:59 +08:00
注册停止后的函数 : 未实现
2024-07-24 02:36:46 +08:00
Args :
2024-08-31 19:51:34 +08:00
func ( [ ` LIFESPAN_FUNC ` ] ( . / lifespan #var-lifespan-func)): 生命周期函数
2024-07-24 02:36:46 +08:00
Returns :
2024-08-31 19:51:34 +08:00
[ ` LIFESPAN_FUNC ` ] ( . / lifespan #var-lifespan-func): 生命周期函数
2024-07-24 02:36:46 +08:00
"""
2024-08-12 04:45:59 +08:00
return self . lifespan . on_after_shutdown ( func )
2024-07-24 02:36:46 +08:00
2024-08-31 19:51:34 +08:00
def on_before_process_shutdown ( self , func : PROCESS_LIFESPAN_FUNC ) :
2024-07-24 02:36:46 +08:00
"""
2024-08-12 04:45:59 +08:00
注册进程停止前的函数 , 为子进程停止时调用
2024-07-24 02:36:46 +08:00
Args :
2024-08-31 19:51:34 +08:00
func ( [ ` PROCESS_LIFESPAN_FUNC ` ] ( . / lifespan #var-process-lifespan-func)): 生命周期函数
2024-07-24 02:36:46 +08:00
Returns :
2024-08-31 19:51:34 +08:00
[ ` PROCESS_LIFESPAN_FUNC ` ] ( . / lifespan #var-process-lifespan-func): 生命周期函数
2024-07-24 02:36:46 +08:00
"""
2024-08-12 04:45:59 +08:00
return self . lifespan . on_before_process_shutdown ( func )
2024-07-24 02:36:46 +08:00
2024-08-31 19:51:34 +08:00
def on_before_process_restart ( self , func : PROCESS_LIFESPAN_FUNC ) - > PROCESS_LIFESPAN_FUNC :
2024-07-24 02:36:46 +08:00
"""
2024-08-12 04:45:59 +08:00
注册进程重启前的函数 , 为子进程重启时调用
2024-07-24 02:36:46 +08:00
Args :
2024-08-31 19:51:34 +08:00
func ( [ ` PROCESS_LIFESPAN_FUNC ` ] ( . / lifespan #var-process-lifespan-func)): 生命周期函数
2024-07-24 02:36:46 +08:00
Returns :
2024-08-31 19:51:34 +08:00
[ ` PROCESS_LIFESPAN_FUNC ` ] ( . / lifespan #var-process-lifespan-func): 生命周期函数
2024-07-24 02:36:46 +08:00
"""
2024-08-12 04:45:59 +08:00
return self . lifespan . on_before_process_restart ( func )
2024-07-24 02:36:46 +08:00
def on_after_restart ( self , func : LIFESPAN_FUNC ) :
"""
注册重启后的函数 : 未实现
Args :
2024-08-31 19:51:34 +08:00
func ( [ ` LIFESPAN_FUNC ` ] ( . / lifespan #var-lifespan-func)): 生命周期函数
2024-07-24 02:36:46 +08:00
Returns :
2024-08-31 19:51:34 +08:00
[ ` LIFESPAN_FUNC ` ] ( . / lifespan #var-lifespan-func): 生命周期函数
2024-07-24 02:36:46 +08:00
"""
return self . lifespan . on_after_restart ( func )
2024-08-17 23:46:43 +08:00
_BOT_INSTANCE : LiteyukiBot
2024-07-24 02:36:46 +08:00
2024-08-17 23:46:43 +08:00
def get_bot ( ) - > LiteyukiBot :
2024-07-24 02:36:46 +08:00
"""
获取轻雪实例
Returns :
2024-08-31 19:51:34 +08:00
[ ` LiteyukiBot ` ] ( #class-liteyukibot): 轻雪实例
2024-07-24 02:36:46 +08:00
"""
2024-08-17 23:46:43 +08:00
2024-07-31 02:28:25 +08:00
if IS_MAIN_PROCESS :
2024-08-12 04:45:59 +08:00
if _BOT_INSTANCE is None :
raise RuntimeError ( " Liteyuki instance not initialized. " )
2024-07-31 02:28:25 +08:00
return _BOT_INSTANCE
else :
2024-08-12 04:45:59 +08:00
raise RuntimeError ( " Can ' t get bot instance in sub process. " )
2024-08-12 02:40:51 +08:00
2024-08-17 23:46:43 +08:00
def get_config ( key : str , default : Any = None ) - > Any :
2024-08-12 02:40:51 +08:00
"""
获取配置
Args :
2024-08-31 19:51:34 +08:00
key ( [ ` str ` ] ( https % 3 A / / docs . python . org / 3 / library / stdtypes . html #str)): 配置键
default ( [ ` Any ` ] ( https % 3 A / / docs . python . org / 3 / library / functions . html #any), optional): 默认值. Defaults to None.
2024-08-12 02:40:51 +08:00
Returns :
2024-08-31 19:51:34 +08:00
[ ` Any ` ] ( https % 3 A / / docs . python . org / 3 / library / functions . html #any): 配置值
2024-08-12 02:40:51 +08:00
"""
2024-08-12 04:45:59 +08:00
return get_bot ( ) . config . get ( key , default )
2024-08-12 02:40:51 +08:00
def get_config_with_compat ( key : str , compat_keys : tuple [ str ] , default : Any = None ) - > Any :
"""
获取配置 , 兼容旧版本
Args :
2024-08-31 19:51:34 +08:00
key ( [ ` str ` ] ( https % 3 A / / docs . python . org / 3 / library / stdtypes . html #str)): 配置键
compat_keys ( [ ` tuple ` ] ( https % 3 A / / docs . python . org / 3 / library / stdtypes . html #tuple)[`str`](https%3A//docs.python.org/3/library/stdtypes.html#str)): 兼容键
default ( [ ` Any ` ] ( https % 3 A / / docs . python . org / 3 / library / functions . html #any), optional): 默认值. Defaults to None.
2024-08-12 02:40:51 +08:00
Returns :
2024-08-31 19:51:34 +08:00
[ ` Any ` ] ( https % 3 A / / docs . python . org / 3 / library / functions . html #any): 配置值
2024-08-12 02:40:51 +08:00
"""
2024-08-12 04:45:59 +08:00
if key in get_bot ( ) . config :
return get_bot ( ) . config [ key ]
2024-08-12 02:40:51 +08:00
for compat_key in compat_keys :
2024-08-12 04:45:59 +08:00
if compat_key in get_bot ( ) . config :
2024-08-16 22:53:54 +08:00
logger . warning ( f " Config key \" { compat_key } \" will be deprecated, use \" { key } \" instead. " )
2024-08-12 04:45:59 +08:00
return get_bot ( ) . config [ compat_key ]
2024-08-12 02:40:51 +08:00
return default
2024-08-12 04:45:59 +08:00
def print_logo ( ) :
2024-08-31 19:51:34 +08:00
""" @litedoc-hide """
2024-08-12 04:45:59 +08:00
print ( " \033 [34m " + r """
__ ______ ________ ________ __ __ __ __ __ __ ______
/ | / | / | / | / \ / | / | / | / | / | / |
$ $ | $ $ $ $ $ $ / $ $ $ $ $ $ $ $ / $ $ $ $ $ $ $ $ / $ $ \ / $ $ / $ $ | $ $ | $ $ | / $ $ / $ $ $ $ $ $ /
$ $ | $ $ | $ $ | $ $ | __ $ $ \/ $ $ / $ $ | $ $ | $ $ | / $ $ / $ $ |
$ $ | $ $ | $ $ | $ $ | $ $ $ $ / $ $ | $ $ | $ $ $ $ < $ $ |
$ $ | $ $ | $ $ | $ $ $ $ $ / $ $ $ $ / $ $ | $ $ | $ $ $ $ $ \ $ $ |
$ $ | _____ _ $ $ | _ $ $ | $ $ | _____ $ $ | $ $ \__ $ $ | $ $ | $ $ \ _ $ $ | _
$ $ | / $ $ | $ $ | $ $ | $ $ | $ $ $ $ / $ $ | $ $ | / $ $ |
$ $ $ $ $ $ $ $ / $ $ $ $ $ $ / $ $ / $ $ $ $ $ $ $ $ / $ $ / $ $ $ $ $ $ / $ $ / $ $ / $ $ $ $ $ $ /
""" + " \033 [0m " )