/** * Using this to make a scanner connection to the server. */ import net from "net"; interface QueuedCommand { command: string; resolve: (value: string) => void; reject: (reason?: any) => void; timeout: NodeJS.Timeout; } const STX = "\x02"; const ETX = "\x03"; // const prodIP = process.env.SERVER_IP as string; // const prodPort = parseInt(process.env.SCANNER_PORT || "50000", 10); // const scannerID = `${process.env.SCANNER_ID}@`; //const scannerCommand = "AlplaPRODcmd00000042#000028547"; // top of the picksheet export class ScannerClient { private socket = new net.Socket(); private connected = false; private queue: QueuedCommand[] = []; private processing = false; private incomingBuffer = ""; constructor( private host: string, private port: number, private scannerId: string, ) { this.initialize(); } private initialize() { this.socket.connect(this.port, this.host, () => { console.info("Connected to scanner"); this.connected = true; }); this.socket.on("data", (data) => this.handleData(data)); this.socket.on("close", () => { console.log("Scanner connection closed"); this.connected = false; }); this.socket.on("error", (err) => { console.error("Scanner error:", err); }); } // ✅ Public method you use public scan(command: string): Promise { if (!this.connected) { return Promise.reject("Scanner not connected"); } return new Promise((resolve, reject) => { const timeout = setTimeout(() => { this.processing = false; reject("Scanner timeout"); this.processQueue(); }, 5000); // 5s safety timeout this.queue.push({ command, resolve, reject, timeout, }); this.processQueue(); }); } // ✅ Ensures strict FIFO processing private processQueue() { if (this.processing) return; if (this.queue.length === 0) return; this.processing = true; const current = this.queue[0]; const message = Buffer.from( `${STX}${this.scannerId}${current.command}${ETX}`, "ascii", ); this.socket.write(message); } // ✅ Handles full STX/ETX framed responses private handleData(data: Buffer) { console.log( "ASCII:", data .toString("ascii") .replace(/\x00/g, "") // remove null bytes .replace(/\x1B\[[0-9;?]*[A-Za-z]/g, "") // remove ANSI escape codes .trim(), ); const current = this.queue.shift(); if (current) { clearTimeout(current.timeout); current.resolve(data.toString("ascii")); } this.processing = false; this.processQueue(); } } export const scanner = new ScannerClient( process.env.SERVER_IP!, parseInt(process.env.SCANNER_PORT!, 10), `${process.env.SCANNER_ID}@`, ); // export const connectToScanner = () => { // if (!process.env.SERVER_IP || !process.env.SCANNER_PORT) { // return { // success: false, // message: "Missing ServerIP or ServerPort", // }; // } // scanner.connect(prodPort, prodIP, () => { // console.log("Connected to scanner"); // connected = true; // }); // }; // export const scan = async (command: string) => { // if (!connected) { // return { // success: false, // message: "Scanner is not connected, please contact admin", // }; // } // if (inScanCommand) { // bufferCommands.push({ timeStamp: new Date(Date.now()), command: command }); // } // // we are going to set to scanning // inScanCommand = true; // const message = Buffer.from(`${STX}${scannerID}${command}${ETX}`, "ascii"); // scanner.write(message); // await new Promise((resolve) => setTimeout(resolve, 750)); // inScanCommand = false; // if (bufferCommands.length > 0) { // await scan(bufferCommands[0].command); // bufferCommands.shift(); // } // return { // success: true, // message: "Scan completed", // }; // }; // scanner.on("data", async (data) => { // console.log( // "Response:", // data // .toString("ascii") // .replace(/\x00/g, "") // remove null bytes // .replace(/\x1B\[[0-9;?]*[A-Za-z]/g, "") // remove ANSI escape codes // .trim(), // ); // }); // scanner.on("close", () => { // console.log("Connection closed"); // }); // scanner.on("error", (err) => { // console.error("Scanner error:", err); // });