fixtureqa 0.1.0__tar.gz → 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fixtureqa-0.1.0/fixtureqa.egg-info → fixtureqa-0.1.2}/PKG-INFO +1 -1
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/connection_manager.py +28 -31
- {fixtureqa-0.1.0 → fixtureqa-0.1.2/fixtureqa.egg-info}/PKG-INFO +1 -1
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/pyproject.toml +1 -1
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/LICENSE +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/README.md +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/__init__.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/__main__.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/__init__.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/app.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/deps.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/routers/__init__.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/routers/admin.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/routers/auth.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/routers/branding.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/routers/fix_spec.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/routers/messages.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/routers/scenarios.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/routers/sessions.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/routers/setup.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/routers/templates.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/routers/ws.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/api/schemas.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/config/__init__.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/__init__.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/auth.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/config_store.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/events.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/fix_application.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/fix_parser.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/fix_spec_parser.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/fix_tags.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/housekeeping.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/message_log.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/message_store.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/models.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/scenario_runner.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/scenario_store.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/session.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/session_manager.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/template_store.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/user_store.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/core/venue_responses.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/fix_specs/FIX42.xml +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/fix_specs/FIX44.xml +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/server.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/static/assets/ag-grid-_QKprVdm.js +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/static/assets/index-B31-1dt-.css +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/static/assets/index-CTsKxGdI.js +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/static/assets/react-vendor-2eF0YfZT.js +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/static/favicon.svg +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/static/index.html +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixture/ui/__init__.py +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixtureqa.egg-info/SOURCES.txt +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixtureqa.egg-info/dependency_links.txt +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixtureqa.egg-info/entry_points.txt +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixtureqa.egg-info/requires.txt +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/fixtureqa.egg-info/top_level.txt +0 -0
- {fixtureqa-0.1.0 → fixtureqa-0.1.2}/setup.cfg +0 -0
|
@@ -5,8 +5,11 @@ fixcore callbacks fire on the asyncio event loop — no thread-crossing needed.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import asyncio
|
|
8
|
+
import logging
|
|
8
9
|
from datetime import datetime, timezone
|
|
9
10
|
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
10
13
|
from fastapi import WebSocket
|
|
11
14
|
from starlette.websockets import WebSocketState
|
|
12
15
|
|
|
@@ -69,7 +72,6 @@ class ConnectionManager:
|
|
|
69
72
|
"""
|
|
70
73
|
|
|
71
74
|
def __init__(self):
|
|
72
|
-
# session_id (or "*") -> dict[WebSocket, _ConnInfo]
|
|
73
75
|
self._clients: dict[str, dict[WebSocket, _ConnInfo]] = {}
|
|
74
76
|
|
|
75
77
|
# ------------------------------------------------------------------
|
|
@@ -79,13 +81,11 @@ class ConnectionManager:
|
|
|
79
81
|
async def connect(self, websocket: WebSocket, session_id: str = "*",
|
|
80
82
|
uid: str = "", is_admin: bool = False) -> None:
|
|
81
83
|
await websocket.accept()
|
|
82
|
-
|
|
83
|
-
self._clients.setdefault(session_id, {})[websocket] = _ConnInfo(uid, is_admin)
|
|
84
|
+
self._clients.setdefault(session_id, {})[websocket] = _ConnInfo(uid, is_admin)
|
|
84
85
|
|
|
85
86
|
def disconnect(self, websocket: WebSocket, session_id: str = "*") -> None:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
clients.pop(websocket, None)
|
|
87
|
+
clients = self._clients.get(session_id, {})
|
|
88
|
+
clients.pop(websocket, None)
|
|
89
89
|
|
|
90
90
|
# ------------------------------------------------------------------
|
|
91
91
|
# Called from the asyncio event loop (fixcore callbacks / scenario runner)
|
|
@@ -105,11 +105,11 @@ class ConnectionManager:
|
|
|
105
105
|
# ------------------------------------------------------------------
|
|
106
106
|
|
|
107
107
|
async def _broadcast(self, session_id: str, payload: dict, owner_uid: str) -> None:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
specific = dict(self._clients.get(session_id, {}))
|
|
109
|
+
wildcard = dict(self._clients.get("*", {}))
|
|
110
|
+
|
|
111
|
+
logger.debug("_broadcast: type=%s session=%s owner=%r clients_specific=%d wildcard=%d",
|
|
112
|
+
payload.get("type"), session_id, owner_uid, len(specific), len(wildcard))
|
|
113
113
|
|
|
114
114
|
# Build target set: connections that may receive this event
|
|
115
115
|
# A connection receives the event if:
|
|
@@ -120,28 +120,27 @@ class ConnectionManager:
|
|
|
120
120
|
if info.is_admin or info.uid == owner_uid:
|
|
121
121
|
targets[ws] = info
|
|
122
122
|
|
|
123
|
+
logger.debug("_broadcast: %d target(s) for owner=%r", len(targets), owner_uid)
|
|
124
|
+
|
|
123
125
|
dead: list[tuple[WebSocket, str]] = []
|
|
124
126
|
for ws in targets:
|
|
125
127
|
try:
|
|
126
128
|
if ws.client_state == WebSocketState.CONNECTED:
|
|
127
129
|
await ws.send_json(payload)
|
|
128
130
|
except Exception:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
dead.append((ws, key))
|
|
131
|
+
for key, sockets in self._clients.items():
|
|
132
|
+
if ws in sockets:
|
|
133
|
+
dead.append((ws, key))
|
|
133
134
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
self._clients.get(key, {}).pop(ws, None)
|
|
135
|
+
for ws, key in dead:
|
|
136
|
+
self._clients.get(key, {}).pop(ws, None)
|
|
137
137
|
|
|
138
138
|
async def _broadcast_to_user(self, uid: str, data: dict) -> None:
|
|
139
139
|
"""Send data to all WS connections belonging to uid."""
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
for
|
|
143
|
-
|
|
144
|
-
all_clients[ws] = info
|
|
140
|
+
all_clients = {}
|
|
141
|
+
for sockets in self._clients.values():
|
|
142
|
+
for ws, info in sockets.items():
|
|
143
|
+
all_clients[ws] = info
|
|
145
144
|
|
|
146
145
|
dead: list[tuple[WebSocket, str]] = []
|
|
147
146
|
for ws, info in all_clients.items():
|
|
@@ -151,11 +150,9 @@ class ConnectionManager:
|
|
|
151
150
|
if ws.client_state == WebSocketState.CONNECTED:
|
|
152
151
|
await ws.send_json(data)
|
|
153
152
|
except Exception:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
for ws, key in dead:
|
|
161
|
-
self._clients.get(key, {}).pop(ws, None)
|
|
153
|
+
for key, sockets in self._clients.items():
|
|
154
|
+
if ws in sockets:
|
|
155
|
+
dead.append((ws, key))
|
|
156
|
+
|
|
157
|
+
for ws, key in dead:
|
|
158
|
+
self._clients.get(key, {}).pop(ws, None)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|