ARTICLE AD BOX
I apologize if this is impossible, unadvisable, or answered elsewhere, but I have spent a couple days trying to find an answer as well as changing/testing the code every way I could think of without achieving my desired result.
I have an internal web application written in Node with an API endpoint (Express) that calls a function to send data to a printer using a Net socket. The code itself works (as far as the fetch, function call, and socket connection) and we use this same flow/functionality in other applications. However, I am trying to make it so that the Express API endpoint waits to send its response until after the Net socket connection is either made or errors, so that the response can be appropriate (5xx for error, 2xx for successful socket connection). This is because while the code works, sometimes the printer is in an error state and the socket connection times-out, but the Express response is always "success" as the function call is successful.
My desired flow is this: client browser makes a fetch call to the endpoint; the endpoint takes the req.body data and calls the printing function; the printing function attempts a socket connection to the printer, and returns either true or false to the endpoint (if the socket connects or errors); the endpoint then, having waited for the return, sends a res.status(...).send(...) with correct code and response data (JSON), so that the client browser can display the appropriate message of success or failure.
Below are the snippets of code used in this flow, with some details changed for privacy. This version of the code is the original "working" set, not including any of the wild/weird things I have tried over the last couple days. In other testing versions I have tried using async/await, wrapping with a promise, etc., but no matter what I do the sendToPrinter function always returns true before the socket connects or errors, with the console.logs output order indicating this.
Any tips, suggestions, advice, or corrections are appreciated! And please don't just tell me this is bad practice, etc., this is a custom internal application for a specific task in an industrial setting. I am only interested in whether my desired functionality is even possible, and how to make it so.
/* router.js */ import express from 'express'; import { printKit } from './controller.js'; const api = express.Router(); export default api; api.post('/printKit/', (req, res, next) => { if (printKit(req.body.lotNumber, req.body.expirationDate, req.body.printer)) res.send({ 'success': true, 'message': 'Successful print', 'lotNumber': req.body.lotNumber, 'expirationDate': req.body.expirationDate, 'printer': { 'host': (req.body.printer) ? req.body.printer.host || 'default' : 'default', 'port': (req.body.printer) ? req.body.printer.port || 'default' : 'default' } }); else res.status(500).send({ 'success': false, 'message': 'Issue sending print', 'lotNumber': req.body.lotNumber, 'expirationDate': req.body.expirationDate, 'printer': { 'host': (req.body.printer) ? req.body.printer.host || 'default' : 'default', 'port': (req.body.printer) ? req.body.printer.port || 'default' : 'default' } }); }); /* controller.js */ import net from 'net'; export { printKit }; const defaultPrinter2x3 = {'host':'0.0.0.0', 'port':9100}; // ip changed for privacy const printKit = (lotNumber, expirationDate, printer = defaultPrinter2x3) => { if (!printer.host || !printer.port) printer = defaultPrinter2x3; console.log(`\nEntry: printKit(${lotNumber},${expirationDate},{${printer.host},${printer.port}})`); const shortExpirationDate = shortenDate(expirationDate); const zpl = `this code removed for privacy`; const success = sendToPrinter(printer,zpl); if(success) return true; else return false; }; const sendToPrinter = (printer, zpl) => { console.log(`\nEntry: sendToPrinter({${printer.host},${printer.port}}, ${zpl})`); if(!printer) { console.log('No printer host/port specified'); return false; } if(!printer.host || !printer.port) { console.log('No printer host/port specified'); return false; } const { host, port } = printer; const data = Buffer.from(zpl); try { const socket = new net.Socket(); socket.connect(printer.port, printer.host, async () => { socket.write(data, (err) => { if (err) { console.error('Error connecting to printer: ', err); throw new Error(err); } else { console.log('Successfully sent data to printer'); } }); socket.end(); }); socket.on('close', () => { console.log('Closed connection to printer'); }); socket.on('error', (err) => { console.error('Connection error:', err.message); throw new Error(err); }) } catch (error) { console.error('Error in printing:', error); return false; } console.log('End of function'); return true; };