Skip to content

Commit 6d0d984

Browse files
authored
Merge pull request #51 from dschweinbenz/fix/usb-listener
fix #50: Solved removing all usb detach listeners
2 parents 43ba9ed + 22d0348 commit 6d0d984

File tree

3 files changed

+91
-15
lines changed

3 files changed

+91
-15
lines changed

.changeset/tidy-ways-flash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@node-escpos/usb-adapter": patch
3+
---
4+
5+
Solved removing all usb detach listeners

packages/usb-adapter/src/index.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ export default class USBAdapter extends Adapter<[]> {
2323

2424
constructor(vid?: number | usb.Device, pid?: number) {
2525
super();
26-
// eslint-disable-next-line @typescript-eslint/no-this-alias
27-
const self = this;
26+
// Bind class reference this to the method
27+
this.detachDevice = this.detachDevice.bind(this);
28+
2829
if (vid && pid && typeof vid === "number") {
2930
this.device = findByIds(vid, pid) || null;
3031
}
@@ -45,13 +46,15 @@ export default class USBAdapter extends Adapter<[]> {
4546
if (!this.device)
4647
throw new Error("Can not find printer");
4748

48-
usb.on("detach", (device) => {
49-
if (device === self.device) {
50-
self.emit("detach", device);
51-
self.emit("disconnect", device);
52-
self.device = null;
53-
}
54-
});
49+
usb.on("detach", this.detachDevice);
50+
}
51+
52+
private detachDevice(device: usb.Device) {
53+
if (device === this.device) {
54+
this.emit("detach", device);
55+
this.emit("disconnect", device);
56+
this.device = null;
57+
}
5558
}
5659

5760
static findPrinter() {
@@ -151,7 +154,7 @@ export default class USBAdapter extends Adapter<[]> {
151154
if (!this.device) callback?.(new Error("Device not found"));
152155
try {
153156
this.device?.close();
154-
usb.removeAllListeners("detach");
157+
usb.removeListener('detach', this.detachDevice);
155158
callback && callback(null);
156159
this.emit("close", this.device);
157160
}
Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,75 @@
1-
import { describe, expect, it } from 'vitest'
1+
import { describe, expect, it, vi } from 'vitest';
2+
import { Device, usb } from 'usb';
3+
import USBAdapter from '../src';
4+
import { promisify } from 'util';
25

36
describe('should', () => {
4-
it('exported', () => {
5-
expect(1).toEqual(1)
6-
})
7-
})
7+
it('Validate findPrinter devices', () => {
8+
const printers = USBAdapter.findPrinter();
9+
if (printers.length > 0) {
10+
// Validate printer iface class for all received printers
11+
for (const printer of printers) {
12+
if (printer.configDescriptor !== undefined) {
13+
let hasPrinterClass = false;
14+
exit_loop:
15+
for (const iface of printer.configDescriptor?.interfaces) {
16+
for (const conf of iface) {
17+
if (conf.bInterfaceClass === 0x07) {
18+
hasPrinterClass = true;
19+
break exit_loop;
20+
}
21+
}
22+
}
23+
expect(hasPrinterClass).to.be.true;
24+
}
25+
}
26+
}
27+
});
28+
29+
it('Validate adapter listeners', async () => {
30+
const printer = new USBAdapter();
31+
32+
const handler = vi.fn();
33+
printer.addListener('close', handler);
34+
35+
const openDevice = promisify(printer.open).bind(printer);
36+
await openDevice();
37+
const closeDevice = promisify(printer.close).bind(printer);
38+
await closeDevice();
39+
40+
expect(handler).toBeCalledTimes(1);
41+
});
42+
43+
it('Validate usb listeners', async () => {
44+
let listenerCount = usb.listenerCount('detach');
45+
const printer = new USBAdapter();
46+
let listenerCountAfter = usb.listenerCount('detach');
47+
// Save last recognized listener function for validation
48+
const libraryListenerFn = usb.listeners('detach')[listenerCountAfter - 1];
49+
expect(listenerCountAfter).to.be.greaterThan(listenerCount);
50+
51+
// Create custom listener and validate if it still exists after device close
52+
listenerCount = listenerCountAfter;
53+
function listenerExec() {}
54+
usb.on('detach', listenerExec);
55+
listenerCountAfter = usb.listenerCount('detach');
56+
expect(listenerCountAfter).to.be.greaterThan(listenerCount);
57+
58+
const openDevice = promisify(printer.open).bind(printer);
59+
await openDevice();
60+
const closeDevice = promisify(printer.close).bind(printer);
61+
await closeDevice(); // Only the internal listener should be removed
62+
63+
expect(usb.listenerCount('detach')).to.be.lessThan(listenerCountAfter);
64+
let libListenerRemoved = true, customListenerStillExist = false;
65+
for (const listenerFn of usb.listeners('detach')) {
66+
if (listenerFn === libraryListenerFn) {
67+
libListenerRemoved = false;
68+
} else if (listenerFn === listenerExec) {
69+
customListenerStillExist = true;
70+
}
71+
}
72+
expect(libListenerRemoved).to.be.true;
73+
expect(customListenerStillExist).to.be.true;
74+
});
75+
});

0 commit comments

Comments
 (0)