-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
支持 WebSocket (OneBot V11)、反向 WebSocket (OneBot V11)
- Loading branch information
1 parent
b99764b
commit 1f42f59
Showing
6 changed files
with
296 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
from client import client | ||
import event_12_to_11 | ||
import websockets | ||
import json | ||
import json | ||
import event | ||
import call_action | ||
import asyncio | ||
import traceback | ||
import websockets.client | ||
import websockets.exceptions | ||
from logger import get_logger | ||
from version import VERSION | ||
|
||
BASE_CONFIG = { | ||
"url": None, | ||
"api_url": None, | ||
"event_url": None, | ||
"reconnect_interval": 3000, | ||
"use_universal_client": False, | ||
"access_token": None | ||
} | ||
logger = get_logger() | ||
|
||
|
||
class WebSocketClient4OB11: | ||
|
||
def __init__(self, config: dict) -> None: | ||
self.config = BASE_CONFIG | config | ||
if not self.config["use_universal_client"]: | ||
self.config["api_url"] = self.config["api_url"] or self.config["url"] | ||
self.config["event_url"] = self.config["event_url"] or self.config["url"] | ||
self.reconnect_task = asyncio.create_task(self.connect()) | ||
|
||
async def connect(self) -> None: | ||
if self.config["use_universal_client"]: | ||
self.api_ws = self.event_ws = await self.create_websocker_connection( | ||
self.config["url"], "Universal" | ||
) | ||
else: | ||
self.api_ws = await self.create_websocker_connection( | ||
self.config["api_url"], "API" | ||
) | ||
self.event_ws = await self.create_websocker_connection( | ||
self.config["event_url"], "Event" | ||
) | ||
try: | ||
del self.reconnect_task | ||
except Exception: | ||
pass | ||
await self.event_ws.send(json.dumps( | ||
event_12_to_11.translate_event(event.get_event_object( | ||
"meta", | ||
"lifecycle", | ||
"connect" | ||
)))) | ||
|
||
async def reconnect(self) -> None: | ||
if hasattr(self, "reconnect_task"): | ||
await self.reconnect_task | ||
return | ||
await self.close() | ||
self.reconnect_task = asyncio.create_task(self.connect()) | ||
|
||
async def close(self) -> None: | ||
try: | ||
await self.api_ws.close() | ||
except Exception: | ||
pass | ||
try: | ||
await self.event_ws.close() | ||
except Exception: | ||
pass | ||
|
||
async def create_websocker_connection(self, url: str, role: str) -> websockets.client.WebSocketClientProtocol: | ||
while True: | ||
try: | ||
logger.info(f"正在连接到反向 WebSocket {role} 服务器:{url}") | ||
return await websockets.client.connect( | ||
url, extra_headers=self.get_headers(role) | ||
) | ||
except Exception as e: | ||
logger.warning(f"连接到反向 WebSocket {role} 时出现错误:{e}") | ||
await asyncio.sleep(self.config["reconnect_interval"] / 1000) | ||
|
||
async def push_event(self, event: dict) -> None: | ||
try: | ||
await self.event_ws.send( | ||
json.dumps( | ||
event_12_to_11.translate_event( | ||
event | ||
) | ||
) | ||
) | ||
except Exception: | ||
logger.warning(f"推送事件时出现错误:{traceback.format_exc()}") | ||
await self.reconnect() | ||
await self.push_event(event) | ||
|
||
async def handle_api_requests(self) -> None: | ||
while True: | ||
try: | ||
recv_data = json.loads(await self.api_ws.recv()) | ||
resp_data = await call_action.on_call_action( | ||
**recv_data, | ||
protocol_version=11 | ||
) | ||
resp_data["retcode"] = { | ||
10001: 1400, | ||
10002: 1404 | ||
}.get(resp_data["retcode"], resp_data["retcode"]) | ||
await self.api_ws.send(json.dumps(resp_data)) | ||
except Exception: | ||
logger.warning(f"处理 API 请求时出现错误:{traceback.format_exc()}") | ||
break | ||
await self.reconnect() | ||
|
||
|
||
def get_headers(self, role: str) -> dict: | ||
return { | ||
"X-Self-ID": client.user.id, | ||
"X-Client-Role": role | ||
} | ({"Authorization": f'Bearer {self.config["access_token"]}'} if self.config["access_token"] else {}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import event_12_to_11 | ||
import event | ||
from http_server import verify_access_token | ||
from logger import get_logger | ||
import uvicorn_server | ||
import fastapi | ||
import call_action | ||
|
||
logger = get_logger() | ||
BASE_CONFIG = { | ||
"host": "0.0.0.0", | ||
"port": 6700, | ||
"access_token": None | ||
} | ||
|
||
class WebSocket4OB11: | ||
|
||
def __init__(self, config: dict) -> None: | ||
self.config = BASE_CONFIG | config | ||
self.clients_on_event_route = [] | ||
self.app = fastapi.FastAPI() | ||
self.app.add_websocket_route("/", self.handle_root_route) | ||
self.app.add_websocket_route("/event", self.handle_event_route) | ||
self.app.add_websocket_route("/api", self.handle_api_route) | ||
|
||
async def start(self) -> None: | ||
await uvicorn_server.run( | ||
self.app, | ||
host=self.config["host"], | ||
port=self.config["port"] | ||
) | ||
|
||
|
||
async def handle_event_route(self, websocket: fastapi.WebSocket) -> None: | ||
if not verify_access_token(websocket, self.config["access_token"]): | ||
if "Authorization" in websocket.headers.keys() or websocket.query_params.get("access_token"): | ||
await websocket.close(403, "Invalid access token") | ||
else: | ||
await websocket.close(401, "Missing access token") | ||
return | ||
await websocket.accept() | ||
self.clients_on_event_route.append(websocket) | ||
await websocket.send_json(event_12_to_11.translate_event(event.get_event_object( | ||
"meta", | ||
"lifecycle", | ||
"connect" | ||
))) | ||
|
||
async def handle_api_route(self, websocket: fastapi.WebSocket) -> None: | ||
if not verify_access_token(websocket, self.config["access_token"]): | ||
if "Authorization" in websocket.headers.keys() or websocket.query_params.get("access_token"): | ||
await websocket.close(403, "Invalid access token") | ||
else: | ||
await websocket.close(401, "Missing access token") | ||
return | ||
await websocket.accept() | ||
while True: | ||
resp_data = await call_action.on_call_action( | ||
**(await websocket.receive_json()), | ||
protocol_version=11 | ||
) | ||
resp_data["retcode"] = { | ||
10001: 1400, | ||
10002: 1404 | ||
}.get(resp_data["retcode"], resp_data["retcode"]) | ||
await websocket.send_json(resp_data) | ||
|
||
async def handle_root_route(self, websocket: fastapi.WebSocket) -> None: | ||
if not verify_access_token(websocket, self.config["access_token"]): | ||
if "Authorization" in websocket.headers.keys() or websocket.query_params.get("access_token"): | ||
await websocket.close(403, "Invalid access token") | ||
else: | ||
await websocket.close(401, "Missing access token") | ||
return | ||
await websocket.accept() | ||
self.clients_on_event_route.append(websocket) | ||
while True: | ||
resp_data = await call_action.on_call_action( | ||
**(await websocket.receive_json()), | ||
protocol_version=12 | ||
) | ||
resp_data["retcode"] = { | ||
10001: 1400, | ||
10002: 1404 | ||
}.get(resp_data["retcode"], resp_data["retcode"]) | ||
await websocket.send_json(resp_data) | ||
|
||
async def push_event(self, _event: dict) -> None: | ||
event = event_12_to_11.translate_event(_event) | ||
for client in self.clients_on_event_route: | ||
try: | ||
await client.send_json(event) | ||
except Exception as e: | ||
logger.error(f"向 {client} 推送事件时出现错误:{e}") | ||
await client.close() | ||
self.clients_on_event_route.remove(client) |