Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 64x 64x 64x 19x 64x 64x 64x 64x 64x 2x 2x 2x 62x 62x 1x 1x 61x 61x 48x 48x 2x 2x 4x 4x 3x 3x 2x 2x 1x 1x 1x 1x | import type { RawData, WebSocket } from "ws";
import type { Logger } from "@shared/logger";
import type { ClientToServerWSMessage } from "@shared/schema";
import { decodeClientMessage } from "../../services/ws-message-decoder";
import type { ClientState } from "./ws-session-manager";
function rawDataToString(data: RawData): string {
Iif (Array.isArray(data)) return Buffer.concat(data).toString();
Iif (data instanceof ArrayBuffer) return Buffer.from(data).toString();
return data.toString();
}
type MessageHandler<T extends ClientToServerWSMessage> = (
ws: WebSocket,
data: T,
clientState: ClientState,
) => void | Promise<void>;
export interface WsMessageRouterHandlers {
startSimulation: MessageHandler<Extract<ClientToServerWSMessage, { type: "start_simulation" }>>;
codeChanged: MessageHandler<Extract<ClientToServerWSMessage, { type: "code_changed" }>>;
stopSimulation: MessageHandler<Extract<ClientToServerWSMessage, { type: "stop_simulation" }>>;
pauseSimulation: MessageHandler<Extract<ClientToServerWSMessage, { type: "pause_simulation" }>>;
resumeSimulation: MessageHandler<Extract<ClientToServerWSMessage, { type: "resume_simulation" }>>;
serialInput: MessageHandler<Extract<ClientToServerWSMessage, { type: "serial_input" }>>;
setPinValue: MessageHandler<Extract<ClientToServerWSMessage, { type: "set_pin_value" }>>;
}
interface WsMessageRouterParams {
logger: Logger;
getClientState: (ws: WebSocket) => ClientState | undefined;
handlers: WsMessageRouterHandlers;
}
export class WsMessageRouter {
constructor(private readonly params: WsMessageRouterParams) {}
async route(ws: WebSocket, message: RawData): Promise<void> {
try {
const msgText = rawDataToString(message);
this.params.logger.debug(`[WS-IN] ${msgText}`);
const data = decodeClientMessage(msgText);
if (!data) {
this.params.logger.warn("[WS] Rejected invalid client message");
ws.close(1008, "Invalid message");
return;
}
const clientState = this.params.getClientState(ws);
if (!clientState) {
this.params.logger.warn(
`[WS] Message received but clientState not found for type: ${data.type}`,
);
return;
}
await this.dispatch(ws, data, clientState);
} catch (error) {
this.params.logger.error(
`Invalid WebSocket message: ${error instanceof Error ? error.message : String(error)}`,
);
}
}
private async dispatch(
ws: WebSocket,
data: ClientToServerWSMessage,
clientState: ClientState,
): Promise<void> {
switch (data.type) {
case "start_simulation":
await this.params.handlers.startSimulation(ws, data, clientState);
break;
case "code_changed":
await this.params.handlers.codeChanged(ws, data, clientState);
break;
case "stop_simulation":
await this.params.handlers.stopSimulation(ws, data, clientState);
break;
case "pause_simulation":
await this.params.handlers.pauseSimulation(ws, data, clientState);
break;
case "resume_simulation":
await this.params.handlers.resumeSimulation(ws, data, clientState);
break;
case "serial_input":
await this.params.handlers.serialInput(ws, data, clientState);
break;
case "set_pin_value":
await this.params.handlers.setPinValue(ws, data, clientState);
break;
}
}
}
|