HeligPfleigh / react-native-thermal-receipt-printer

A RN library for thermal printer
163 stars 103 forks source link

Problem with bluetooth printer is off, but paired with device #60

Open Rc85 opened 3 years ago

Rc85 commented 3 years ago

Current Behavior

My setup is that when my device turns on and if there is paired bluetooth printer, it will automatically attempt a connection to it. The problem is that if the printer is turned off, the device is still paired, there will be a slight hang of the entire app (eg. - I cannot click on an order to open order details and all buttons are non-interactive).

My component heirachy is like so

<App>
  <Printer> <-- getDeviceList, connectPrinter, all happening in this component
  <Orders> <-- customer orders
</App>

It doesn't seem like it's a state management issue as I am setting the state in <Printer /> only. I tried adding a loading state to <Printer /> so that when it stops hanging, it finishes loading. But it doesn't work, it seems the issue is a synchronous issue. The loading will disappear even before the hang is resolved.

The error that comes up after the hang is read failed, socket might closed or timeout, read ret: -1 and this is from the connectPrinter function..

When my app loads, I get the printers.

const getPrinters = async () => {
    if (Platform.OS === 'android') {
      await BLEPrinter.init()
        .then(async () => {
          await BLEPrinter.getDeviceList()
            .then((result) => {
              console.log('Printers', result);
              if (result) setPrinters(result);
            })
            .catch((err) => console.log(err));
        })
        .catch((err) => console.log('Bluetooth Error', err));
    }
  };

And if one is found, I connect to it

export const connectPrinter = async (
  printers: any,
  selectedPrinter: any,
  restaurantLocation: LocationLocationsInterface | undefined
) => {
  let connectedPrinter;

  if (printers.length > 0) {
    const macAddress = restaurantLocation?.settings.printer
      ? restaurantLocation.settings.printer.inner_mac_address
      : selectedPrinter.inner_mac_address;

    await BLEPrinter.connectPrinter(macAddress)
      .then((printer) => {
        if (printer && macAddress == printer.inner_mac_address) {
          Toast.show({
            text: 'Bluetooth printer connected',
            type: 'success',
            duration: 3000
          });

          connectedPrinter = printer;
        }
      })
      .catch((err) => console.log(err));
  }

  return connectedPrinter;
};

Expected Behavior

The connection to printer should happen asynchronously and not block any kind of operations if it fails to connect due to the error shown above.

How to reproduce

Create a component that automatically connects to a pair bluetooth printer, but not turned on when the component mounts/renders.

Your Environment

software version
iOS or Android 11
react-native 0.63.0
node 14.16
npm or yarn 6.14.11
nguyen-vo commented 3 years ago

I would not use async/await with promises.

Since JavaScript is a single threat programming language, when using async/await, it will wait until the process is done before starting a new process. It seems that the Time to live of BLEPrinter when connecting to an unavailable device is very long. So you don't want to wait for the process. Instead, just let it run parallel by not using async/await. If any printer was not able to print then set an error message or some indicator. I would recommend using react-native-toast-message.

nguyen-vo commented 3 years ago

Apparently, I ran into this issue. The problem isn’t with promises nor async/await. It seems like the Connect function is set with a very long Time To Live. To resolve this you can use connectToDevice function in ‘react-native-ble-plx’ and set the time to live to 1000ms. If it couldn't connect to your printer it will throw an error. Then you can handle error in the catch