api-mocker 0.3.0__py3-none-any.whl → 0.5.0__py3-none-any.whl
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.
- api_mocker/auth_system.py +610 -0
- api_mocker/cli.py +380 -1
- api_mocker/database_integration.py +566 -0
- api_mocker/graphql_mock.py +593 -0
- api_mocker/ml_integration.py +709 -0
- api_mocker/mock_responses.py +622 -0
- api_mocker/websocket_mock.py +476 -0
- {api_mocker-0.3.0.dist-info → api_mocker-0.5.0.dist-info}/METADATA +15 -2
- {api_mocker-0.3.0.dist-info → api_mocker-0.5.0.dist-info}/RECORD +13 -7
- {api_mocker-0.3.0.dist-info → api_mocker-0.5.0.dist-info}/WHEEL +0 -0
- {api_mocker-0.3.0.dist-info → api_mocker-0.5.0.dist-info}/entry_points.txt +0 -0
- {api_mocker-0.3.0.dist-info → api_mocker-0.5.0.dist-info}/licenses/LICENSE +0 -0
- {api_mocker-0.3.0.dist-info → api_mocker-0.5.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
"""
|
|
2
|
+
WebSocket Mock Support System
|
|
3
|
+
|
|
4
|
+
This module provides comprehensive WebSocket mocking capabilities including:
|
|
5
|
+
- Real-time message handling
|
|
6
|
+
- Connection management
|
|
7
|
+
- Message routing and broadcasting
|
|
8
|
+
- Authentication and authorization
|
|
9
|
+
- Custom message handlers
|
|
10
|
+
- Connection state management
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import asyncio
|
|
14
|
+
import json
|
|
15
|
+
import uuid
|
|
16
|
+
from typing import Any, Dict, List, Optional, Callable, Set
|
|
17
|
+
from dataclasses import dataclass, field
|
|
18
|
+
from enum import Enum
|
|
19
|
+
from datetime import datetime
|
|
20
|
+
import websockets
|
|
21
|
+
from websockets.server import WebSocketServerProtocol
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class WebSocketMessageType(Enum):
|
|
25
|
+
"""WebSocket message types"""
|
|
26
|
+
TEXT = "text"
|
|
27
|
+
BINARY = "binary"
|
|
28
|
+
PING = "ping"
|
|
29
|
+
PONG = "pong"
|
|
30
|
+
CLOSE = "close"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class WebSocketConnectionState(Enum):
|
|
34
|
+
"""WebSocket connection states"""
|
|
35
|
+
CONNECTING = "connecting"
|
|
36
|
+
OPEN = "open"
|
|
37
|
+
CLOSING = "closing"
|
|
38
|
+
CLOSED = "closed"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class WebSocketMessage:
|
|
43
|
+
"""Represents a WebSocket message"""
|
|
44
|
+
message_type: WebSocketMessageType
|
|
45
|
+
content: Any
|
|
46
|
+
timestamp: datetime = field(default_factory=datetime.now)
|
|
47
|
+
message_id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
|
48
|
+
sender_id: Optional[str] = None
|
|
49
|
+
target_id: Optional[str] = None
|
|
50
|
+
room: Optional[str] = None
|
|
51
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
55
|
+
class WebSocketConnection:
|
|
56
|
+
"""Represents a WebSocket connection"""
|
|
57
|
+
connection_id: str
|
|
58
|
+
websocket: WebSocketServerProtocol
|
|
59
|
+
state: WebSocketConnectionState = WebSocketConnectionState.CONNECTING
|
|
60
|
+
user_id: Optional[str] = None
|
|
61
|
+
rooms: Set[str] = field(default_factory=set)
|
|
62
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
63
|
+
created_at: datetime = field(default_factory=datetime.now)
|
|
64
|
+
last_activity: datetime = field(default_factory=datetime.now)
|
|
65
|
+
message_count: int = 0
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class WebSocketRoom:
|
|
70
|
+
"""Represents a WebSocket room for message broadcasting"""
|
|
71
|
+
name: str
|
|
72
|
+
connections: Set[str] = field(default_factory=set)
|
|
73
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
74
|
+
created_at: datetime = field(default_factory=datetime.now)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@dataclass
|
|
78
|
+
class WebSocketMessageHandler:
|
|
79
|
+
"""Represents a message handler for WebSocket messages"""
|
|
80
|
+
pattern: str
|
|
81
|
+
handler_func: Callable
|
|
82
|
+
description: Optional[str] = None
|
|
83
|
+
requires_auth: bool = False
|
|
84
|
+
rate_limit: Optional[int] = None # messages per minute
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class WebSocketMockServer:
|
|
88
|
+
"""Main WebSocket mock server implementation"""
|
|
89
|
+
|
|
90
|
+
def __init__(self, host: str = "localhost", port: int = 8765):
|
|
91
|
+
self.host = host
|
|
92
|
+
self.port = port
|
|
93
|
+
self.connections: Dict[str, WebSocketConnection] = {}
|
|
94
|
+
self.rooms: Dict[str, WebSocketRoom] = {}
|
|
95
|
+
self.message_handlers: List[WebSocketMessageHandler] = []
|
|
96
|
+
self.server: Optional[websockets.WebSocketServer] = None
|
|
97
|
+
self.running = False
|
|
98
|
+
|
|
99
|
+
# Statistics
|
|
100
|
+
self.total_connections = 0
|
|
101
|
+
self.total_messages = 0
|
|
102
|
+
self.active_connections = 0
|
|
103
|
+
|
|
104
|
+
# Setup default handlers
|
|
105
|
+
self._setup_default_handlers()
|
|
106
|
+
|
|
107
|
+
def _setup_default_handlers(self) -> None:
|
|
108
|
+
"""Setup default message handlers"""
|
|
109
|
+
# Echo handler
|
|
110
|
+
self.add_message_handler(
|
|
111
|
+
pattern="echo",
|
|
112
|
+
handler_func=self._echo_handler,
|
|
113
|
+
description="Echo back the received message"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Broadcast handler
|
|
117
|
+
self.add_message_handler(
|
|
118
|
+
pattern="broadcast",
|
|
119
|
+
handler_func=self._broadcast_handler,
|
|
120
|
+
description="Broadcast message to all connections"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# Room join handler
|
|
124
|
+
self.add_message_handler(
|
|
125
|
+
pattern="join",
|
|
126
|
+
handler_func=self._join_room_handler,
|
|
127
|
+
description="Join a room for group messaging"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# Room leave handler
|
|
131
|
+
self.add_message_handler(
|
|
132
|
+
pattern="leave",
|
|
133
|
+
handler_func=self._leave_room_handler,
|
|
134
|
+
description="Leave a room"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Room message handler
|
|
138
|
+
self.add_message_handler(
|
|
139
|
+
pattern="room_message",
|
|
140
|
+
handler_func=self._room_message_handler,
|
|
141
|
+
description="Send message to a specific room"
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Stats handler
|
|
145
|
+
self.add_message_handler(
|
|
146
|
+
pattern="stats",
|
|
147
|
+
handler_func=self._stats_handler,
|
|
148
|
+
description="Get server statistics"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
def add_message_handler(self, pattern: str, handler_func: Callable,
|
|
152
|
+
description: str = None, requires_auth: bool = False,
|
|
153
|
+
rate_limit: int = None) -> None:
|
|
154
|
+
"""Add a custom message handler"""
|
|
155
|
+
handler = WebSocketMessageHandler(
|
|
156
|
+
pattern=pattern,
|
|
157
|
+
handler_func=handler_func,
|
|
158
|
+
description=description,
|
|
159
|
+
requires_auth=requires_auth,
|
|
160
|
+
rate_limit=rate_limit
|
|
161
|
+
)
|
|
162
|
+
self.message_handlers.append(handler)
|
|
163
|
+
|
|
164
|
+
async def start_server(self) -> None:
|
|
165
|
+
"""Start the WebSocket server"""
|
|
166
|
+
if self.running:
|
|
167
|
+
return
|
|
168
|
+
|
|
169
|
+
self.server = await websockets.serve(
|
|
170
|
+
self._handle_connection,
|
|
171
|
+
self.host,
|
|
172
|
+
self.port
|
|
173
|
+
)
|
|
174
|
+
self.running = True
|
|
175
|
+
print(f"WebSocket mock server started on {self.host}:{self.port}")
|
|
176
|
+
|
|
177
|
+
async def stop_server(self) -> None:
|
|
178
|
+
"""Stop the WebSocket server"""
|
|
179
|
+
if self.server:
|
|
180
|
+
self.server.close()
|
|
181
|
+
await self.server.wait_closed()
|
|
182
|
+
self.running = False
|
|
183
|
+
print("WebSocket mock server stopped")
|
|
184
|
+
|
|
185
|
+
async def _handle_connection(self, websocket: WebSocketServerProtocol, path: str) -> None:
|
|
186
|
+
"""Handle a new WebSocket connection"""
|
|
187
|
+
connection_id = str(uuid.uuid4())
|
|
188
|
+
connection = WebSocketConnection(
|
|
189
|
+
connection_id=connection_id,
|
|
190
|
+
websocket=websocket,
|
|
191
|
+
state=WebSocketConnectionState.OPEN
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
self.connections[connection_id] = connection
|
|
195
|
+
self.total_connections += 1
|
|
196
|
+
self.active_connections += 1
|
|
197
|
+
|
|
198
|
+
print(f"New WebSocket connection: {connection_id}")
|
|
199
|
+
|
|
200
|
+
try:
|
|
201
|
+
# Send welcome message
|
|
202
|
+
await self._send_message(connection, {
|
|
203
|
+
"type": "welcome",
|
|
204
|
+
"connection_id": connection_id,
|
|
205
|
+
"message": "Connected to WebSocket mock server",
|
|
206
|
+
"timestamp": datetime.now().isoformat()
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
# Handle messages
|
|
210
|
+
async for message in websocket:
|
|
211
|
+
await self._process_message(connection, message)
|
|
212
|
+
|
|
213
|
+
except websockets.exceptions.ConnectionClosed:
|
|
214
|
+
print(f"WebSocket connection closed: {connection_id}")
|
|
215
|
+
except Exception as e:
|
|
216
|
+
print(f"WebSocket error: {e}")
|
|
217
|
+
finally:
|
|
218
|
+
await self._cleanup_connection(connection)
|
|
219
|
+
|
|
220
|
+
async def _process_message(self, connection: WebSocketConnection, message: str) -> None:
|
|
221
|
+
"""Process an incoming WebSocket message"""
|
|
222
|
+
try:
|
|
223
|
+
# Parse message
|
|
224
|
+
if isinstance(message, str):
|
|
225
|
+
try:
|
|
226
|
+
data = json.loads(message)
|
|
227
|
+
except json.JSONDecodeError:
|
|
228
|
+
data = {"type": "text", "content": message}
|
|
229
|
+
else:
|
|
230
|
+
data = {"type": "binary", "content": message}
|
|
231
|
+
|
|
232
|
+
# Update connection activity
|
|
233
|
+
connection.last_activity = datetime.now()
|
|
234
|
+
connection.message_count += 1
|
|
235
|
+
self.total_messages += 1
|
|
236
|
+
|
|
237
|
+
# Find matching handler
|
|
238
|
+
handler = self._find_handler(data.get("type", ""))
|
|
239
|
+
if handler:
|
|
240
|
+
await handler.handler_func(connection, data)
|
|
241
|
+
else:
|
|
242
|
+
# Default handler - echo back
|
|
243
|
+
await self._echo_handler(connection, data)
|
|
244
|
+
|
|
245
|
+
except Exception as e:
|
|
246
|
+
print(f"Error processing message: {e}")
|
|
247
|
+
await self._send_error(connection, str(e))
|
|
248
|
+
|
|
249
|
+
def _find_handler(self, message_type: str) -> Optional[WebSocketMessageHandler]:
|
|
250
|
+
"""Find a handler for the message type"""
|
|
251
|
+
for handler in self.message_handlers:
|
|
252
|
+
if handler.pattern == message_type:
|
|
253
|
+
return handler
|
|
254
|
+
return None
|
|
255
|
+
|
|
256
|
+
async def _echo_handler(self, connection: WebSocketConnection, data: Dict[str, Any]) -> None:
|
|
257
|
+
"""Echo handler - echo back the received message"""
|
|
258
|
+
response = {
|
|
259
|
+
"type": "echo",
|
|
260
|
+
"original": data,
|
|
261
|
+
"timestamp": datetime.now().isoformat()
|
|
262
|
+
}
|
|
263
|
+
await self._send_message(connection, response)
|
|
264
|
+
|
|
265
|
+
async def _broadcast_handler(self, connection: WebSocketConnection, data: Dict[str, Any]) -> None:
|
|
266
|
+
"""Broadcast handler - send message to all connections"""
|
|
267
|
+
message = data.get("message", "Broadcast message")
|
|
268
|
+
response = {
|
|
269
|
+
"type": "broadcast",
|
|
270
|
+
"message": message,
|
|
271
|
+
"sender": connection.connection_id,
|
|
272
|
+
"timestamp": datetime.now().isoformat()
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
# Send to all connections
|
|
276
|
+
for conn in self.connections.values():
|
|
277
|
+
if conn.state == WebSocketConnectionState.OPEN:
|
|
278
|
+
await self._send_message(conn, response)
|
|
279
|
+
|
|
280
|
+
async def _join_room_handler(self, connection: WebSocketConnection, data: Dict[str, Any]) -> None:
|
|
281
|
+
"""Join room handler"""
|
|
282
|
+
room_name = data.get("room")
|
|
283
|
+
if not room_name:
|
|
284
|
+
await self._send_error(connection, "Room name required")
|
|
285
|
+
return
|
|
286
|
+
|
|
287
|
+
# Create room if it doesn't exist
|
|
288
|
+
if room_name not in self.rooms:
|
|
289
|
+
self.rooms[room_name] = WebSocketRoom(name=room_name)
|
|
290
|
+
|
|
291
|
+
# Add connection to room
|
|
292
|
+
self.rooms[room_name].connections.add(connection.connection_id)
|
|
293
|
+
connection.rooms.add(room_name)
|
|
294
|
+
|
|
295
|
+
response = {
|
|
296
|
+
"type": "room_joined",
|
|
297
|
+
"room": room_name,
|
|
298
|
+
"timestamp": datetime.now().isoformat()
|
|
299
|
+
}
|
|
300
|
+
await self._send_message(connection, response)
|
|
301
|
+
|
|
302
|
+
async def _leave_room_handler(self, connection: WebSocketConnection, data: Dict[str, Any]) -> None:
|
|
303
|
+
"""Leave room handler"""
|
|
304
|
+
room_name = data.get("room")
|
|
305
|
+
if not room_name:
|
|
306
|
+
await self._send_error(connection, "Room name required")
|
|
307
|
+
return
|
|
308
|
+
|
|
309
|
+
# Remove connection from room
|
|
310
|
+
if room_name in self.rooms:
|
|
311
|
+
self.rooms[room_name].connections.discard(connection.connection_id)
|
|
312
|
+
connection.rooms.discard(room_name)
|
|
313
|
+
|
|
314
|
+
response = {
|
|
315
|
+
"type": "room_left",
|
|
316
|
+
"room": room_name,
|
|
317
|
+
"timestamp": datetime.now().isoformat()
|
|
318
|
+
}
|
|
319
|
+
await self._send_message(connection, response)
|
|
320
|
+
|
|
321
|
+
async def _room_message_handler(self, connection: WebSocketConnection, data: Dict[str, Any]) -> None:
|
|
322
|
+
"""Room message handler"""
|
|
323
|
+
room_name = data.get("room")
|
|
324
|
+
message = data.get("message", "")
|
|
325
|
+
|
|
326
|
+
if not room_name:
|
|
327
|
+
await self._send_error(connection, "Room name required")
|
|
328
|
+
return
|
|
329
|
+
|
|
330
|
+
if room_name not in self.rooms:
|
|
331
|
+
await self._send_error(connection, "Room not found")
|
|
332
|
+
return
|
|
333
|
+
|
|
334
|
+
if connection.connection_id not in self.rooms[room_name].connections:
|
|
335
|
+
await self._send_error(connection, "Not in room")
|
|
336
|
+
return
|
|
337
|
+
|
|
338
|
+
# Send message to all connections in room
|
|
339
|
+
response = {
|
|
340
|
+
"type": "room_message",
|
|
341
|
+
"room": room_name,
|
|
342
|
+
"message": message,
|
|
343
|
+
"sender": connection.connection_id,
|
|
344
|
+
"timestamp": datetime.now().isoformat()
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
for conn_id in self.rooms[room_name].connections:
|
|
348
|
+
if conn_id in self.connections:
|
|
349
|
+
conn = self.connections[conn_id]
|
|
350
|
+
if conn.state == WebSocketConnectionState.OPEN:
|
|
351
|
+
await self._send_message(conn, response)
|
|
352
|
+
|
|
353
|
+
async def _stats_handler(self, connection: WebSocketConnection, data: Dict[str, Any]) -> None:
|
|
354
|
+
"""Stats handler - return server statistics"""
|
|
355
|
+
stats = {
|
|
356
|
+
"type": "stats",
|
|
357
|
+
"total_connections": self.total_connections,
|
|
358
|
+
"active_connections": self.active_connections,
|
|
359
|
+
"total_messages": self.total_messages,
|
|
360
|
+
"rooms": len(self.rooms),
|
|
361
|
+
"handlers": len(self.message_handlers),
|
|
362
|
+
"timestamp": datetime.now().isoformat()
|
|
363
|
+
}
|
|
364
|
+
await self._send_message(connection, stats)
|
|
365
|
+
|
|
366
|
+
async def _send_message(self, connection: WebSocketConnection, data: Dict[str, Any]) -> None:
|
|
367
|
+
"""Send a message to a connection"""
|
|
368
|
+
try:
|
|
369
|
+
if connection.state == WebSocketConnectionState.OPEN:
|
|
370
|
+
await connection.websocket.send(json.dumps(data))
|
|
371
|
+
except Exception as e:
|
|
372
|
+
print(f"Error sending message: {e}")
|
|
373
|
+
|
|
374
|
+
async def _send_error(self, connection: WebSocketConnection, error_message: str) -> None:
|
|
375
|
+
"""Send an error message to a connection"""
|
|
376
|
+
error_data = {
|
|
377
|
+
"type": "error",
|
|
378
|
+
"message": error_message,
|
|
379
|
+
"timestamp": datetime.now().isoformat()
|
|
380
|
+
}
|
|
381
|
+
await self._send_message(connection, error_data)
|
|
382
|
+
|
|
383
|
+
async def _cleanup_connection(self, connection: WebSocketConnection) -> None:
|
|
384
|
+
"""Cleanup a closed connection"""
|
|
385
|
+
connection.state = WebSocketConnectionState.CLOSED
|
|
386
|
+
self.active_connections -= 1
|
|
387
|
+
|
|
388
|
+
# Remove from all rooms
|
|
389
|
+
for room_name in connection.rooms.copy():
|
|
390
|
+
if room_name in self.rooms:
|
|
391
|
+
self.rooms[room_name].connections.discard(connection.connection_id)
|
|
392
|
+
# Remove empty rooms
|
|
393
|
+
if not self.rooms[room_name].connections:
|
|
394
|
+
del self.rooms[room_name]
|
|
395
|
+
|
|
396
|
+
# Remove connection
|
|
397
|
+
if connection.connection_id in self.connections:
|
|
398
|
+
del self.connections[connection.connection_id]
|
|
399
|
+
|
|
400
|
+
async def broadcast_to_room(self, room_name: str, message: Dict[str, Any]) -> None:
|
|
401
|
+
"""Broadcast a message to all connections in a room"""
|
|
402
|
+
if room_name not in self.rooms:
|
|
403
|
+
return
|
|
404
|
+
|
|
405
|
+
for conn_id in self.rooms[room_name].connections:
|
|
406
|
+
if conn_id in self.connections:
|
|
407
|
+
conn = self.connections[conn_id]
|
|
408
|
+
if conn.state == WebSocketConnectionState.OPEN:
|
|
409
|
+
await self._send_message(conn, message)
|
|
410
|
+
|
|
411
|
+
async def send_to_connection(self, connection_id: str, message: Dict[str, Any]) -> None:
|
|
412
|
+
"""Send a message to a specific connection"""
|
|
413
|
+
if connection_id in self.connections:
|
|
414
|
+
conn = self.connections[connection_id]
|
|
415
|
+
if conn.state == WebSocketConnectionState.OPEN:
|
|
416
|
+
await self._send_message(conn, message)
|
|
417
|
+
|
|
418
|
+
def get_connection_stats(self) -> Dict[str, Any]:
|
|
419
|
+
"""Get connection statistics"""
|
|
420
|
+
return {
|
|
421
|
+
"total_connections": self.total_connections,
|
|
422
|
+
"active_connections": self.active_connections,
|
|
423
|
+
"total_messages": self.total_messages,
|
|
424
|
+
"rooms": len(self.rooms),
|
|
425
|
+
"handlers": len(self.message_handlers)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
def get_room_info(self, room_name: str) -> Optional[Dict[str, Any]]:
|
|
429
|
+
"""Get information about a room"""
|
|
430
|
+
if room_name not in self.rooms:
|
|
431
|
+
return None
|
|
432
|
+
|
|
433
|
+
room = self.rooms[room_name]
|
|
434
|
+
return {
|
|
435
|
+
"name": room.name,
|
|
436
|
+
"connections": len(room.connections),
|
|
437
|
+
"created_at": room.created_at.isoformat(),
|
|
438
|
+
"metadata": room.metadata
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
# Global WebSocket mock server instance
|
|
443
|
+
websocket_mock_server = WebSocketMockServer()
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
# Convenience functions
|
|
447
|
+
async def start_websocket_server(host: str = "localhost", port: int = 8765) -> WebSocketMockServer:
|
|
448
|
+
"""Start a WebSocket mock server"""
|
|
449
|
+
server = WebSocketMockServer(host, port)
|
|
450
|
+
await server.start_server()
|
|
451
|
+
return server
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
def create_websocket_message_handler(pattern: str, handler_func: Callable) -> None:
|
|
455
|
+
"""Add a custom WebSocket message handler"""
|
|
456
|
+
websocket_mock_server.add_message_handler(pattern, handler_func)
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
async def broadcast_message(room: str, message: str, message_type: str = "broadcast") -> None:
|
|
460
|
+
"""Broadcast a message to a room"""
|
|
461
|
+
data = {
|
|
462
|
+
"type": message_type,
|
|
463
|
+
"message": message,
|
|
464
|
+
"timestamp": datetime.now().isoformat()
|
|
465
|
+
}
|
|
466
|
+
await websocket_mock_server.broadcast_to_room(room, data)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
async def send_private_message(connection_id: str, message: str) -> None:
|
|
470
|
+
"""Send a private message to a connection"""
|
|
471
|
+
data = {
|
|
472
|
+
"type": "private_message",
|
|
473
|
+
"message": message,
|
|
474
|
+
"timestamp": datetime.now().isoformat()
|
|
475
|
+
}
|
|
476
|
+
await websocket_mock_server.send_to_connection(connection_id, data)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: api-mocker
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: 🚀 The Ultimate API Development Acceleration Tool - 3000+ Downloads! Production-ready FastAPI mock server with AI-powered generation, scenario-based mocking, smart response matching, enhanced analytics,
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: 🚀 The Ultimate API Development Acceleration Tool - 3000+ Downloads! Production-ready FastAPI mock server with AI-powered generation, scenario-based mocking, smart response matching, enhanced analytics, comprehensive testing framework, advanced mock response management, GraphQL mocking, WebSocket support, enterprise authentication, database integration, and machine learning capabilities.
|
|
5
5
|
Author-email: sherin joseph roy <sherin.joseph2217@gmail.com>
|
|
6
6
|
License: MIT License
|
|
7
7
|
|
|
@@ -70,6 +70,19 @@ Requires-Dist: httpx>=0.24.0
|
|
|
70
70
|
Requires-Dist: rich>=13.0.0
|
|
71
71
|
Requires-Dist: psutil>=5.9.0
|
|
72
72
|
Requires-Dist: aiofiles>=23.0.0
|
|
73
|
+
Requires-Dist: websockets>=11.0.0
|
|
74
|
+
Requires-Dist: aiosqlite>=0.19.0
|
|
75
|
+
Requires-Dist: asyncpg>=0.29.0
|
|
76
|
+
Requires-Dist: motor>=3.3.0
|
|
77
|
+
Requires-Dist: pymongo>=4.6.0
|
|
78
|
+
Requires-Dist: redis>=5.0.0
|
|
79
|
+
Requires-Dist: scikit-learn>=1.3.0
|
|
80
|
+
Requires-Dist: pandas>=2.0.0
|
|
81
|
+
Requires-Dist: numpy>=1.24.0
|
|
82
|
+
Requires-Dist: pyotp>=2.9.0
|
|
83
|
+
Requires-Dist: qrcode>=7.4.0
|
|
84
|
+
Requires-Dist: PyJWT>=2.8.0
|
|
85
|
+
Requires-Dist: joblib>=1.3.0
|
|
73
86
|
Provides-Extra: advanced
|
|
74
87
|
Requires-Dist: PyJWT>=2.8.0; extra == "advanced"
|
|
75
88
|
Requires-Dist: redis>=4.5.0; extra == "advanced"
|
|
@@ -2,11 +2,16 @@ api_mocker/__init__.py,sha256=4krN1yJyngDrqVf6weYU5n3cpHpej8tE97frHPXxYqM,168
|
|
|
2
2
|
api_mocker/advanced.py,sha256=vf7pzC-ouVgT7PkSSMKLa423Z--Lj9ihC-OCNAhPOro,13429
|
|
3
3
|
api_mocker/ai_generator.py,sha256=mdha8_9HKiD9CKOT2MnJvaPC_59RwFW5NcUsGuKPP2c,17420
|
|
4
4
|
api_mocker/analytics.py,sha256=dO4uuoi-YmY6bSBYYahiwnXvTXOylR6RVDiq46UIMoA,14205
|
|
5
|
-
api_mocker/
|
|
5
|
+
api_mocker/auth_system.py,sha256=ePC0UVc0vQf5QOIVyPGyMZ41OdKgYldUxJllQyZgeHE,20496
|
|
6
|
+
api_mocker/cli.py,sha256=xRO5thj2hL7JzU0NOOTuDU8nPkl8eIfUWdMEAAv49q0,72678
|
|
6
7
|
api_mocker/config.py,sha256=zNlJCk1Bs0BrGU-92wiFv2ZTBRu9dJQ6sF8Dh6kIhLQ,913
|
|
7
8
|
api_mocker/core.py,sha256=K3rP5_cJIEpr02Qgcc_n1Ga3KPo4HumsA6Dlynaj_nQ,8478
|
|
8
9
|
api_mocker/dashboard.py,sha256=OnZOTNgKXgDU3FON6avwZ4R7NRJjqCUhQePadvRBHHM,14000
|
|
10
|
+
api_mocker/database_integration.py,sha256=oB-mGNu21bpeGhapuyklGgKYDfYqQZk6DP0zSbPcrU0,20342
|
|
9
11
|
api_mocker/enhanced_analytics.py,sha256=cSTLOft7oKZwDuy5ibUvfuSfRHmkAr9GQYU5DvtVOwI,23028
|
|
12
|
+
api_mocker/graphql_mock.py,sha256=Znxf_PcpCyGwOcuiTeoi__MXydlTGvVZsyCchHgg5SY,21744
|
|
13
|
+
api_mocker/ml_integration.py,sha256=exnOlqOOrdd4z7sj1LniYS5wVkJTPSI7FGIYEHdUREI,26348
|
|
14
|
+
api_mocker/mock_responses.py,sha256=au9-aXBXqfct_hLhCbwYgbNEfxJqPTCmETqJVsbszqU,21153
|
|
10
15
|
api_mocker/openapi.py,sha256=Pb1gKbBWosEV5i739rW0Nb3ArNq62lgMN0ecyvigNKY,7403
|
|
11
16
|
api_mocker/plugins.py,sha256=OK3OVHJszDky46JHntMVsZUH1ajBjBhAKq3TCDYuxWI,8178
|
|
12
17
|
api_mocker/recorder.py,sha256=7tiT2Krxy3nLDxFAE7rpZSimuD-rKeiwdU72cp0dg6E,9984
|
|
@@ -14,9 +19,10 @@ api_mocker/scenarios.py,sha256=wadcxu4Gp8w7i-UlPr6PlbcYnrSd1ehZA81e9dxGTgc,13392
|
|
|
14
19
|
api_mocker/server.py,sha256=xfczRj4xFXGVaGn2pVPgGvYyv3IHUlYTEz3Hop1KQu0,3812
|
|
15
20
|
api_mocker/smart_matching.py,sha256=DvTSKQwo4MhPEUHWdV3zF_H_dmp-l-47I59zz41tNe0,15067
|
|
16
21
|
api_mocker/testing.py,sha256=z4yJqS5MaSBOThpf3GtUY4dCzXTgopmnGnCuvnmKkF4,24949
|
|
17
|
-
api_mocker
|
|
18
|
-
api_mocker-0.
|
|
19
|
-
api_mocker-0.
|
|
20
|
-
api_mocker-0.
|
|
21
|
-
api_mocker-0.
|
|
22
|
-
api_mocker-0.
|
|
22
|
+
api_mocker/websocket_mock.py,sha256=bz923XE8NHFGOYvtMEinCBjYYvS0OHLL2hDWsjs9cik,17094
|
|
23
|
+
api_mocker-0.5.0.dist-info/licenses/LICENSE,sha256=FzyeLcPe623lrwpFx3xQ3W0Hb_S2sbHqLzhSXaTmcGg,1074
|
|
24
|
+
api_mocker-0.5.0.dist-info/METADATA,sha256=FlId0Vxf8Kh-wzv3JbHSwO6me_JYhgfLg5aSRJ7w1HE,15054
|
|
25
|
+
api_mocker-0.5.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
26
|
+
api_mocker-0.5.0.dist-info/entry_points.txt,sha256=dj0UIkQ36Uq3oeSjGzmRRUQKFriq4WMCzg7TCor7wkM,51
|
|
27
|
+
api_mocker-0.5.0.dist-info/top_level.txt,sha256=ZcowEudKsJ6xbvOXIno2zZcPhjB-gGO1w7uzoUKRKDM,11
|
|
28
|
+
api_mocker-0.5.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|