wse-client 1.4.0 → 1.4.2

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.
package/README.md CHANGED
@@ -20,7 +20,7 @@ Building real-time features between React and Python is painful. You need WebSoc
20
20
 
21
21
  Install `wse-server` on your backend, `wse-client` on your frontend (React or Python). Everything works immediately: auto-reconnection, message encryption, sequence ordering, offline queues, health monitoring. No configuration required for the defaults. Override what you need.
22
22
 
23
- The engine is Rust-accelerated via PyO3. Up to **14M msg/s** JSON, **30M msg/s** compressed benchmarked on AMD EPYC 7502P (32 cores) with the Rust stress-test client ([results](docs/BENCHMARKS_RUST_CLIENT.md)). Sub-millisecond connection latency (0.38ms median) with Rust JWT authentication.
23
+ The engine is Rust-accelerated via PyO3. **14M msg/s** JSON, **30M msg/s** binary, **2.1M deliveries/s** fan-out, **500K concurrent connections** with zero message loss -- benchmarked on AMD EPYC 7502P. Multi-instance horizontal scaling via Redis pub/sub. Sub-millisecond latency (0.38 ms) with Rust JWT authentication.
24
24
 
25
25
  ---
26
26
 
@@ -33,17 +33,28 @@ Embed WSE into your existing FastAPI app on the same port:
33
33
  ```python
34
34
  from fastapi import FastAPI
35
35
  from wse_server import create_wse_router, WSEConfig
36
+ import redis.asyncio as redis
36
37
 
37
38
  app = FastAPI()
38
39
 
40
+ redis_client = redis.Redis(host="localhost", port=6379, decode_responses=False)
41
+
39
42
  wse = create_wse_router(WSEConfig(
40
- redis_url="redis://localhost:6379",
43
+ redis_client=redis_client,
41
44
  ))
42
45
 
43
46
  app.include_router(wse, prefix="/wse")
47
+ ```
48
+
49
+ Publish events from anywhere in your app via the PubSub bus:
44
50
 
45
- # Publish from anywhere in your app
46
- await wse.publish("notifications", {"text": "Order shipped!", "order_id": 42})
51
+ ```python
52
+ bus = app.state.pubsub_bus
53
+
54
+ await bus.publish(
55
+ topic="notifications",
56
+ event={"event_type": "order_shipped", "order_id": 42, "text": "Order shipped!"},
57
+ )
47
58
  ```
48
59
 
49
60
  ### Server (Python) -- Standalone Mode
@@ -141,7 +152,7 @@ Connection quality scoring (excellent / good / fair / poor), latency tracking, j
141
152
 
142
153
  ### Scaling
143
154
 
144
- Redis pub/sub for multi-process fan-out. Run multiple server workers behind a load balancer. Clients get messages from any worker. Fire-and-forget delivery with sub-millisecond latency.
155
+ Redis pub/sub for multi-instance fan-out. Run N server instances behind a load balancer -- publish on any instance, all subscribers receive the message regardless of which instance they're connected to. Pipelined PUBLISH (up to 64 per round-trip), circuit breaker, exponential backoff with jitter, dead letter queue for failed messages. Capacity scales linearly with instances: tested up to 1.04M deliveries/s per instance.
145
156
 
146
157
  ### Rust Performance
147
158
 
@@ -169,7 +180,8 @@ Compression, sequencing, filtering, rate limiting, and the WebSocket server itse
169
180
  | **Snapshot Provider** | Protocol for initial state delivery. Implement `get_snapshot(user_id, topics)` and clients receive current state immediately on subscribe -- no waiting for the next publish cycle. |
170
181
  | **Circuit Breaker** | Three-state machine (CLOSED / OPEN / HALF_OPEN). Sliding-window failure tracking. Automatic recovery probes. Prevents cascade failures when downstream services are unhealthy. |
171
182
  | **Message Categories** | `S` (snapshot), `U` (update), `WSE` (system). Category prefixing for client-side routing and filtering. |
172
- | **PubSub Bus** | Redis pub/sub with PSUBSCRIBE pattern matching. orjson fast-path serialization. Custom JSON encoder for UUID, datetime, Decimal. Non-blocking handler invocation. |
183
+ | **Multi-Instance Orchestration** | Horizontal scaling via Redis pub/sub. Publish on any instance, all subscribers receive the message. Pipelined PUBLISH (64 commands/batch, 3 retries), circuit breaker (10-fail threshold, 60s reset), exponential backoff with jitter, dead letter queue (1000-entry ring buffer). 1.04M deliveries/s per instance, linear scaling with N instances. |
184
+ | **PubSub Bus** | Redis pub/sub with PSUBSCRIBE pattern matching. Glob wildcard topic routing (`user:*:events`). orjson fast-path serialization. Non-blocking handler invocation. |
173
185
  | **Pluggable Security** | `EncryptionProvider` and `TokenProvider` protocols. Built-in: AES-GCM-256 with ECDH P-256 key exchange, HMAC-SHA256 signing, selective message signing. Rust-accelerated crypto (SHA-256, HMAC, AES-GCM, ECDH). |
174
186
  | **Rust JWT Authentication** | HS256 JWT validation in Rust during the WebSocket handshake. Zero GIL acquisition on the connection critical path. 0.01ms decode (85x faster than Python). Cookie extraction and `server_ready` sent from Rust before Python runs. |
175
187
  | **Lock-Free Server Queries** | `get_connection_count()` uses `AtomicUsize` — zero GIL, zero blocking, safe to call from async Python handlers. No channel round-trip to the tokio runtime. |
@@ -210,44 +222,137 @@ Compression, sequencing, filtering, rate limiting, and the WebSocket server itse
210
222
 
211
223
  ## Performance
212
224
 
213
- Rust-accelerated engine via PyO3. Benchmarked on localhost.
225
+ Rust-accelerated engine via PyO3. AMD EPYC 7502P (32 cores, 128 GB), Ubuntu 24.04, localhost.
226
+
227
+ ### Highlights
228
+
229
+ | Metric | Value | Details |
230
+ |--------|-------|---------|
231
+ | **Peak throughput** | **14.2M msg/s** | JSON, Rust client, 500 connections |
232
+ | **Peak binary** | **30M msg/s** | MsgPack/compressed, Rust client |
233
+ | **Fan-out broadcast** | **2.1M deliveries/s** | Single-instance, zero message loss |
234
+ | **Max connections** | **500,000** | Zero errors, zero gaps at every tier |
235
+ | **Connection latency** | **0.38 ms** median | Rust JWT auth in handshake |
236
+ | **Accept rate** | **15,020 conn/s** | Sustained connection establishment |
237
+ | **Memory per conn** | **4.4 KB** | Rust core static overhead |
238
+
239
+ ### Point-to-Point (Rust Native Client)
240
+
241
+ | Payload | Throughput | Bandwidth |
242
+ |---------|-----------|-----------|
243
+ | 64 bytes | **19.4M msg/s** | 1.2 GB/s |
244
+ | 256 bytes | **12.5M msg/s** | 3.1 GB/s |
245
+ | 1 KB | **10.3M msg/s** | 10.0 GB/s |
246
+ | 16 KB | **1.2M msg/s** | **19.9 GB/s** |
247
+ | 64 KB | **284K msg/s** | **18.2 GB/s** |
248
+
249
+ ### Point-to-Point (Python Multi-Process, 64 Workers)
214
250
 
215
- ### Apple M2 (8 cores)
251
+ | Metric | JSON | MsgPack |
252
+ |--------|------|---------|
253
+ | **Sustained** | **2,045,000 msg/s** | **2,072,000 msg/s** |
254
+ | **Burst** | 1,557,000 msg/s | 1,836,000 msg/s |
255
+ | **64KB messages** | 256K msg/s (16.0 GB/s) | -- |
256
+ | **Ping RTT** | 0.26 ms median | -- |
216
257
 
217
- | Metric | Single Client | 10 Workers |
218
- |--------|--------------|------------|
219
- | **Sustained throughput (JSON)** | 113,000 msg/s | **356,000 msg/s** |
220
- | **Sustained throughput (MsgPack)** | 116,000 msg/s | **345,000 msg/s** |
221
- | **Burst throughput (JSON)** | 106,000 msg/s | **488,000 msg/s** |
222
- | **Connection latency** | **0.53 ms** median | 2.20 ms median |
223
- | **Ping RTT** | **0.09 ms** median | 0.18 ms median |
224
- | **64KB messages** | 43K msg/s (2.7 GB/s) | **164K msg/s (10.2 GB/s)** |
258
+ ### Point-to-Point (TypeScript/Node.js, 64 Processes)
225
259
 
226
- ### AMD EPYC 7502P (64 cores, 128 GB)
260
+ | Format | Throughput | Scaling |
261
+ |--------|-----------|---------|
262
+ | JSON | **7.0M msg/s** | 97% linear |
263
+ | MsgPack | **7.9M msg/s** | +13% over JSON |
227
264
 
228
- | Metric | 64 Workers | 128 Workers |
229
- |--------|-----------|-------------|
230
- | **Sustained throughput (JSON)** | **2,045,000 msg/s** | 2,013,000 msg/s |
231
- | **Sustained throughput (MsgPack)** | **2,072,000 msg/s** | 2,041,000 msg/s |
232
- | **Burst throughput (JSON)** | 1,557,000 msg/s | **1,836,000 msg/s** |
233
- | **Connection latency** | 2.60 ms median | 2.96 ms median |
234
- | **Ping RTT** | 0.26 ms median | 0.41 ms median |
235
- | **64KB messages** | **256K msg/s (16.0 GB/s)** | 238K msg/s (14.9 GB/s) |
265
+ ### Fan-out Broadcast (Single-Instance)
236
266
 
237
- See [BENCHMARKS.md](docs/BENCHMARKS.md) for full results and methodology.
267
+ Server broadcasts to N subscribers. **Zero message loss at every tier.**
268
+
269
+ | Subscribers | Deliveries/s | Bandwidth | p50 Latency |
270
+ |-------------|-------------|-----------|-------------|
271
+ | 10 | **2.1M** | 295 MB/s | 0.005 ms |
272
+ | 1,000 | 1.4M | 185 MB/s | -- |
273
+ | 10,000 | 1.2M | 163 MB/s | -- |
274
+ | 100,000 | 1.7M | 234 MB/s | -- |
275
+ | **500,000** | **1.4M** | 128 MB/s | -- |
276
+
277
+ ### Rust Acceleration vs Python
278
+
279
+ | Component | Speedup | Rust | Python |
280
+ |-----------|---------|------|--------|
281
+ | JWT decode (HS256) | **85x** | 10 us | 850 us |
282
+ | Msgpack parsing | **~50x** | -- | -- |
283
+ | Rate limiter | **40x** | -- | -- |
284
+ | HMAC-SHA256 | **22x** | -- | -- |
285
+ | Compression (zlib) | **6.7x** | -- | -- |
286
+
287
+ See benchmark docs for full results: [Overview](docs/BENCHMARKS.md) | [Rust Client](docs/BENCHMARKS_RUST_CLIENT.md) | [TypeScript Client](docs/BENCHMARKS_TS_CLIENT.md) | [Python Client](docs/BENCHMARKS_PYTHON_CLIENT.md) | [Fan-out](docs/BENCHMARKS_FANOUT.md)
238
288
 
239
289
  ---
240
290
 
241
291
  ## Use Cases
242
292
 
243
- WSE works for any real-time communication between frontend and backend:
293
+ ### Live Dashboards
294
+
295
+ Push price updates, sensor data, or analytics to the browser in real time.
296
+
297
+ ```python
298
+ # Server: push price updates
299
+ await bus.publish(
300
+ topic="prices",
301
+ event={"event_type": "price_update", "symbol": "AAPL", "price": 187.42},
302
+ )
303
+ ```
304
+
305
+ ```tsx
306
+ // React: consume them
307
+ window.addEventListener('price_update', (e: CustomEvent) => {
308
+ updateChart(e.detail.symbol, e.detail.price);
309
+ });
310
+ ```
311
+
312
+ ### Notifications
313
+
314
+ Push order updates, alerts, or system events to specific users.
315
+
316
+ ```python
317
+ # Server: notify a specific user
318
+ await bus.publish(
319
+ topic=f"user:{user_id}:events",
320
+ event={"event_type": "order_shipped", "order_id": 42, "text": "Your order shipped!"},
321
+ )
322
+ ```
323
+
324
+ ```tsx
325
+ // React: show a toast
326
+ window.addEventListener('order_shipped', (e: CustomEvent) => {
327
+ showToast(e.detail.text);
328
+ });
329
+ ```
330
+
331
+ ### Chat and Messaging
332
+
333
+ Group chats, DMs, typing indicators, read receipts. Enable encryption for privacy.
334
+
335
+ ```python
336
+ # Server: broadcast a chat message
337
+ await bus.publish(
338
+ topic=f"chat:{channel_id}",
339
+ event={"event_type": "message_sent", "text": body.text, "author": user.name},
340
+ )
341
+ ```
342
+
343
+ ```python
344
+ # Python client: listen for messages
345
+ async with connect("ws://localhost:5006/wse", token=jwt) as client:
346
+ await client.subscribe([f"chat:{channel_id}"])
347
+ async for event in client:
348
+ print(f"{event.payload['author']}: {event.payload['text']}")
349
+ ```
350
+
351
+ ### Other Use Cases
244
352
 
245
- - **Live dashboards** -- stock prices, sensor data, analytics, monitoring panels
246
- - **Notifications** -- order updates, alerts, system events pushed to the browser
247
- - **Collaborative apps** -- shared cursors, document editing, whiteboarding
248
- - **Chat and messaging** -- group chats, DMs, typing indicators, read receipts
249
- - **IoT and telemetry** -- device status, real-time metrics, command and control
250
- - **Gaming** -- game state sync, leaderboards, matchmaking updates
353
+ - **Collaborative editing** -- shared cursors, document changes, conflict detection via sequence numbers
354
+ - **IoT and telemetry** -- device status, sensor metrics, command and control. Use LOW priority for telemetry, HIGH for alerts
355
+ - **Gaming** -- game state sync, leaderboards, matchmaking. Use msgpack binary protocol for lower latency
251
356
 
252
357
  ---
253
358
 
@@ -1,5 +1,5 @@
1
1
  export declare const WS_PROTOCOL_VERSION = 1;
2
- export declare const WS_CLIENT_VERSION = "1.3.9";
2
+ export declare const WS_CLIENT_VERSION = "1.4.2";
3
3
  export declare const HEARTBEAT_INTERVAL = 15000;
4
4
  export declare const IDLE_TIMEOUT = 40000;
5
5
  export declare const CONNECTION_TIMEOUT = 10000;
package/dist/constants.js CHANGED
@@ -5,7 +5,7 @@
5
5
  // Protocol Constants
6
6
  // ---------------------------------------------------------------------------
7
7
  export const WS_PROTOCOL_VERSION = 1;
8
- export const WS_CLIENT_VERSION = '1.3.9';
8
+ export const WS_CLIENT_VERSION = '1.4.2';
9
9
  // ---------------------------------------------------------------------------
10
10
  // Connection Constants
11
11
  // ---------------------------------------------------------------------------
package/dist/index.d.ts CHANGED
@@ -21,5 +21,5 @@ export type { OfflineQueueConfig } from './services/OfflineQueue';
21
21
  export { EventHandlers } from './handlers/EventHandlers';
22
22
  export { registerAllHandlers } from './handlers/index';
23
23
  export * from './constants';
24
- export declare const WSE_VERSION = "1.3.9";
24
+ export declare const WSE_VERSION = "1.4.2";
25
25
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -44,5 +44,5 @@ export * from './constants';
44
44
  // ---------------------------------------------------------------------------
45
45
  // Version Info
46
46
  // ---------------------------------------------------------------------------
47
- export const WSE_VERSION = '1.3.9';
47
+ export const WSE_VERSION = '1.4.2';
48
48
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wse-client",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "WSE (WebSocket Engine) React client. Type-safe hooks, auto-reconnect, offline queue, E2E encryption.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",