diff --git a/test/client-test.mjs b/test/client-test.mjs new file mode 100644 index 0000000..2e36df9 --- /dev/null +++ b/test/client-test.mjs @@ -0,0 +1,139 @@ +#!/usr/bin/env node +/** + * Test the ViceClient directly by importing from the bundled dist + */ + +import { Socket } from "net"; + +const HOST = "127.0.0.1"; +const PORT = 6502; + +const STX = 0x02; +const API_VERSION = 0x02; +const CMD_DISPLAY_GET = 0x84; + +let requestId = 0; +let socket; +let responseBuffer = Buffer.alloc(0); + +function nextRequestId() { + requestId = (requestId + 1) & 0xffffffff; + return requestId; +} + +function buildPacket(command, body) { + // Same format as MCP client: 11-byte header + const header = Buffer.alloc(11); + header[0] = STX; + header[1] = API_VERSION; + header.writeUInt32LE(body.length, 2); + header.writeUInt32LE(nextRequestId(), 6); + header[10] = command; + return Buffer.concat([header, body]); +} + +async function connect() { + return new Promise((resolve, reject) => { + socket = new Socket(); + socket.on("connect", resolve); + socket.on("error", reject); + socket.connect(PORT, HOST); + }); +} + +async function sendDisplayGet() { + return new Promise((resolve, reject) => { + // Body: useVicii(1) + format(1) - exactly like MCP client.getDisplay() + const body = Buffer.alloc(2); + body[0] = 1; // useVicii = true + body[1] = 0; // format = indexed 8-bit + + const packet = buildPacket(CMD_DISPLAY_GET, body); + const reqId = requestId; + + console.log(`Sending DisplayGet, reqId=${reqId}`); + console.log(`Packet (${packet.length} bytes): ${packet.toString("hex")}`); + + const timeout = setTimeout(() => { + reject(new Error("Timeout waiting for DisplayGet response")); + }, 15000); + + const handleData = () => { + while (responseBuffer.length >= 12) { + if (responseBuffer[0] !== STX) { + responseBuffer = responseBuffer.subarray(1); + continue; + } + + const bodyLength = responseBuffer.readUInt32LE(2); + const totalLength = 12 + bodyLength; + + if (responseBuffer.length < totalLength) { + console.log(`Waiting for more data: have ${responseBuffer.length}, need ${totalLength}`); + break; + } + + const responseType = responseBuffer[6]; + const errorCode = responseBuffer[7]; + const respReqId = responseBuffer.readUInt32LE(8); + const respBody = responseBuffer.subarray(12, totalLength); + + console.log(`Got response: type=0x${responseType.toString(16)}, error=0x${errorCode.toString(16)}, reqId=${respReqId}, bodyLen=${respBody.length}`); + + responseBuffer = responseBuffer.subarray(totalLength); + + // Skip async events + if (respReqId === 0xffffffff) { + console.log(` (async event, skipping)`); + continue; + } + + if (respReqId === reqId) { + clearTimeout(timeout); + socket.off("data", onData); + resolve({ responseType, errorCode, body: respBody }); + return; + } + } + }; + + const onData = (data) => { + console.log(`Received ${data.length} bytes`); + responseBuffer = Buffer.concat([responseBuffer, data]); + handleData(); + }; + + socket.on("data", onData); + socket.write(packet); + }); +} + +async function main() { + console.log("Testing DisplayGet with MCP client packet format...\n"); + + console.log("1. Connecting..."); + await connect(); + console.log(" Connected!\n"); + + console.log("2. Sending DisplayGet..."); + try { + const resp = await sendDisplayGet(); + if (resp.errorCode !== 0) { + console.log(` ERROR: 0x${resp.errorCode.toString(16)}`); + } else { + const width = resp.body.readUInt16LE(4); + const height = resp.body.readUInt16LE(6); + const bufferLength = resp.body.readUInt32LE(17); + console.log(` SUCCESS! ${width}x${height}, ${bufferLength} bytes`); + } + } catch (err) { + console.log(` FAILED: ${err.message}`); + } + + socket.end(); +} + +main().catch(err => { + console.error("Fatal:", err); + process.exit(1); +});