wse-server 2.3.2__tar.gz → 2.4.1__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.
- {wse_server-2.3.2 → wse_server-2.4.1}/PKG-INFO +14 -10
- {wse_server-2.3.2 → wse_server-2.4.1}/README.md +13 -9
- {wse_server-2.3.2 → wse_server-2.4.1}/pyproject.toml +1 -1
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/Cargo.lock +3 -3
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/Cargo.toml +1 -1
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/wse/cluster.rs +215 -26
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/wse/compression.rs +213 -4
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/wse/presence.rs +292 -33
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/wse/recovery.rs +57 -4
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/wse/security.rs +14 -9
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/wse/sequencer.rs +99 -12
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/wse/server.rs +311 -48
- {wse_server-2.3.2 → wse_server-2.4.1}/wse_server/__init__.py +1 -1
- {wse_server-2.3.2 → wse_server-2.4.1}/LICENSE +0 -0
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/.cargo/config.toml +0 -0
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/jwt.rs +0 -0
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/lib.rs +0 -0
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/wse/filters.rs +0 -0
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/wse/mod.rs +0 -0
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/wse/queue.rs +0 -0
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/wse/rate_limiter.rs +0 -0
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/wse/reliability.rs +0 -0
- {wse_server-2.3.2 → wse_server-2.4.1}/rust/src/wse/transformer.rs +0 -0
- {wse_server-2.3.2 → wse_server-2.4.1}/wse_server/_wse_accel.pyi +0 -0
- {wse_server-2.3.2 → wse_server-2.4.1}/wse_server/core/__init__.py +0 -0
- {wse_server-2.3.2 → wse_server-2.4.1}/wse_server/core/filters.py +0 -0
- {wse_server-2.3.2 → wse_server-2.4.1}/wse_server/core/types.py +0 -0
- {wse_server-2.3.2 → wse_server-2.4.1}/wse_server/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wse-server
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.1
|
|
4
4
|
Classifier: Development Status :: 5 - Production/Stable
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -80,7 +80,7 @@ High-performance WebSocket server built in Rust with native clustering, E2E encr
|
|
|
80
80
|
|---------|---------|
|
|
81
81
|
| **Key exchange** | ECDH P-256 (per-connection keypair, automatic during handshake) |
|
|
82
82
|
| **Encryption** | AES-GCM-256 with unique 12-byte IV per message |
|
|
83
|
-
| **Key derivation** | HKDF-SHA256 (salt: `wse-encryption
|
|
83
|
+
| **Key derivation** | HKDF-SHA256 (no salt, info: `wse-encryption/aes-gcm-key`) |
|
|
84
84
|
| **Wire format** | `E:` prefix + 12-byte IV + AES-GCM ciphertext + 16-byte auth tag |
|
|
85
85
|
| **Key rotation** | Configurable rotation interval (default 1 hour), automatic renegotiation |
|
|
86
86
|
| **Replay prevention** | Nonce cache (10K entries, 5-minute TTL) on the client side |
|
|
@@ -122,6 +122,7 @@ High-performance WebSocket server built in Rust with native clustering, E2E encr
|
|
|
122
122
|
| **Memory management** | Global budget (default 256 MB), TTL eviction, LRU eviction when over budget |
|
|
123
123
|
| **Zero-copy storage** | Recovery entries share `Bytes` (Arc) with the broadcast path |
|
|
124
124
|
| **Recovery on reconnect** | `subscribe_with_recovery()` replays missed messages automatically |
|
|
125
|
+
| **Per-message stamp** | When recovery is enabled, every topic broadcast carries `tp`/`e`/`o` (topic, epoch, offset) so clients dedup idempotently and detect gaps from the messages themselves |
|
|
125
126
|
|
|
126
127
|
### Client SDKs (Python + TypeScript/React)
|
|
127
128
|
|
|
@@ -132,8 +133,8 @@ High-performance WebSocket server built in Rust with native clustering, E2E encr
|
|
|
132
133
|
| **Circuit breaker** | CLOSED/OPEN/HALF_OPEN state machine, prevents connection storms |
|
|
133
134
|
| **Rate limiting** | Client-side token bucket, coordinates with server feedback |
|
|
134
135
|
| **E2E encryption** | Wire-compatible AES-GCM-256 + ECDH P-256 (both clients speak the same protocol) |
|
|
135
|
-
| **Event sequencing** | Duplicate detection (sliding window) +
|
|
136
|
-
| **Network monitor** | Real-time latency, jitter,
|
|
136
|
+
| **Event sequencing** | Duplicate detection (sliding window) + per-topic `(epoch, offset)` idempotent dedup with automatic gap recovery |
|
|
137
|
+
| **Network monitor** | Real-time latency, jitter, and connection-quality scoring (Python client also estimates packet loss) |
|
|
137
138
|
| **Priority queues** | 5 levels from CRITICAL to BACKGROUND |
|
|
138
139
|
| **Offline queue** | IndexedDB persistence (TypeScript), replayed on reconnect |
|
|
139
140
|
| **Compression** | Automatic zlib for messages above threshold |
|
|
@@ -146,8 +147,11 @@ High-performance WebSocket server built in Rust with native clustering, E2E encr
|
|
|
146
147
|
|---------|---------|
|
|
147
148
|
| **Origin validation** | Configure in reverse proxy (nginx/Caddy) to prevent CSWSH |
|
|
148
149
|
| **Cookie auth** | `access_token` HTTP-only cookie with `Secure + SameSite=Lax` (OWASP recommended for browsers) |
|
|
149
|
-
| **Frame protection** | 1 MB max frame size, serde_json parsing (no eval), escaped user IDs in server_ready |
|
|
150
|
+
| **Frame protection** | 1 MB max frame size, serde_json parsing (no eval), escaped user IDs in server_ready; inbound msgpack rejected beyond 64 nesting levels |
|
|
150
151
|
| **Cluster frame protection** | zstd decompression output capped at 1 MB (MAX_FRAME_SIZE), protocol version validation |
|
|
152
|
+
| **Slowloris protection** | At most 512 concurrent pre-handshake connections; sockets that never complete the WS upgrade are bounded and dropped |
|
|
153
|
+
| **Bounded callback dispatch** | Callback mode caps in-flight `on_message` callbacks at 256 per connection; excess inbound work is shed and counted as rate-limited |
|
|
154
|
+
| **Fail-closed recovery ACL** | Recovery replay applies the connection's topic ACL — unauthorized topics are never replayed or position-probed |
|
|
151
155
|
|
|
152
156
|
---
|
|
153
157
|
|
|
@@ -359,10 +363,10 @@ result = server.subscribe_with_recovery(
|
|
|
359
363
|
epoch=client_epoch, # From previous session
|
|
360
364
|
offset=client_offset, # From previous session
|
|
361
365
|
)
|
|
362
|
-
# {"topics": {"prices": {"epoch":
|
|
366
|
+
# {"topics": {"prices": {"epoch": "0000007b", "offset": 456, "recovered": True, "count": 12}}}
|
|
363
367
|
```
|
|
364
368
|
|
|
365
|
-
The server maintains per-topic ring buffers (power-of-2 capacity, bitmask indexing).
|
|
369
|
+
The server maintains per-topic ring buffers (power-of-2 capacity, bitmask indexing). When recovery is enabled, every topic broadcast is stamped with `tp`/`e`/`o` (topic, epoch, offset) fields, so clients track their per-topic position from the messages themselves, drop duplicates idempotently by `(epoch, offset)`, and automatically request recovery when they detect an offset gap. On reconnect, the server replays missed messages from the ring buffer. If the gap is too large or the epoch has changed, the client receives a `NotRecovered` status and should re-subscribe from scratch.
|
|
366
370
|
|
|
367
371
|
Memory is managed with a global budget (default 256 MB), TTL eviction for idle buffers, and LRU eviction when over budget.
|
|
368
372
|
|
|
@@ -543,7 +547,7 @@ def handle(event):
|
|
|
543
547
|
client.run_forever()
|
|
544
548
|
```
|
|
545
549
|
|
|
546
|
-
Key features: 4 reconnect strategies (exponential, linear, fibonacci, adaptive), connection pool with health scoring and 3 load balancing strategies, circuit breaker, token bucket rate limiter, event sequencer with dedup and
|
|
550
|
+
Key features: 4 reconnect strategies (exponential, linear, fibonacci, adaptive), connection pool with health scoring and 3 load balancing strategies, circuit breaker, token bucket rate limiter, event sequencer with id dedup plus per-topic `(epoch, offset)` idempotent dedup and gap recovery, network quality monitoring (latency/jitter/packet loss).
|
|
547
551
|
|
|
548
552
|
See [python-client/](python-client/) for full source and examples.
|
|
549
553
|
|
|
@@ -571,7 +575,7 @@ function App() {
|
|
|
571
575
|
|
|
572
576
|
Key features: offline queue with IndexedDB persistence, adaptive quality management, connection pool with health scoring, E2E encryption (Web Crypto API), message batching, 5 priority levels, Zustand store for external state access.
|
|
573
577
|
|
|
574
|
-
See [client/](client/) for full source and examples.
|
|
578
|
+
See [ts-client/](ts-client/) for full source and examples.
|
|
575
579
|
|
|
576
580
|
---
|
|
577
581
|
|
|
@@ -614,7 +618,7 @@ Working examples in the [`examples/`](examples/) directory:
|
|
|
614
618
|
- [Rust Utilities](docs/RUST_UTILITIES.md) - priority queues, rate limiters, sequencing, compression, crypto, JWT
|
|
615
619
|
- [Security](docs/SECURITY.md) - JWT, encryption, mTLS, rate limiting, circuit breaker
|
|
616
620
|
- [Deployment](docs/DEPLOYMENT.md) - production setup, Docker, Kubernetes, cluster configuration
|
|
617
|
-
- [Migration Guide](docs/MIGRATION.md) - upgrading from v1.x to v2.
|
|
621
|
+
- [Migration Guide](docs/MIGRATION.md) - upgrading from v1.x to v2.x
|
|
618
622
|
- [Contributing](CONTRIBUTING.md) - development setup and coding standards
|
|
619
623
|
- [Changelog](CHANGELOG.md) - version history
|
|
620
624
|
|
|
@@ -39,7 +39,7 @@ High-performance WebSocket server built in Rust with native clustering, E2E encr
|
|
|
39
39
|
|---------|---------|
|
|
40
40
|
| **Key exchange** | ECDH P-256 (per-connection keypair, automatic during handshake) |
|
|
41
41
|
| **Encryption** | AES-GCM-256 with unique 12-byte IV per message |
|
|
42
|
-
| **Key derivation** | HKDF-SHA256 (salt: `wse-encryption
|
|
42
|
+
| **Key derivation** | HKDF-SHA256 (no salt, info: `wse-encryption/aes-gcm-key`) |
|
|
43
43
|
| **Wire format** | `E:` prefix + 12-byte IV + AES-GCM ciphertext + 16-byte auth tag |
|
|
44
44
|
| **Key rotation** | Configurable rotation interval (default 1 hour), automatic renegotiation |
|
|
45
45
|
| **Replay prevention** | Nonce cache (10K entries, 5-minute TTL) on the client side |
|
|
@@ -81,6 +81,7 @@ High-performance WebSocket server built in Rust with native clustering, E2E encr
|
|
|
81
81
|
| **Memory management** | Global budget (default 256 MB), TTL eviction, LRU eviction when over budget |
|
|
82
82
|
| **Zero-copy storage** | Recovery entries share `Bytes` (Arc) with the broadcast path |
|
|
83
83
|
| **Recovery on reconnect** | `subscribe_with_recovery()` replays missed messages automatically |
|
|
84
|
+
| **Per-message stamp** | When recovery is enabled, every topic broadcast carries `tp`/`e`/`o` (topic, epoch, offset) so clients dedup idempotently and detect gaps from the messages themselves |
|
|
84
85
|
|
|
85
86
|
### Client SDKs (Python + TypeScript/React)
|
|
86
87
|
|
|
@@ -91,8 +92,8 @@ High-performance WebSocket server built in Rust with native clustering, E2E encr
|
|
|
91
92
|
| **Circuit breaker** | CLOSED/OPEN/HALF_OPEN state machine, prevents connection storms |
|
|
92
93
|
| **Rate limiting** | Client-side token bucket, coordinates with server feedback |
|
|
93
94
|
| **E2E encryption** | Wire-compatible AES-GCM-256 + ECDH P-256 (both clients speak the same protocol) |
|
|
94
|
-
| **Event sequencing** | Duplicate detection (sliding window) +
|
|
95
|
-
| **Network monitor** | Real-time latency, jitter,
|
|
95
|
+
| **Event sequencing** | Duplicate detection (sliding window) + per-topic `(epoch, offset)` idempotent dedup with automatic gap recovery |
|
|
96
|
+
| **Network monitor** | Real-time latency, jitter, and connection-quality scoring (Python client also estimates packet loss) |
|
|
96
97
|
| **Priority queues** | 5 levels from CRITICAL to BACKGROUND |
|
|
97
98
|
| **Offline queue** | IndexedDB persistence (TypeScript), replayed on reconnect |
|
|
98
99
|
| **Compression** | Automatic zlib for messages above threshold |
|
|
@@ -105,8 +106,11 @@ High-performance WebSocket server built in Rust with native clustering, E2E encr
|
|
|
105
106
|
|---------|---------|
|
|
106
107
|
| **Origin validation** | Configure in reverse proxy (nginx/Caddy) to prevent CSWSH |
|
|
107
108
|
| **Cookie auth** | `access_token` HTTP-only cookie with `Secure + SameSite=Lax` (OWASP recommended for browsers) |
|
|
108
|
-
| **Frame protection** | 1 MB max frame size, serde_json parsing (no eval), escaped user IDs in server_ready |
|
|
109
|
+
| **Frame protection** | 1 MB max frame size, serde_json parsing (no eval), escaped user IDs in server_ready; inbound msgpack rejected beyond 64 nesting levels |
|
|
109
110
|
| **Cluster frame protection** | zstd decompression output capped at 1 MB (MAX_FRAME_SIZE), protocol version validation |
|
|
111
|
+
| **Slowloris protection** | At most 512 concurrent pre-handshake connections; sockets that never complete the WS upgrade are bounded and dropped |
|
|
112
|
+
| **Bounded callback dispatch** | Callback mode caps in-flight `on_message` callbacks at 256 per connection; excess inbound work is shed and counted as rate-limited |
|
|
113
|
+
| **Fail-closed recovery ACL** | Recovery replay applies the connection's topic ACL — unauthorized topics are never replayed or position-probed |
|
|
110
114
|
|
|
111
115
|
---
|
|
112
116
|
|
|
@@ -318,10 +322,10 @@ result = server.subscribe_with_recovery(
|
|
|
318
322
|
epoch=client_epoch, # From previous session
|
|
319
323
|
offset=client_offset, # From previous session
|
|
320
324
|
)
|
|
321
|
-
# {"topics": {"prices": {"epoch":
|
|
325
|
+
# {"topics": {"prices": {"epoch": "0000007b", "offset": 456, "recovered": True, "count": 12}}}
|
|
322
326
|
```
|
|
323
327
|
|
|
324
|
-
The server maintains per-topic ring buffers (power-of-2 capacity, bitmask indexing).
|
|
328
|
+
The server maintains per-topic ring buffers (power-of-2 capacity, bitmask indexing). When recovery is enabled, every topic broadcast is stamped with `tp`/`e`/`o` (topic, epoch, offset) fields, so clients track their per-topic position from the messages themselves, drop duplicates idempotently by `(epoch, offset)`, and automatically request recovery when they detect an offset gap. On reconnect, the server replays missed messages from the ring buffer. If the gap is too large or the epoch has changed, the client receives a `NotRecovered` status and should re-subscribe from scratch.
|
|
325
329
|
|
|
326
330
|
Memory is managed with a global budget (default 256 MB), TTL eviction for idle buffers, and LRU eviction when over budget.
|
|
327
331
|
|
|
@@ -502,7 +506,7 @@ def handle(event):
|
|
|
502
506
|
client.run_forever()
|
|
503
507
|
```
|
|
504
508
|
|
|
505
|
-
Key features: 4 reconnect strategies (exponential, linear, fibonacci, adaptive), connection pool with health scoring and 3 load balancing strategies, circuit breaker, token bucket rate limiter, event sequencer with dedup and
|
|
509
|
+
Key features: 4 reconnect strategies (exponential, linear, fibonacci, adaptive), connection pool with health scoring and 3 load balancing strategies, circuit breaker, token bucket rate limiter, event sequencer with id dedup plus per-topic `(epoch, offset)` idempotent dedup and gap recovery, network quality monitoring (latency/jitter/packet loss).
|
|
506
510
|
|
|
507
511
|
See [python-client/](python-client/) for full source and examples.
|
|
508
512
|
|
|
@@ -530,7 +534,7 @@ function App() {
|
|
|
530
534
|
|
|
531
535
|
Key features: offline queue with IndexedDB persistence, adaptive quality management, connection pool with health scoring, E2E encryption (Web Crypto API), message batching, 5 priority levels, Zustand store for external state access.
|
|
532
536
|
|
|
533
|
-
See [client/](client/) for full source and examples.
|
|
537
|
+
See [ts-client/](ts-client/) for full source and examples.
|
|
534
538
|
|
|
535
539
|
---
|
|
536
540
|
|
|
@@ -573,7 +577,7 @@ Working examples in the [`examples/`](examples/) directory:
|
|
|
573
577
|
- [Rust Utilities](docs/RUST_UTILITIES.md) - priority queues, rate limiters, sequencing, compression, crypto, JWT
|
|
574
578
|
- [Security](docs/SECURITY.md) - JWT, encryption, mTLS, rate limiting, circuit breaker
|
|
575
579
|
- [Deployment](docs/DEPLOYMENT.md) - production setup, Docker, Kubernetes, cluster configuration
|
|
576
|
-
- [Migration Guide](docs/MIGRATION.md) - upgrading from v1.x to v2.
|
|
580
|
+
- [Migration Guide](docs/MIGRATION.md) - upgrading from v1.x to v2.x
|
|
577
581
|
- [Contributing](CONTRIBUTING.md) - development setup and coding standards
|
|
578
582
|
- [Changelog](CHANGELOG.md) - version history
|
|
579
583
|
|
|
@@ -1491,9 +1491,9 @@ dependencies = [
|
|
|
1491
1491
|
|
|
1492
1492
|
[[package]]
|
|
1493
1493
|
name = "rustls-webpki"
|
|
1494
|
-
version = "0.103.
|
|
1494
|
+
version = "0.103.13"
|
|
1495
1495
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1496
|
-
checksum = "
|
|
1496
|
+
checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
|
|
1497
1497
|
dependencies = [
|
|
1498
1498
|
"aws-lc-rs",
|
|
1499
1499
|
"ring",
|
|
@@ -2327,7 +2327,7 @@ dependencies = [
|
|
|
2327
2327
|
|
|
2328
2328
|
[[package]]
|
|
2329
2329
|
name = "wse-accel"
|
|
2330
|
-
version = "2.
|
|
2330
|
+
version = "2.4.0"
|
|
2331
2331
|
dependencies = [
|
|
2332
2332
|
"aes-gcm",
|
|
2333
2333
|
"ahash",
|