Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error: Can't close device with a pending request #92

Open
KylianJay opened this issue Apr 21, 2024 · 1 comment
Open

Error: Can't close device with a pending request #92

KylianJay opened this issue Apr 21, 2024 · 1 comment

Comments

@KylianJay
Copy link

I've switched to using USB adapter since I thought this would fix my many stability issues. It did not.
Instead, I now get this error. What is causing this?
`/home/kylianjay/Documents/osozai/osozai-qrmenu-master/pi/node_modules/usb/dist/usb/device.js:80
this.__close();
^

Error: Can't close device with a pending request
at Device.close (/home/kylianjay/Documents/osozai/osozai-qrmenu-master/pi/node_modules/usb/dist/usb/device.js:80:14)
at USBAdapter.close (file:///home/kylianjay/Documents/osozai/osozai-qrmenu-master/pi/node_modules/@node-escpos/usb-adapter/dist/index.mjs:133:20)
at file:///home/kylianjay/Documents/osozai/osozai-qrmenu-master/pi/node_modules/@node-escpos/core/dist/index.mjs:1159:20
at new Promise ()
at Printer.close (file:///home/kylianjay/Documents/osozai/osozai-qrmenu-master/pi/node_modules/@node-escpos/core/dist/index.mjs:1158:12)

Node.js v20.11.0
`
I'm on a Raspberry Pi Model 3, for context.

The code in question that causes this issue is here:
`app.post('/create/order', async (req, res) => {
// we're getting an order! let's print it!
console.log("printing order with id: #" + req.body.id)
console.log(req.body)
let foodString = "";
let drinksString = "";
let dessertsString = "";

if (req.body.items && Array.isArray(req.body.items) && req.body.items.length > 0) {
    const donItems = req.body.items[0].don;
    const drinkItems = req.body.items[0].drinks;
    const dessertsItems = req.body.items[0].desserts;

    if (donItems && Array.isArray(donItems)) {
        const food = donItems.map(donItem => {
            let itemString = donItem.name.replace(/[^\P{L}a-zA-Z]/g, '') + ` `;

            // Check if extraToppings exist and is an array before adding the line
            if (Array.isArray(donItem.selectedToppings) && donItem.selectedToppings.length > 0) {
                const options = donItem.selectedToppings.map(topping => topping.name.replace(/[^\P{L}a-zA-Z\s]/g, ''));
                itemString += `\n Options: (${options.join(', ')})`;
            }

            return itemString;
        });
        foodString = food.join("\n ");
    }

    if (drinkItems && Array.isArray(drinkItems)) {
        const drinks = drinkItems.map(drinkItem => {
            let itemString = drinkItem.name.replace(/[^\P{L}a-zA-Z]/g, '') + ``;

            // Check if milkOptions exist before adding the line
            // Check if extraToppings exist and is an array before adding the line
            if (Array.isArray(drinkItem.selectedToppings) && drinkItem.selectedToppings.length > 0) {
                const options = drinkItem.selectedToppings.map(topping => topping.name.replace(/[^\P{L}a-zA-Z\s]/g, ''));
                itemString += `\n Options: (${options.join(', ')})`;
            }

            return itemString;
        });
        drinksString = drinks.join("\n ");
    }

    if (dessertsItems && Array.isArray(dessertsItems)) {
        const desserts = dessertsItems.map(dessertItem => {
            let itemString = dessertItem.name.replace(/[^\P{L}a-zA-Z]/g, '') + ``;

            // Check if extraToppings exist and is an array before adding the line
            if (Array.isArray(dessertItem.selectedToppings) && dessertItem.selectedToppings.length > 0) {
                const options = dessertItem.selectedToppings.map(topping => topping.name.replace(/[^\P{L}a-zA-Z\s]/g, ''));
                itemString += `\n Options: (${options.join(', ')})`;
            }

            return itemString;
        });
        dessertsString = desserts.join("\n ");
    }

    const separationLine = "-------------------------";

    // Check if there are items for Food before adding the separation line
    if (foodString && (drinksString || dessertsString)) {
        foodString += `\n${separationLine}\n`;
    }

    // Check if there are items for Drinks before adding the separation line
    if (drinksString && dessertsString) {
        drinksString += `\n${separationLine}\n`;
    }
}

try {
    const separationLine = "-------------------------";
    console.log("sending " 
    + "Order ID: " + req.body.id
    + "Table: " + req.body.table
    + "Food: " + foodString
    + "Drinks: " + drinksString
    + "Desserts: " + dessertsString
    + "Total: " + "€" + req.body.priceTotal + ",-"
    + "Date: " + req.body.datetime
    + "Notes: " + req.body.notes
    + "to printer")
    res.status(200).send("Order: " + req.body.id + " Printed")

    const print = () => {
        return new Promise((resolve, reject) => {
            const device = new USB();
            const options = { encoding: "GB18030" /* default */ }
            let printer = new Printer(device, options);
          device.open(function (error) {
            if (error) {
              return reject(error);
            }
            printer
            .font('b')
            .align('ct')
            .size(1,1)
            .text("Receipt 1 of 2")
            .style('bu')
            .size(2, 2)
            .text('New order for Table: ' + req.body.table)
            .text(`\n${separationLine}\n`)
            .text('Food: ' + foodString)
            .text('Drinks: ' + drinksString)
            .text('Desserts: ' + dessertsString)
            .text(`\n${separationLine}\n`)
            .text('Notes: ' + req.body.notes)
            .font('a')
            .size(1, 1)
            .text(`\n${separationLine}\n`)
            .text('Total: ' +  "€" + req.body.priceTotal + ",-")
            .text('Date: ' + req.body.datetime)
            .text('Order ID: ' + req.body.id)
            .text(" ")
            .cut()
            .font('b')
            .align('ct')
            .size(1,1)
            .text("Receipt 2 of 2")
            .style('bu')
            .size(2, 2)
            .text('New order for Table: ' + req.body.table)
            .text(`\n${separationLine}\n`)
            .text('Food: ' + foodString)
            .text('Drinks: ' + drinksString)
            .text('Desserts: ' + dessertsString)
            .text(`\n${separationLine}\n`)
            .text('Notes: ' + req.body.notes)
            .font('a')
            .size(1, 1)
            .text(`\n${separationLine}\n`)
            .text('Total: ' +  req.body.priceTotal)
            .text('Date: ' + req.body.datetime)
            .text('Order ID: ' + req.body.id)
            .text(" ")

            printer
            .cut()
            .close(() => {
                resolve();
            });
          });
        });
      };
      await print();
      console.log('did it get here?')
}

catch (error) {
    console.log(error)
    res.status(400).send("Error printing order: " + req.body.id + " Error: " + error)
}

})`

Again, any help is greatly appreciated!

Copy link

dosubot bot commented Apr 21, 2024

The error "Can't close device with a pending request" typically occurs when trying to close the USB device connection while there are still ongoing or pending I/O operations. This means that your application is attempting to close the connection before all data transfers have finished. To resolve this, you need to ensure that all pending operations are completed or canceled before calling the close method on the device. This might involve adding logic to track ongoing operations and waiting for these to complete before proceeding with the device closure.

Here's a more structured approach to manage printing operations asynchronously, which can help prevent such errors:

const print = (text) => {
  return new Promise((resolve, reject) => {
    device.open(function (error) {
      if (error) {
        return reject(error);
      }
      printer
        .font('a')
        .align('ct')
        .style('bu')
        .size(1, 1)
        .text(text)
        .cut()
        .close(() => {
          resolve();
        });
    });
  });
};

By wrapping your printing logic in a Promise and using async/await, you can ensure that the device is not closed until all operations have been completed. This approach helps in managing the lifecycle of the stream more effectively and reduces the likelihood of encountering errors related to premature closure of the device.

Additionally, ensure that all libraries, especially escpos and its dependencies, are up to date and compatible with your Node.js version (v20.11.0). Incompatibilities can also lead to unexpected errors, including those related to stream and device management.

Details

Sources


About Dosu
This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a 👍 if this is helpful and 👎 if it is irrelevant.

To continue the conversation, mention @dosu.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant