From c9973713fccae3dc57a71112b71e005a0b2e0146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=A8=E5=AD=90?= <113816301+liyihao1110@users.noreply.github.com> Date: Wed, 19 Feb 2025 00:05:20 +0800 Subject: [PATCH] =?UTF-8?q?refactor(conn):=20=E9=87=8D=E6=9E=84=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E6=A8=A1=E5=9D=97=E5=B9=B6=E7=A7=BB=E9=99=A4=20HTTP?= =?UTF-8?q?=20=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除了 gateway.py 和 http.py 文件 - 新增 wsroute.py 文件,合并并优化 WebSocket 相关功能 - 移除了 BotAPI 和 BotClient 中与 HTTP 相关的代码 - 更新了配置文件结构,删除了 HTTP URI 相关内容 --- ncatbot/conn/connect.py | 57 ++++++++++++++++++++++ ncatbot/conn/gateway.py | 65 ------------------------- ncatbot/conn/http.py | 103 ---------------------------------------- ncatbot/conn/wsroute.py | 55 +++++++++++++++++++++ ncatbot/core/api.py | 12 +++-- ncatbot/core/client.py | 26 ++-------- ncatbot/utils/config.py | 22 +-------- 7 files changed, 125 insertions(+), 215 deletions(-) create mode 100644 ncatbot/conn/connect.py delete mode 100644 ncatbot/conn/gateway.py delete mode 100644 ncatbot/conn/http.py create mode 100644 ncatbot/conn/wsroute.py diff --git a/ncatbot/conn/connect.py b/ncatbot/conn/connect.py new file mode 100644 index 0000000..2f593fd --- /dev/null +++ b/ncatbot/conn/connect.py @@ -0,0 +1,57 @@ +import asyncio +import json + +import websockets + +from ncatbot.utils.config import config +from ncatbot.utils.logger import get_log + +_log = get_log() + + +class Websocket: + def __init__(self, client): + self.client = client + self._websocket_uri = config.ws_uri + "/event" + self._header = {"Content-Type": "application/json","Authorization": f"Bearer {config.token}"} if config.token else {"Content-Type": "application/json"} + + async def on_message(self, message: dict): + if message["post_type"] == "message" or message["post_type"] == "message_sent": + if message["message_type"] == "group": + asyncio.create_task(self.client.handle_group_event(message)) + elif message["message_type"] == "private": + asyncio.create_task(self.client.handle_private_event(message)) + else: + _log.error("Unknown error: Unrecognized message type!Please check log info!") and _log.debug(message) + elif message["post_type"] == "notice": + asyncio.create_task(self.client.handle_notice_event(message)) + elif message["post_type"] == "request": + asyncio.create_task(self.client.handle_request_event(message)) + elif message["post_type"] == "meta_event": + if message["meta_event_type"] == "lifecycle": + _log.info(f"机器人 {message.get('self_id')} 成功启动") + else: + _log.debug(message) + else: + _log.error("Unknown error: Unrecognized message type!Please check log info!") and _log.debug(message) + + async def on_error(self, error): + _log.error(f"WebSocket 连接错误: {error}") + + async def on_close(self): + _log.info("WebSocket 连接已关闭") + + async def on_connect(self): + async with websockets.connect(uri=self._websocket_uri, extra_headers=self._header) as ws: + # 我发现你们在client.py中已经进行了websocket连接的测试,故删除了此处不必要的错误处理。 + while True: + try: + message = await ws.recv() + message = json.loads(message) + await self.on_message(message) + # 这里的错误处理没有进行细分,我觉得没有很大的必要,报错的可能性不大,如果你对websocket了解很深,请完善此部分。 + except Exception as e: + await self.on_error(e) + break + await self.on_close() + diff --git a/ncatbot/conn/gateway.py b/ncatbot/conn/gateway.py deleted file mode 100644 index 2ebec77..0000000 --- a/ncatbot/conn/gateway.py +++ /dev/null @@ -1,65 +0,0 @@ -import asyncio -import json - -import websockets - -from ncatbot.utils.config import config -from ncatbot.utils.logger import get_log - -_log = get_log("ncatbot") - - -class Websocket: - def __init__(self, client, config=None): - self.client = client - - async def receive(self, message): - msg = json.loads(message) - if msg["post_type"] == "message" or msg["post_type"] == "message_sent": - if msg["message_type"] == "group": - asyncio.create_task(self.client.handle_group_event(msg)) - elif msg["message_type"] == "private": - asyncio.create_task(self.client.handle_private_event(msg)) - else: - _log.error("这个报错说明message_type不属于group,private\n" + str(msg)) - elif msg["post_type"] == "notice": - asyncio.create_task(self.client.handle_notice_event(msg)) - elif msg["post_type"] == "request": - asyncio.create_task(self.client.handle_request_event(msg)) - elif msg["post_type"] == "meta_event": - if msg["meta_event_type"] == "lifecycle": - _log.info(f"机器人 {msg.get('self_id')} 成功启动") - else: - pass - else: - _log.error("这是一个错误,请反馈给开发者\n" + str(msg)) - - async def ws_connect(self): - try: - async with websockets.connect( - uri=config.ws_uri + "/event", - extra_headers=( - { - "Content-Type": "application/json", - "Authorization": f"Bearer {config.token}", - } - if config.token - else {"Content-Type": "application/json"} - ), - ) as ws: - try: - _log.info("websocket连接已建立") - while True: - message = await ws.recv() - try: - await self.receive( - message - ) # 捕获receive内部的异常,不影响程序持续运行 - except Exception as e: - _log.error(f"处理消息时发生错误: {e}") - except Exception as e: - _log.error(f"WebSocket 接收消息异常: {e}") - raise e - except Exception as e: - _log.error(f"WebSocket 连接错误: {e}") - raise e diff --git a/ncatbot/conn/http.py b/ncatbot/conn/http.py deleted file mode 100644 index 3befdd8..0000000 --- a/ncatbot/conn/http.py +++ /dev/null @@ -1,103 +0,0 @@ -import datetime -import json as j - -import httpx -import websockets - -from ncatbot.utils.config import config - - -async def check_websocket(uri): - """ - 检查指定的 WebSocket uri 是否可用。 - - :return: 如果可用返回 True,否则返回 False - """ - headers = ( - { - "Content-Type": "application/json", - "Authorization": f"Bearer {config.token}", - } - if config.token - else {"Content-Type": "application/json"} - ) - try: - # 尝试连接 WebSocket 服务器 - async with websockets.connect(f"{uri}", extra_headers=headers): - (f"WebSocket {uri} 可用.") - return True - except Exception as e: - print(f"检查 WebSocket 端口时发生错误: {e}") - return False - - -class Route: - def __init__(self): - self.headers = ( - { - "Content-Type": "application/json", - "Authorization": f"Bearer {config.token}", - } - if config.token - else {"Content-Type": "application/json"} - ) - self.url = config.hp_uri - - async def get(self, path, params=None): - async with httpx.AsyncClient() as client: - response = await client.get( - self.url + path, params=params, headers=self.headers, timeout=10 - ) - return response.json() - - async def post(self, path, params=None, json=None): - async with httpx.AsyncClient() as client: - if params: - response = await client.post( - self.url + path, params=params, headers=self.headers, timeout=10 - ) - elif json: - response = await client.post( - self.url + path, json=json, headers=self.headers, timeout=10 - ) - return response.json() - - -class WsRoute: - def __init__(self): - self.url = config.ws_uri + "/api" - self.headers = ( - { - "Content-Type": "application/json", - "Authorization": f"Bearer {config.token}", - } - if config.token - else {"Content-Type": "application/json"} - ) - - async def post(self, path, params=None, json=None): - async with websockets.connect( - self.url, extra_headers=self.headers - ) as websocket: - if params: - await websocket.send( - j.dumps( - { - "action": path.replace("/", ""), - "params": params, - "echo": int(datetime.datetime.now().timestamp()), - } - ) - ) - elif json: - await websocket.send( - j.dumps( - { - "action": path.replace("/", ""), - "params": json, - "echo": int(datetime.datetime.now().timestamp()), - } - ) - ) - response = await websocket.recv() - return j.loads(response) diff --git a/ncatbot/conn/wsroute.py b/ncatbot/conn/wsroute.py new file mode 100644 index 0000000..a2aaf49 --- /dev/null +++ b/ncatbot/conn/wsroute.py @@ -0,0 +1,55 @@ +import datetime +import json as j + +import websockets + +from ncatbot.utils.config import config +from ncatbot.utils.logger import get_log + +_log = get_log() + +async def check_websocket(uri): + """ + 检查指定的 WebSocket uri 是否可用。 + + :return: 如果可用返回 True,否则返回 False + """ + try: + async with websockets.connect(f"{uri}", extra_headers={"Content-Type": "application/json","Authorization": f"Bearer {config.token}"} if config.token else {"Content-Type": "application/json"}): + _log.info(f"WebSocket {uri} 可用.") + return True + except Exception as e: + _log.error(f"检查 WebSocket 端口时发生错误: {e}") + return False + +class Route: + """ + 路由类,用于处理 WebSocket 连接。 + """ + def __init__(self): + self.url = config.ws_uri + "/api" + self.headers = {"Content-Type": "application/json","Authorization": f"Bearer {config.token}"} if config.token else {"Content-Type": "application/json"} + + async def post(self, path, params=None, json=None): + async with websockets.connect(self.url, extra_headers=self.headers) as ws: + if params: + await ws.send( + j.dumps( + { + "action": path.replace("/", ""), + "params": params, + "echo": int(datetime.datetime.now().timestamp()), + } + ) + ) + elif json: + await ws.send( + j.dumps( + { + "action": path.replace("/", ""), + "params": json, + "echo": int(datetime.datetime.now().timestamp()), + } + ) + ) + return j.loads(await ws.recv()) diff --git a/ncatbot/core/api.py b/ncatbot/core/api.py index 881fae9..39cc157 100644 --- a/ncatbot/core/api.py +++ b/ncatbot/core/api.py @@ -1,7 +1,7 @@ import os from typing import Union -from ncatbot.conn.http import Route, WsRoute +from ncatbot.conn.wsroute import Route from ncatbot.core.message import ( At, CustomMusic, @@ -25,7 +25,6 @@ _log = get_log() - def check_and_log(result): if result["status"] == REQUEST_SUCCESS: _log.debug(result) @@ -35,11 +34,14 @@ def check_and_log(result): class BotAPI: - def __init__(self, use_ws: bool): - self.__message = [] - self._http = WsRoute() if use_ws else Route() + def __init__(self): + self._http = Route() async def _construct_forward_message(self, messages): + """ + :param messages: 消息列表 + :return: 转发消息 + """ def decode_summary(report): def decode_single_message(message): if message["type"] == "text": diff --git a/ncatbot/core/client.py b/ncatbot/core/client.py index 1aeddb0..c71bac1 100644 --- a/ncatbot/core/client.py +++ b/ncatbot/core/client.py @@ -6,8 +6,8 @@ import urllib import urllib.parse -from ncatbot.conn.gateway import Websocket -from ncatbot.conn.http import check_websocket +from ncatbot.conn.connect import Websocket +from ncatbot.conn.wsroute import check_websocket from ncatbot.core.api import BotAPI from ncatbot.core.launcher import start_qq from ncatbot.core.message import GroupMessage, PrivateMessage @@ -30,14 +30,14 @@ class BotClient: - def __init__(self, use_ws=True, plugins_path="plugins"): + def __init__(self, plugins_path="plugins"): if not config._updated: _log.warning("没有主动设置配置项, 配置项将使用默认值") time.sleep(0.8) _log.info(config) time.sleep(1.6) - self.api = BotAPI(use_ws) + self.api = BotAPI() self._group_event_handlers = [] self._private_event_handlers = [] self._notice_event_handlers = [] @@ -104,7 +104,7 @@ def request_event(self, func): async def run_async(self): websocket_server = Websocket(self) await self.plugin_sys.load_plugin(self.api) - await websocket_server.ws_connect() + await websocket_server.on_connect() def run(self, reload=False, debug=False): """ @@ -171,7 +171,6 @@ def run(self, reload=False, debug=False): exit(1) # WebUI配置和连接等待逻辑... - http_enable = False if config.hp_uri == "" else True ws_enable = False if config.ws_uri == "" else True if platform.system() == "Linux": config_path = "/opt/QQ/resources/app/app_launcher/napcat/config" @@ -182,21 +181,6 @@ def run(self, reload=False, debug=False): os.chdir(os.path.join(NAPCAT_DIR, "config")) expected_data = { "network": { - "httpServers": [ - { - "name": "httpServer", - "enable": http_enable, - "port": int(urllib.parse.urlparse(config.hp_uri).port), - "host": str(urllib.parse.urlparse(config.hp_uri).hostname), - "enableCors": True, - "enableWebsocket": True, - "messagePostFormat": "array", - "token": ( - str(config.token) if config.token is not None else "" - ), - "debug": False, - } - ], "websocketServers": [ { "name": "WsServer", diff --git a/ncatbot/utils/config.py b/ncatbot/utils/config.py index a5965aa..3bbbbf4 100644 --- a/ncatbot/utils/config.py +++ b/ncatbot/utils/config.py @@ -9,15 +9,13 @@ class SetConfig: def __init__(self): self._updated = False self.bt_uin = "123456" - self.hp_uri = "localhost:3000" self.ws_uri = "localhost:3001" self.token = "" def __str__(self): return ( - f"Configuration:\n" + f"\n--Configuration--\n" f"BOT QQ 号: {self.bt_uin}\n" - f"HTTP URI: {self.hp_uri}\n" f"WebSocket URI: {self.ws_uri}\n" f"Token: {self.token}" ) @@ -44,15 +42,6 @@ def load_config(self, path): parts = location.split(":") self.ws_ip = parts[0] self.ws_port = parts[1] - self.hp_uri = config["hp_uri"] - location = ( - self.hp_uri.replace("http://", "") - if self.hp_uri.startswith("http://") - else self.hp_uri.replace("https://", "") - ) - parts = location.split(":") - self.http_ip = parts[0] - self.http_port = parts[1] self.token = config["token"] self.bot_uin = config["bt_uin"] self.standerize_uri() @@ -62,21 +51,12 @@ def load_config(self, path): def standerize_uri(self): if not (self.ws_uri.startswith("ws://") or self.ws_uri.startswith("wss://")): self.ws_uri = "ws://" + self.ws_uri - if not ( - self.hp_uri.startswith("http://") or self.hp_uri.startswith("https://") - ): - self.hp_uri = "http://" + self.hp_uri def set_ws_uri(self, ws_uri: str): self._updated = True self.ws_uri = ws_uri self.standerize_uri() - def set_hp_uri(self, http_uri: str): - self._updated = True - self.hp_uri = http_uri - self.standerize_uri() - def set_bot_uin(self, uin: str): self._updated = True self.bt_uin = uin