feat: Унифицирован формат сообщений

This commit is contained in:
AURUMVORXX
2025-11-06 00:59:58 +05:00
parent 13d4a69ad2
commit 1f821b4478
3 changed files with 74 additions and 45 deletions

View File

@@ -45,9 +45,7 @@ class PyG2O
function _send(data, uuid = "none") function _send(data, uuid = "none")
{ {
if (uuid != "none") data["uuid"] <- uuid;
data["uuid"] <- uuid;
_connection.send(JSON.dump_ansi(data, 2)); _connection.send(JSON.dump_ansi(data, 2));
} }
@@ -56,7 +54,7 @@ class PyG2O
if (!_silent) if (!_silent)
print("[PyG2O] Successfully connected to " + url); print("[PyG2O] Successfully connected to " + url);
_send({"init_temp_tokens": _clientTokens}); _send({"event": "init_temp_tokens", "token": _clientTokens});
} }
function _onClose(url, message) function _onClose(url, message)
@@ -98,7 +96,7 @@ class PyG2O
addEventHandler("onPlayerJoin", function(playerid){ addEventHandler("onPlayerJoin", function(playerid){
local new_token = _globalInstance.generateClientPassword(); local new_token = _globalInstance.generateClientPassword();
_globalInstance._send({"create_temp_token": new_token}) _globalInstance._send({"event": "create_temp_token", "token": new_token})
_clientTokens[playerid] <- new_token; _clientTokens[playerid] <- new_token;
local packet = Packet(); local packet = Packet();
@@ -108,6 +106,6 @@ addEventHandler("onPlayerJoin", function(playerid){
}); });
addEventHandler("onPlayerDisconnect", function(playerid, reason){ addEventHandler("onPlayerDisconnect", function(playerid, reason){
_globalInstance._send({"remove_temp_token": _clientTokens[playerid]}); _globalInstance._send({"event": "remove_temp_token", "token": _clientTokens[playerid]});
delete _clientTokens[playerid]; delete _clientTokens[playerid];
}); });

View File

@@ -1,5 +1,4 @@
import inspect import inspect
from fastapi import WebSocket
_EVENTS = {} _EVENTS = {}
@@ -16,14 +15,31 @@ def event(event_name: str, priority: int = 9999):
return func return func
return inlineEvent return inlineEvent
async def call_event(event_name: str, connection: WebSocket, uuid: str | None, *args, **kwargs): async def call_event(event_name: str, **kwargs):
from .server import Server from .server import Server
if event_name not in _EVENTS: if event_name not in _EVENTS:
return return
for item in _EVENTS[event_name]: for item in _EVENTS[event_name]:
result = await item['function'](*args, **kwargs) sig = inspect.signature(item['function'])
if uuid is None or result is None: params = list(sig.parameters.keys())
args = {}
for param in params:
args[param] = kwargs.get(param)
if any(p.kind == p.VAR_KEYWORD for p in sig.parameters.values()):
result = await item['function'](**kwargs)
else:
result = await item['function'](**args)
if result is None:
return return
await Server.send(connection = connection, uuid = uuid, message = result)
await Server.send(
connection = kwargs['connection'],
uuid = kwargs['uuid'],
event = 'backend_response',
message = result,
)

View File

@@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
import json import json
from types import SimpleNamespace
import loguru import loguru
import asyncio import asyncio
from weakref import WeakValueDictionary, WeakSet, finalize from weakref import WeakValueDictionary, WeakSet, finalize
@@ -33,18 +34,24 @@ class Server:
cls._register_routes(app) cls._register_routes(app)
@classmethod @classmethod
def publish(cls, topic: str, message) -> asyncio.Future: def publish(cls, topic: str, event: str, message: dict) -> asyncio.Future | None:
if topic not in cls._topics: try:
raise KeyError('Клиентов прослушивающих этот топик не существует') if topic not in cls._topics:
raise KeyError('Клиентов прослушивающих этот топик не существует')
request, data = cls._make_request() # Формируем сообщение
data['data'] = message request, data = cls._make_request()
data = json.dumps(data) data['event'] = event
# Меняем синтаксис под Squirrel data.update(message)
data = data.replace("'", '\\"').replace('True', 'true').replace('False', 'false') data = json.dumps(data)
asyncio.create_task(cls._send_to_topic(topic, data)) # Меняем синтаксис под Squirrel
return request data = data.replace("'", '\\"').replace('True', 'true').replace('False', 'false')
asyncio.create_task(cls._send_to_topic(topic, data))
return request
except ValueError:
cls._logger.exception('message должен быть типа dict')
@classmethod @classmethod
async def _send_to_topic(cls, topic, data): async def _send_to_topic(cls, topic, data):
@@ -52,15 +59,19 @@ class Server:
await connection.send_text(data) await connection.send_text(data)
@classmethod @classmethod
async def send(cls, connection: WebSocket, message, uuid: str): async def send(cls, connection: WebSocket, event: str, message: dict, uuid: str | None = None):
data = { try:
'uuid': uuid, data = {
'data': message, 'event': event,
} 'uuid': uuid,
data = json.dumps(data) }
# Меняем синтаксис под Squirrel data.update(message)
data = data.replace("'", '\\"').replace('True', 'true').replace('False', 'false') data = json.dumps(data)
await connection.send_text(data) # Меняем синтаксис под Squirrel
data = data.replace("'", '\\"').replace('True', 'true').replace('False', 'false')
await connection.send_text(data)
except ValueError:
cls._logger.exception('message должен быть типа dict')
@classmethod @classmethod
def _make_request(cls): def _make_request(cls):
@@ -70,7 +81,6 @@ class Server:
data = { data = {
'uuid': request_id, 'uuid': request_id,
'data': None,
} }
return request, data return request, data
@@ -136,29 +146,34 @@ class Server:
async def _process_message(cls, connection: WebSocket, message: dict): async def _process_message(cls, connection: WebSocket, message: dict):
match message: match message:
case {'event': event, **kwargs}: case {'event': 'subscribe', 'topics': topics}:
try:
cls._requests[kwargs['uuid']].set_result(kwargs.get('data'))
except KeyError:
uuid = kwargs.get('uuid')
if uuid is not None:
del kwargs['uuid']
asyncio.create_task(call_event(event, connection, uuid, **kwargs))
case {'subscribe': topics}:
await cls._subscribe(topics, connection) await cls._subscribe(topics, connection)
case {'unsubscribe': topics}: case {'event': 'unsubscribe', 'topics': topics}:
await cls._unsubscribe(topics, connection) await cls._unsubscribe(topics, connection)
case {'create_temp_token': token}: case {'event': 'create_temp_token', 'token': token}:
cls._temp_tokens.append(token) cls._temp_tokens.append(token)
case {'remove_temp_token': token}: case {'event': 'remove_temp_token', 'token': token}:
cls._temp_tokens.remove(token) cls._temp_tokens.remove(token)
case {'init_temp_tokens': tokens}: case {'event': 'init_temp_tokens', 'tokens': tokens}:
cls._temp_tokens = cls._temp_tokens + list(tokens.items()) cls._temp_tokens = cls._temp_tokens + list(tokens.items())
case {'event': 'sq_response', 'uuid': uuid, 'data': data}:
try:
cls._requests[uuid].set_result(data)
except KeyError:
...
case {'event': event, 'uuid': uuid, **kwargs}:
try:
cls._requests[uuid].set_result(SimpleNamespace(**kwargs))
except KeyError:
kwargs['uuid'] = uuid
kwargs['connection'] = connection
asyncio.create_task(call_event(event, **kwargs))
case _: case _:
raise ValueError(f'Неподдерживаемый тип PyG2O сообщения: {message}') raise ValueError(f'Неподдерживаемый тип PyG2O сообщения: {message}')