feat: 6 web client variants — all wire-compatible with WZP protocol

3 new WZP-WS variants (speak WZP wire format over WebSocket):
- wzp-ws.js (Variant 4): WZP MediaHeader + raw PCM, no WASM
- wzp-ws-fec.js (Variant 5): WZP + WASM RaptorQ FEC (block=5, symbol=2048)
- wzp-ws-full.js (Variant 6): WZP + FEC + ChaCha20-Poly1305 E2E encryption

Wire protocol compliance (verified against wzp-proto/src/packet.rs):
- MediaHeader 12-byte bit layout: V(1)|T(1)|CodecID(4)|Q(1)|FecRatioHi(1)
- FEC ratio 7-bit encoding across byte0-byte1 boundary
- All fields big-endian (seq u16, timestamp u32)
- Crypto nonce: session_id[4] + seq_be[4] + direction[1] + pad[3]
- HKDF info: "warzone-session-key" (matches wzp-crypto)

Auth flow (matches wzp-relay/src/ws.rs):
- First WS message: {"type":"auth","token":"..."}
- Relay responds: {"type":"auth_ok"} or {"type":"auth_error"}
- All 6 variants handle auth_ok/auth_error text messages

Updated:
- wzp-core.js: detectVariant() accepts ws, ws-fec, ws-full
- index.html: script map + ClientClass dispatch for all 6 variants
- index.html: WASM auto-loading for variants with loadWasm()

URL patterns:
  ?variant=pure       Variant 1: Raw PCM over WS (bridge needed)
  ?variant=hybrid     Variant 2: Raw PCM + WASM FEC (bridge needed)
  ?variant=full       Variant 3: WebTransport + FEC + crypto (no bridge)
  ?variant=ws         Variant 4: WZP protocol over WS (relay direct)
  ?variant=ws-fec     Variant 5: WZP + FEC over WS (relay direct)
  ?variant=ws-full    Variant 6: WZP + FEC + E2E crypto over WS (relay direct)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-03-30 14:53:53 +04:00
parent ec437afbce
commit 2de6e19956
5 changed files with 1664 additions and 12 deletions

View File

@@ -66,9 +66,12 @@
(function() {
var variant = WZPCore.detectVariant();
var scriptMap = {
pure: 'js/wzp-pure.js',
hybrid: 'js/wzp-hybrid.js',
full: 'js/wzp-full.js',
pure: 'js/wzp-pure.js',
hybrid: 'js/wzp-hybrid.js',
full: 'js/wzp-full.js',
'ws': 'js/wzp-ws.js',
'ws-fec': 'js/wzp-ws-fec.js',
'ws-full': 'js/wzp-ws-full.js',
};
var src = scriptMap[variant] || scriptMap.pure;
var s = document.createElement('script');
@@ -117,8 +120,17 @@ function wzpBoot() {
var proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
var wsUrl = proto + '//' + location.host + '/ws/' + encodeURIComponent(room);
// Create client based on selected variant
// Create client based on detected variant
var variant = WZPCore.detectVariant();
var ClientClass = {
pure: window.WZPPureClient,
hybrid: window.WZPHybridClient,
full: window.WZPFullClient,
'ws': window.WZPWsClient,
'ws-fec': window.WZPWsFecClient,
'ws-full': window.WZPWsFullClient,
}[variant] || window.WZPPureClient;
var clientOpts = {
wsUrl: wsUrl,
room: room,
@@ -133,14 +145,23 @@ function wzpBoot() {
},
};
if (variant === 'full' && typeof WZPFullClient !== 'undefined') {
// Full variant: add WebTransport URL, falls back to WS if WT unavailable
// Full variant: add WebTransport URL for direct relay connection
if (variant === 'full') {
clientOpts.url = location.origin.replace('http', 'https');
client = new WZPFullClient(clientOpts);
} else if (variant === 'hybrid' && typeof WZPHybridClient !== 'undefined') {
client = new WZPHybridClient(clientOpts);
} else {
client = new WZPPureClient(clientOpts);
}
client = new ClientClass(clientOpts);
// Load WASM for variants that need it
if (client.loadWasm) {
try {
WZPCore.updateStatus('Loading WASM module...');
await client.loadWasm();
} catch (e) {
WZPCore.updateStatus('WASM load failed: ' + e.message);
ui.setConnected(false);
return;
}
}
try {