mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-23 09:42:53 +00:00
Multiplex logical sessions over the monitored daemon connection and wrap original binary bytes in routing headers. Admit channels under their authenticated parent and current grants; preserve scoped delivery and physical send completion.
34 lines
1.6 KiB
TypeScript
34 lines
1.6 KiB
TypeScript
import { MAX_WEBSOCKET_MESSAGE_BYTES } from "../websocket-message-limit.js";
|
|
/** Routing adds a bounded header; the enclosed terminal/file frame is never re-encoded. */
|
|
export const HOST_ROUTE_OPCODE = 0x30;
|
|
export const MAX_HOST_ROUTE_ID_BYTES = 256;
|
|
export const MAX_HOST_ROUTE_HEADER_BYTES = 3 + MAX_HOST_ROUTE_ID_BYTES;
|
|
export const MAX_ROUTED_PAYLOAD_BYTES = MAX_WEBSOCKET_MESSAGE_BYTES - MAX_HOST_ROUTE_HEADER_BYTES;
|
|
export interface HostRouteFrame {
|
|
routeId: string;
|
|
payload: Uint8Array;
|
|
}
|
|
export function encodeHostRouteFrame(routeId: string, payload: Uint8Array): Uint8Array {
|
|
const id = new TextEncoder().encode(routeId);
|
|
if (!id.length || id.length > MAX_HOST_ROUTE_ID_BYTES) throw new Error("Invalid host route ID");
|
|
if (payload.byteLength > MAX_ROUTED_PAYLOAD_BYTES) throw new Error("Host frame is too large");
|
|
const frame = new Uint8Array(3 + id.length + payload.byteLength);
|
|
frame[0] = HOST_ROUTE_OPCODE;
|
|
new DataView(frame.buffer).setUint16(1, id.length);
|
|
frame.set(id, 3);
|
|
frame.set(payload, 3 + id.length);
|
|
return frame;
|
|
}
|
|
export function decodeHostRouteFrame(bytes: Uint8Array): HostRouteFrame | null {
|
|
if (bytes[0] !== HOST_ROUTE_OPCODE || bytes.length < 3) return null;
|
|
const length = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint16(1);
|
|
if (!length || length > MAX_HOST_ROUTE_ID_BYTES || bytes.length < 3 + length) return null;
|
|
if (bytes.length - 3 - length > MAX_ROUTED_PAYLOAD_BYTES) return null;
|
|
try {
|
|
const routeId = new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(3, 3 + length));
|
|
return { routeId, payload: bytes.subarray(3 + length) };
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|