76 lines
3.0 KiB
JavaScript
76 lines
3.0 KiB
JavaScript
// WSTS codec — encoder/decoder for the WebSocket frames MWSE exchanges.
|
|
//
|
|
// Infrastructure for issue #42 (binary framing). The codec is pluggable: today
|
|
// it speaks JSON text frames (mode=CODEC_JSON); the binary path (mode=CODEC_BINARY)
|
|
// is stubbed and will be wired once the server side lands.
|
|
//
|
|
// Frame shapes (codec-agnostic, defined by WSTS protocol):
|
|
// Inbound from server: [payload, signalName] — signal
|
|
// [payload, id, 'E'|'C'] — reply
|
|
// Outbound to server: [msg, 'R'] — fire-and-forget (WOM)
|
|
// [msg, id, 'R'] — request (reply once)
|
|
// [msg, id, 'S'] — stream (reply multiple)
|
|
import { CODEC_JSON, CODEC_BINARY } from './version.js';
|
|
|
|
export class WSTSCodec {
|
|
constructor() {
|
|
this.mode = CODEC_JSON;
|
|
}
|
|
|
|
// encode turns a JS frame array into a wire value (string or ArrayBuffer).
|
|
encode(frame) {
|
|
if (this.mode === CODEC_JSON) {
|
|
return JSON.stringify(frame);
|
|
}
|
|
if (this.mode === CODEC_BINARY) {
|
|
return this._encodeBinary(frame);
|
|
}
|
|
throw new Error(`WSTSCodec: unknown mode ${this.mode}`);
|
|
}
|
|
|
|
// decode turns raw wire data into a JS frame array.
|
|
decode(raw) {
|
|
if (typeof raw === 'string') {
|
|
return JSON.parse(raw);
|
|
}
|
|
if (raw instanceof ArrayBuffer) {
|
|
if (this.mode === CODEC_BINARY) {
|
|
return this._decodeBinary(raw);
|
|
}
|
|
throw new Error('WSTSCodec: received binary frame but codec is in JSON mode');
|
|
}
|
|
throw new Error(`WSTSCodec: unexpected frame type ${typeof raw}`);
|
|
}
|
|
|
|
// negotiate picks the best codec from the server's offered list and activates it.
|
|
// Returns true when a common codec was found.
|
|
negotiate(serverCodecs) {
|
|
// Prefer binary when both sides support it (future upgrade path).
|
|
if (serverCodecs.includes(CODEC_BINARY)) {
|
|
this.mode = CODEC_BINARY;
|
|
return true;
|
|
}
|
|
if (serverCodecs.includes(CODEC_JSON)) {
|
|
this.mode = CODEC_JSON;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ---- Binary codec (issue #42) ----------------------------------------
|
|
// Wire layout: 1-byte opcode | 4-byte uint32 big-endian payload length | payload bytes
|
|
// Opcodes: 0x01 = signal, 0x02 = reply-end ('E'), 0x03 = reply-continue ('C'),
|
|
// 0x04 = request ('R'), 0x05 = stream ('S'), 0x06 = wom ('R' no id)
|
|
// Payload: MessagePack (or CBOR) encoded frame contents.
|
|
// This is intentionally NOT implemented yet — throws so callers know when they
|
|
// accidentally reach binary paths before #42 is merged.
|
|
|
|
_encodeBinary(_frame) {
|
|
throw new Error('WSTSCodec binary encoding not yet implemented (#42)');
|
|
}
|
|
|
|
_decodeBinary(_buf) {
|
|
throw new Error('WSTSCodec binary decoding not yet implemented (#42)');
|
|
}
|
|
}
|