usb 2.5.0 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.5.1] - 2022-08-29
4
+
5
+ ### Fixed
6
+ - USB device plug/unplug detection on Windows when devce already attached - [`531`](https://github.com/node-usb/node-usb/pull/531) ([Rob Moran](https://github.com/thegecko))
7
+ - Removed dependency on yarn in package.json scripts - [`535`](https://github.com/node-usb/node-usb/pull/535) ([Rob Moran](https://github.com/thegecko))
8
+
3
9
  ## [2.5.0] - 2022-07-30
4
10
 
5
11
  ### Fixed
package/README.md CHANGED
@@ -594,11 +594,17 @@ git submodule update --init
594
594
  ```
595
595
 
596
596
  ## Building
597
- The package uses `yarn` for the typescript code and `prebuildify` to generate the native binaries. These can be executed as follows:
597
+ The package uses `prebuildify` to generate the native binaries using an `install` script and `TypeScript` for the binding code using the `compile` script. The package can be built as follows:
598
598
 
599
599
  ```bash
600
600
  yarn
601
- yarn prebuild
601
+ yarn compile
602
+ ```
603
+
604
+ The native binaries can be rebuilt with:
605
+
606
+ ```bash
607
+ yarn rebuild
602
608
  ```
603
609
 
604
610
  __Note:__ On Linux, you'll need libudev to build libusb. On Ubuntu/Debian:
@@ -4,14 +4,18 @@ interface EventListeners<T> {
4
4
  newListener: keyof T;
5
5
  removeListener: keyof T;
6
6
  }
7
+ interface DeviceIds {
8
+ idVendor: number;
9
+ idProduct: number;
10
+ }
7
11
  declare module './bindings' {
8
12
  interface Device extends ExtendedDevice {
9
13
  }
10
14
  interface DeviceEvents extends EventListeners<DeviceEvents> {
11
15
  attach: Device;
12
16
  detach: Device;
13
- attachIds: undefined;
14
- detachIds: undefined;
17
+ attachIds: DeviceIds;
18
+ detachIds: DeviceIds;
15
19
  }
16
20
  function addListener<K extends keyof DeviceEvents>(event: K, listener: (arg: DeviceEvents[K]) => void): void;
17
21
  function removeListener<K extends keyof DeviceEvents>(event: K, listener: (arg: DeviceEvents[K]) => void): void;
package/dist/usb/index.js CHANGED
@@ -21,50 +21,52 @@ Object.setPrototypeOf(usb, events_1.EventEmitter.prototype);
21
21
  Object.getOwnPropertyNames(device_1.ExtendedDevice.prototype).forEach(function (name) {
22
22
  Object.defineProperty(usb.Device.prototype, name, Object.getOwnPropertyDescriptor(device_1.ExtendedDevice.prototype, name) || Object.create(null));
23
23
  });
24
- // Polling mechanism for discovering device changes where hotplug detection is not available
25
- var pollTimeout = 500;
24
+ // Hotplug support
26
25
  var hotplugSupported = usb._supportedHotplugEvents();
27
- var pollingHotplug = false;
28
- var pollDevices = new Set();
29
- var pollHotplugOnce = function (start) {
26
+ // Devices delta support for non-libusb hotplug events
27
+ // This methd needs to be used for attach/detach IDs (hotplugSupportType === 2) rather than a lookup because vid/pid are not unique
28
+ var hotPlugDevices = new Set();
29
+ var emitHotplugEvents = function () {
30
30
  var e_1, _a, e_2, _b;
31
31
  // Collect current devices
32
32
  var devices = new Set(usb.getDeviceList());
33
- if (!start) {
34
- try {
35
- // Find attached devices
36
- for (var devices_1 = __values(devices), devices_1_1 = devices_1.next(); !devices_1_1.done; devices_1_1 = devices_1.next()) {
37
- var device = devices_1_1.value;
38
- if (!pollDevices.has(device))
39
- usb.emit('attach', device);
40
- }
41
- }
42
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
43
- finally {
44
- try {
45
- if (devices_1_1 && !devices_1_1.done && (_a = devices_1.return)) _a.call(devices_1);
33
+ try {
34
+ // Find attached devices
35
+ for (var devices_1 = __values(devices), devices_1_1 = devices_1.next(); !devices_1_1.done; devices_1_1 = devices_1.next()) {
36
+ var device = devices_1_1.value;
37
+ if (!hotPlugDevices.has(device)) {
38
+ usb.emit('attach', device);
46
39
  }
47
- finally { if (e_1) throw e_1.error; }
48
40
  }
41
+ }
42
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
43
+ finally {
49
44
  try {
50
- // Find detached devices
51
- for (var pollDevices_1 = __values(pollDevices), pollDevices_1_1 = pollDevices_1.next(); !pollDevices_1_1.done; pollDevices_1_1 = pollDevices_1.next()) {
52
- var device = pollDevices_1_1.value;
53
- if (!devices.has(device))
54
- usb.emit('detach', device);
55
- }
45
+ if (devices_1_1 && !devices_1_1.done && (_a = devices_1.return)) _a.call(devices_1);
56
46
  }
57
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
58
- finally {
59
- try {
60
- if (pollDevices_1_1 && !pollDevices_1_1.done && (_b = pollDevices_1.return)) _b.call(pollDevices_1);
47
+ finally { if (e_1) throw e_1.error; }
48
+ }
49
+ try {
50
+ // Find detached devices
51
+ for (var hotPlugDevices_1 = __values(hotPlugDevices), hotPlugDevices_1_1 = hotPlugDevices_1.next(); !hotPlugDevices_1_1.done; hotPlugDevices_1_1 = hotPlugDevices_1.next()) {
52
+ var device = hotPlugDevices_1_1.value;
53
+ if (!devices.has(device)) {
54
+ usb.emit('detach', device);
61
55
  }
62
- finally { if (e_2) throw e_2.error; }
63
56
  }
64
57
  }
65
- pollDevices = devices;
58
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
59
+ finally {
60
+ try {
61
+ if (hotPlugDevices_1_1 && !hotPlugDevices_1_1.done && (_b = hotPlugDevices_1.return)) _b.call(hotPlugDevices_1);
62
+ }
63
+ finally { if (e_2) throw e_2.error; }
64
+ }
65
+ hotPlugDevices = devices;
66
66
  };
67
- var pollHotplugLoop = function (start) {
67
+ // Polling mechanism for checking device changes where hotplug detection is not available
68
+ var pollingHotplug = false;
69
+ var pollHotplug = function (start) {
68
70
  if (start === void 0) { start = false; }
69
71
  if (start) {
70
72
  pollingHotplug = true;
@@ -72,33 +74,53 @@ var pollHotplugLoop = function (start) {
72
74
  else if (!pollingHotplug) {
73
75
  return;
74
76
  }
75
- pollHotplugOnce(start);
76
- setTimeout(function () {
77
- pollHotplugLoop();
78
- }, pollTimeout);
77
+ else {
78
+ emitHotplugEvents();
79
+ }
80
+ setTimeout(function () { return pollHotplug(); }, 500);
81
+ };
82
+ // Hotplug control
83
+ var startHotplug = function () {
84
+ if (hotplugSupported !== 1) {
85
+ // Collect initial devices when not using libusb
86
+ hotPlugDevices = new Set(usb.getDeviceList());
87
+ }
88
+ if (hotplugSupported) {
89
+ // Use hotplug event emitters
90
+ usb._enableHotplugEvents();
91
+ if (hotplugSupported === 2) {
92
+ // Use hotplug ID events to trigger a change check
93
+ usb.on('attachIds', emitHotplugEvents);
94
+ usb.on('detachIds', emitHotplugEvents);
95
+ }
96
+ }
97
+ else {
98
+ // Fallback to using polling to check for changes
99
+ pollHotplug(true);
100
+ }
101
+ };
102
+ var stopHotplug = function () {
103
+ if (hotplugSupported) {
104
+ // Disable hotplug events
105
+ usb._disableHotplugEvents();
106
+ if (hotplugSupported === 2) {
107
+ // Remove hotplug ID event listeners
108
+ usb.off('attachIds', emitHotplugEvents);
109
+ usb.off('detachIds', emitHotplugEvents);
110
+ }
111
+ }
112
+ else {
113
+ // Stop polling
114
+ pollingHotplug = false;
115
+ }
79
116
  };
80
- var hotplugModeIsIdsOnly = hotplugSupported === 2;
81
- if (hotplugModeIsIdsOnly) {
82
- // The hotplug backend doesnt emit 'attach' or 'detach', so we need to do some conversion
83
- var hotplugEventConversion = function () {
84
- // Future: This might want a debounce, to avoid doing multiple polls when attaching a usb hub or something
85
- pollHotplugOnce(false);
86
- };
87
- usb.on('attachIds', hotplugEventConversion);
88
- usb.on('detachIds', hotplugEventConversion);
89
- }
90
117
  usb.on('newListener', function (event) {
91
118
  if (event !== 'attach' && event !== 'detach') {
92
119
  return;
93
120
  }
94
121
  var listenerCount = usb.listenerCount('attach') + usb.listenerCount('detach');
95
122
  if (listenerCount === 0) {
96
- if (hotplugSupported) {
97
- usb._enableHotplugEvents();
98
- }
99
- else {
100
- pollHotplugLoop(true);
101
- }
123
+ startHotplug();
102
124
  }
103
125
  });
104
126
  usb.on('removeListener', function (event) {
@@ -107,12 +129,7 @@ usb.on('removeListener', function (event) {
107
129
  }
108
130
  var listenerCount = usb.listenerCount('attach') + usb.listenerCount('detach');
109
131
  if (listenerCount === 0) {
110
- if (hotplugSupported) {
111
- usb._disableHotplugEvents();
112
- }
113
- else {
114
- pollingHotplug = false;
115
- }
132
+ stopHotplug();
116
133
  }
117
134
  });
118
135
  module.exports = usb;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../tsc/usb/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../tsc/usb/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "usb",
3
3
  "description": "Library to access USB devices",
4
4
  "license": "MIT",
5
- "version": "2.5.0",
5
+ "version": "2.5.1",
6
6
  "main": "dist/index.js",
7
7
  "engines": {
8
8
  "node": ">=10.20.0 <11.x || >=12.17.0 <13.0 || >=14.0.0"
@@ -36,12 +36,11 @@
36
36
  "hardware"
37
37
  ],
38
38
  "scripts": {
39
- "prepare": "yarn compile",
40
39
  "install": "node-gyp-build",
41
40
  "rebuild": "node-gyp rebuild",
42
- "clean": "git clean -dfx",
43
- "compile": "tsc && yarn lint && yarn docs",
44
- "lint": "eslint . --ext .ts",
41
+ "clean": "git clean -fx ./build ./prebuilds ./dist ./docs ./node_modules",
42
+ "compile": "tsc",
43
+ "postcompile": "eslint . --ext .ts",
45
44
  "watch": "tsc -w --preserveWatchOutput",
46
45
  "test": "mocha --require coffeescript/register --grep Module test/*",
47
46
  "full-test": "mocha --require coffeescript/register test/*.coffee",
Binary file
Binary file
Binary file
@@ -61,12 +61,11 @@ void handleHotplug(HotPlug* info) {
61
61
  Napi::Object v8dev = Device::get(env, dev);
62
62
  libusb_unref_device(dev);
63
63
 
64
- Napi::Value v8Vid = env.Null();
65
- Napi::Value v8Pid = env.Null();
64
+ Napi::Object v8VidPid = Napi::Object::New(env);
66
65
  auto deviceDescriptor = v8dev.Get("deviceDescriptor");
67
66
  if (deviceDescriptor.IsObject()) {
68
- v8Vid = deviceDescriptor.As<Napi::Object>().Get("idVendor");
69
- v8Pid = deviceDescriptor.As<Napi::Object>().Get("idProduct");
67
+ v8VidPid.Set("idVendor", deviceDescriptor.As<Napi::Object>().Get("idVendor"));
68
+ v8VidPid.Set("idProduct", deviceDescriptor.As<Napi::Object>().Get("idProduct"));
70
69
  }
71
70
 
72
71
  Napi::String eventName;
@@ -87,5 +86,5 @@ void handleHotplug(HotPlug* info) {
87
86
  }
88
87
 
89
88
  hotplugThis->Get("emit").As<Napi::Function>().MakeCallback(hotplugThis->Value(), { eventName, v8dev });
90
- hotplugThis->Get("emit").As<Napi::Function>().MakeCallback(hotplugThis->Value(), { changeEventName, v8Vid, v8Pid });
89
+ hotplugThis->Get("emit").As<Napi::Function>().MakeCallback(hotplugThis->Value(), { changeEventName, v8VidPid });
91
90
  }
@@ -135,8 +135,9 @@ void handleHotplug(HotPlug* info) {
135
135
 
136
136
  int vid = info->vid;
137
137
  int pid = info->pid;
138
- auto v8Vid = Napi::Number::New(env, vid);
139
- auto v8Pid = Napi::Number::New(env, pid);
138
+ Napi::Object v8VidPid = Napi::Object::New(env);
139
+ v8VidPid.Set("idVendor", Napi::Number::New(env, vid));
140
+ v8VidPid.Set("idProduct", Napi::Number::New(env, pid));
140
141
  CM_NOTIFY_ACTION event = info->event;
141
142
  delete info;
142
143
 
@@ -156,5 +157,5 @@ void handleHotplug(HotPlug* info) {
156
157
  return;
157
158
  }
158
159
 
159
- hotplugThis->Get("emit").As<Napi::Function>().MakeCallback(hotplugThis->Value(), { eventName, v8Vid, v8Pid });
160
+ hotplugThis->Get("emit").As<Napi::Function>().MakeCallback(hotplugThis->Value(), { eventName, v8VidPid });
160
161
  }
package/tsc/usb/index.ts CHANGED
@@ -18,6 +18,11 @@ interface EventListeners<T> {
18
18
  removeListener: keyof T;
19
19
  }
20
20
 
21
+ interface DeviceIds {
22
+ idVendor: number;
23
+ idProduct: number;
24
+ }
25
+
21
26
  declare module './bindings' {
22
27
 
23
28
  /* eslint-disable @typescript-eslint/no-empty-interface */
@@ -26,8 +31,8 @@ declare module './bindings' {
26
31
  interface DeviceEvents extends EventListeners<DeviceEvents> {
27
32
  attach: Device;
28
33
  detach: Device;
29
- attachIds: undefined;
30
- detachIds: undefined;
34
+ attachIds: DeviceIds;
35
+ detachIds: DeviceIds;
31
36
  }
32
37
 
33
38
  function addListener<K extends keyof DeviceEvents>(event: K, listener: (arg: DeviceEvents[K]) => void): void;
@@ -42,58 +47,84 @@ declare module './bindings' {
42
47
  function listenerCount<K extends keyof DeviceEvents>(event: K): number;
43
48
  }
44
49
 
45
- // Polling mechanism for discovering device changes where hotplug detection is not available
46
- const pollTimeout = 500;
50
+ // Hotplug support
47
51
  const hotplugSupported = usb._supportedHotplugEvents();
48
- let pollingHotplug = false;
49
- let pollDevices = new Set<usb.Device>();
50
52
 
51
- const pollHotplugOnce = (start: boolean) => {
53
+ // Devices delta support for non-libusb hotplug events
54
+ // This methd needs to be used for attach/detach IDs (hotplugSupportType === 2) rather than a lookup because vid/pid are not unique
55
+ let hotPlugDevices = new Set<usb.Device>();
56
+ const emitHotplugEvents = () => {
52
57
  // Collect current devices
53
58
  const devices = new Set(usb.getDeviceList());
54
59
 
55
- if (!start) {
56
- // Find attached devices
57
- for (const device of devices) {
58
- if (!pollDevices.has(device))
59
- usb.emit('attach', device);
60
+ // Find attached devices
61
+ for (const device of devices) {
62
+ if (!hotPlugDevices.has(device)) {
63
+ usb.emit('attach', device);
60
64
  }
65
+ }
61
66
 
62
- // Find detached devices
63
- for (const device of pollDevices) {
64
- if (!devices.has(device))
65
- usb.emit('detach', device);
67
+ // Find detached devices
68
+ for (const device of hotPlugDevices) {
69
+ if (!devices.has(device)) {
70
+ usb.emit('detach', device);
66
71
  }
67
72
  }
68
73
 
69
- pollDevices = devices;
74
+ hotPlugDevices = devices;
70
75
  };
71
76
 
72
- const pollHotplugLoop = (start = false) => {
77
+ // Polling mechanism for checking device changes where hotplug detection is not available
78
+ let pollingHotplug = false;
79
+ const pollHotplug = (start = false) => {
73
80
  if (start) {
74
81
  pollingHotplug = true;
75
82
  } else if (!pollingHotplug) {
76
83
  return;
84
+ } else {
85
+ emitHotplugEvents();
86
+ }
87
+
88
+ setTimeout(() => pollHotplug(), 500);
89
+ };
90
+
91
+ // Hotplug control
92
+ const startHotplug = () => {
93
+ if (hotplugSupported !== 1) {
94
+ // Collect initial devices when not using libusb
95
+ hotPlugDevices = new Set(usb.getDeviceList());
77
96
  }
78
97
 
79
- pollHotplugOnce(start);
98
+ if (hotplugSupported) {
99
+ // Use hotplug event emitters
100
+ usb._enableHotplugEvents();
80
101
 
81
- setTimeout(() => {
82
- pollHotplugLoop();
83
- }, pollTimeout);
102
+ if (hotplugSupported === 2) {
103
+ // Use hotplug ID events to trigger a change check
104
+ usb.on('attachIds', emitHotplugEvents);
105
+ usb.on('detachIds', emitHotplugEvents);
106
+ }
107
+ } else {
108
+ // Fallback to using polling to check for changes
109
+ pollHotplug(true);
110
+ }
84
111
  };
85
112
 
86
- const hotplugModeIsIdsOnly = hotplugSupported === 2;
87
- if (hotplugModeIsIdsOnly) {
88
- // The hotplug backend doesnt emit 'attach' or 'detach', so we need to do some conversion
89
- const hotplugEventConversion = () => {
90
- // Future: This might want a debounce, to avoid doing multiple polls when attaching a usb hub or something
91
- pollHotplugOnce(false);
92
- };
113
+ const stopHotplug = () => {
114
+ if (hotplugSupported) {
115
+ // Disable hotplug events
116
+ usb._disableHotplugEvents();
93
117
 
94
- usb.on('attachIds', hotplugEventConversion);
95
- usb.on('detachIds', hotplugEventConversion);
96
- }
118
+ if (hotplugSupported === 2) {
119
+ // Remove hotplug ID event listeners
120
+ usb.off('attachIds', emitHotplugEvents);
121
+ usb.off('detachIds', emitHotplugEvents);
122
+ }
123
+ } else {
124
+ // Stop polling
125
+ pollingHotplug = false;
126
+ }
127
+ };
97
128
 
98
129
  usb.on('newListener', event => {
99
130
  if (event !== 'attach' && event !== 'detach') {
@@ -101,11 +132,7 @@ usb.on('newListener', event => {
101
132
  }
102
133
  const listenerCount = usb.listenerCount('attach') + usb.listenerCount('detach');
103
134
  if (listenerCount === 0) {
104
- if (hotplugSupported) {
105
- usb._enableHotplugEvents();
106
- } else {
107
- pollHotplugLoop(true);
108
- }
135
+ startHotplug();
109
136
  }
110
137
  });
111
138
 
@@ -115,11 +142,7 @@ usb.on('removeListener', event => {
115
142
  }
116
143
  const listenerCount = usb.listenerCount('attach') + usb.listenerCount('detach');
117
144
  if (listenerCount === 0) {
118
- if (hotplugSupported) {
119
- usb._disableHotplugEvents();
120
- } else {
121
- pollingHotplug = false;
122
- }
145
+ stopHotplug();
123
146
  }
124
147
  });
125
148