techniq / node-pn532

Native Node.js driver for the PN532 NFC chip
73 stars 32 forks source link

Remove listeners and scanTag timeout #8

Open alexit84 opened 8 years ago

alexit84 commented 8 years ago

Hello, I'm playing with your library with Raspberry Pi and PN532 Breakout board. Everything is working well :)

I had the need to set a timeout to the scanTag() function if if nothing had been found. So I needed a function to stop all the pending listeners. This worked like a charm for me:

removeListeners() {
        this.frameEmitter.removeAllListeners();
}

Maybe this can be useful for others.

Anyway, maybe a timeout parameter on the scanTag() function could be the best option...

Thank you, Alessandro

techniq commented 8 years ago

Glad to hear it's working well :)

Not sure I fully understanding the need to remove the listeners. Are you calling scanTag directly (and then waiting on the promise), or listening for the tag event (which calls/polls scanTag)?

Thus far I typically just listen for the tag event and respond whenever that may be (seconds/minutes/days...).

alexit84 commented 8 years ago

Hi, you are right, I've not explained well my need. I'm making a simple REST server with Express to get data from Nfc tags. I call directly the scanTag waiting on the promise, but I would like to stop that request after a set timeout if an event didn't happen. This is an example of my code:

app.post('/read', function (req, res) {
    var timeout = setTimeout(function () {
      res.status(504).send("No tag found");
      rfid.removeListeners();
    }, 10000);

    rfid.scanTag().then(function(tag) {
        clearTimeout(timeout);
        console.log("Tag: "+ tag.uid);
        var result = {};
        result.uid = tag.uid.replace(/:/g,'');
        rfid.readNdefData().then(function(data) {
            if (data != null || data != undefined) {
                var records = ndef.decodeMessage(data.toJSON().data);
                if (records[0].type == "U")
                    result.uri = records[0].value;
                else if (records[0].type == "T")
                    result.text = records[0].value;
            } 
            console.log(JSON.stringify(result));
            res.status(200).send(result);
        });
    });
});

If the result does not come within 10s, the user is informed and the promise is cancelled (he can not wait indefinitely...)
I'm happy with the result I got, but probably there are better ways to accomplish the same results. I'm opened to suggestions :)

Thank you, Alessandro

techniq commented 8 years ago

Awe, makes sense know seeing your use case. I could see having the ability to timeout or cancel a command. I think currently you could access the frameEmitter directly without having to patch in the direct removeListeners()

...
    var timeout = setTimeout(function () {
      res.status(504).send("No tag found");
      rfid.frameEmitter.removeListeners();
    }, 10000);
...

Since promises can't be cancelled, it might be worth looking at using Observables/RxJS which allow cancelling a "future" value

alexit84 commented 8 years ago

Unfortunately that line give this error: TypeError: rfid.frameEmitter.removeListeners is not a function