diff --git a/addons/dashboard/helper.py b/addons/dashboard/helper.py index 0aeac5613..c46e2ecce 100644 --- a/addons/dashboard/helper.py +++ b/addons/dashboard/helper.py @@ -7,6 +7,14 @@ from util.cmd_config import CmdConfig from dataclasses import dataclass import sys import os +import threading +import time + + +def shutdown_bot(delay_s: int): + time.sleep(delay_s) + py = sys.executable + os.execl(py, py, *sys.argv) @dataclass class DashBoardConfig(): @@ -36,8 +44,7 @@ class DashBoardHelper(): self.save_config(post_configs) self.parse_default_config(self.dashboard_data, self.cc.get_all()) # 重启 - py = sys.executable - os.execl(py, py, *sys.argv) + threading.Thread(target=shutdown_bot, args=(2,), daemon=True).start() except Exception as e: gu.log(f"在保存配置时发生错误:{e}", gu.LEVEL_ERROR, tag="可视化面板") raise e diff --git a/addons/dashboard/server.py b/addons/dashboard/server.py index 8733c3374..128be13bf 100644 --- a/addons/dashboard/server.py +++ b/addons/dashboard/server.py @@ -1,7 +1,10 @@ from flask import Flask, request +from flask.logging import default_handler +from werkzeug.serving import make_server import datetime from util import general_utils as gu from dataclasses import dataclass +import logging @dataclass class DashBoardData(): @@ -19,6 +22,8 @@ class AstrBotDashBoard(): def __init__(self, dashboard_data: DashBoardData): self.dashboard_data = dashboard_data self.dashboard_be = Flask(__name__) + log = logging.getLogger('werkzeug') + log.setLevel(logging.ERROR) self.funcs = {} @self.dashboard_be.get("/stats") @@ -27,7 +32,7 @@ class AstrBotDashBoard(): status="success", message="", data=self.dashboard_data.stats - ).dict() + ).__dict__ @self.dashboard_be.get("/configs") def get_configs(): @@ -44,7 +49,7 @@ class AstrBotDashBoard(): self.funcs["post_configs"](post_configs) return Response( status="success", - message="保存成功~ 机器人正在重启以应用新的配置。", + message="保存成功~ 机器人将在 2 秒内重启以应用新的配置。", data=None ).__dict__ except Exception as e: @@ -70,4 +75,6 @@ class AstrBotDashBoard(): def run(self): gu.log(f"\n\n==================\n您可以访问:\n\thttp://localhost:6185/\n来登录可视化面板。\n==================\n\n", tag="可视化面板") - self.dashboard_be.run(host="0.0.0.0", port=6185) + # self.dashboard_be.run(host="0.0.0.0", port=6185) + http_server = make_server('0.0.0.0', 6185, self.dashboard_be) + http_server.serve_forever() diff --git a/cores/monitor/perf.py b/cores/monitor/perf.py new file mode 100644 index 000000000..e9388be64 --- /dev/null +++ b/cores/monitor/perf.py @@ -0,0 +1,21 @@ +''' +监测机器性能 +- Bot 内存使用量 +- CPU 占用率 +''' + +import psutil +from cores.qqbot.global_object import GlobalObject +import time + +def run_monitor(global_object: GlobalObject): + '''运行监测''' + while True: + stat = global_object.dashboard_data.stats + # 程序占用的内存大小 + mem = psutil.Process().memory_info().rss / 1024 / 1024 # MB + stat['sys_perf'] = { + 'memory': mem, + 'cpu': psutil.cpu_percent() + } + time.sleep(30) \ No newline at end of file diff --git a/cores/qqbot/core.py b/cores/qqbot/core.py index ef0fa558b..fb8de10a3 100644 --- a/cores/qqbot/core.py +++ b/cores/qqbot/core.py @@ -41,6 +41,7 @@ from . global_object import GlobalObject from typing import Union, Callable from addons.dashboard.helper import DashBoardHelper from addons.dashboard.server import DashBoardData +from cores.monitor.perf import run_monitor # 缓存的会话 session_dict = {} @@ -407,7 +408,6 @@ def initBot(cfg, prov): "name": "default", "prompt": default_personality_str, } - # 初始化dashboard _global_object.dashboard_data = DashBoardData( stats={}, @@ -418,6 +418,9 @@ def initBot(cfg, prov): dashboard_thread = threading.Thread(target=dashboard_helper.run, daemon=True) dashboard_thread.start() + # 运行 monitor + threading.Thread(target=run_monitor, args=(_global_object,), daemon=False).start() + gu.log("🎉 项目启动完成。") # asyncio.get_event_loop().run_until_complete(cli()) diff --git a/cores/qqbot/global_object.py b/cores/qqbot/global_object.py index 8e268ff71..4b660ff8e 100644 --- a/cores/qqbot/global_object.py +++ b/cores/qqbot/global_object.py @@ -29,6 +29,7 @@ class GlobalObject: platform_qqchan: QQChan default_personality: dict dashboard_data: DashBoardData + stat: dict def __init__(self): self.nick = None # gocq 的昵称 @@ -44,6 +45,8 @@ class GlobalObject: self.platform_qqchan = None self.default_personality = None self.dashboard_data = None + self.stat = {} + class AstrMessageEvent(): message_str: str # 纯消息字符串