Skip to content
This repository has been archived by the owner on Mar 7, 2023. It is now read-only.

Rewrite based around napi and context aware #127

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,6 @@
npm install usb-detection
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a scenario where we can merge node-usb-detection into node-usb (or at least the windows implementation) to cover the deficiencies in libusb and align efforts? I'd love to see the JavaScript polling removed and native events used instead.

-- @thegecko, #127 (comment)

The reason I started using this project 6 years ago was because it was the only project that actually worked on Windows (and the other OS's). Although not my use case, it also seems like a lot of people use this with Electron so it would be good to have a compatible option there too.

The second criteria is documentation which looks to be available on https://github.com/node-usb/node-usb#usbdetection

A third criteria is it actually being able to be built and installed easily. This means prebuilds or ideally no C++ code necessary if that was even possible.

If those can be addressed(which some already are), then I could see this being deprecated in favor of usb.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thegecko (repost that in this thread)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MadLittleMods I believe with the v2.x.x release of node-usb, all of your criteria are now met

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thegecko Tested and seems to work. I think we can move forward with deprecating as I'm running into a wall trying to get prebuilds to work anyway (#165 (comment)).

const { usb, getDeviceList} = require('usb');

const devices = getDeviceList();
console.log('devices', devices);

usb.on('attach', function(device) { console.log('attach', device) });

usb.on('detach', function(device) { console.log('detach', device) });

To note some differences and preemptively answer some peoples questions, how do we get deviceName, manufacturer, serialNumber when using the usb package? Maybe I'm just not understanding how to get a USBDevice which seems to have those properties as described in the readme and somehow mixing the legacy API.

usb-detection

{
    locationId: 336592896,
    vendorId: 6353,
    productId: 20193,
    deviceName: 'Pixel 4a',
    manufacturer: 'Google',
    serialNumber: 'xxx',
    deviceAddress: 7
  }

usb

{
  busNumber: 20,
  deviceAddress: 5,
  deviceDescriptor: {
    bLength: 18,
    bDescriptorType: 1,
    bcdUSB: 512,
    bDeviceClass: 0,
    bDeviceSubClass: 0,
    bDeviceProtocol: 0,
    bMaxPacketSize0: 64,
    idVendor: 6353,
    idProduct: 20193,
    bcdDevice: 1088,
    iManufacturer: 1,
    iProduct: 2,
    iSerialNumber: 3,
    bNumConfigurations: 1
  },
  portNumbers: [ 1 ]
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The legacy API returns the raw USB data which doesn't undertake further blocking calls to obtain the strings (e.g. serial number, device name, etc.).

You can get these in a manner of ways:

import { WebUSB } from 'usb';

(async () => {
    const customWebUSB = new WebUSB({
        // Bypass checking for authorised devices
        allowAllDevices: true
    });

    customWebUSB.addEventListener('connect', event => console.log(event.device);
})();

```

## Install for Electron

This module uses native extensions and needs to be compiled for your target version of Electron. Precompiled binaries for recent Node.js and Electron versions are built and published using [prebuild][] and can be installed automatically using [electron-rebuild][].

See the [Electron docs for using native modules][electron-native-modules] to ensure your project is set up to correctly use the prebuilt binaries for your version of Electron.

[prebuild]: https://github.com/prebuild/prebuild
[electron-rebuild]: https://github.com/electron/electron-rebuild
[electron-native-modules]: https://www.electronjs.org/docs/tutorial/using-native-node-modules

---

If you run into the following error, here are the exact steps you can use:

```
detection.node was compiled against a different Node.js version using NODE_MODULE_VERSION 72. This version of Node.js requires NODE_MODULE_VERSION 80. Please try re-compiling or re-installing
```

1. `npm i electron-rebuild --save-dev`
1. `./node_modules/.bin/electron-rebuild`


# Usage

```js
Expand Down
19 changes: 18 additions & 1 deletion binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,30 @@
"targets": [
{
"target_name": "detection",
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"xcode_settings": { "GCC_ENABLE_CPP_EXCEPTIONS": "YES",
# "CLANG_CXX_LIBRARY": "libc++",
"MACOSX_DEPLOYMENT_TARGET": "10.7",
"OTHER_CFLAGS": [
"-arch x86_64",
"-arch arm64"
],
"OTHER_LDFLAGS": [
"-arch x86_64",
"-arch arm64"
]
},
"msvs_settings": {
"VCCLCompilerTool": { "ExceptionHandling": 1 },
},
"sources": [
"src/detection.cpp",
"src/detection.h",
"src/deviceList.cpp"
],
"include_dirs" : [
"<!(node -e \"require('nan')\")"
"<!@(node -p \"require('node-addon-api').include\")"
],
'conditions': [
['OS=="win"',
Expand Down
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function find(vid: number): Promise<Device[]>;
export function find(callback: (error: any, devices: Device[]) => any): void;
export function find(): Promise<Device[]>;

export function isMonitoring(): boolean;
export function startMonitoring(): void;
export function stopMonitoring(): void;
export function on(event: string, callback: (device: Device) => void): void;
Expand Down
75 changes: 37 additions & 38 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//var SegfaultHandler = require('segfault-handler');
//SegfaultHandler.registerHandler();
// var SegfaultHandler = require('segfault-handler');
// SegfaultHandler.registerHandler();

var index = require('./package.json');

Expand All @@ -10,9 +10,11 @@ function isFunction(functionToCheck) {
if(global[index.name] && global[index.name].version === index.version) {
module.exports = global[index.name];
} else {
var detection = require('bindings')('detection.node');
var binding = require('bindings')('detection.node');
var EventEmitter2 = require('eventemitter2').EventEmitter2;

var detection = new binding.Detection();

var detector = new EventEmitter2({
wildcard: true,
delimiter: ':',
Expand All @@ -34,34 +36,25 @@ if(global[index.name] && global[index.name].version === index.version) {
// Assemble the optional args into something we can use with `apply`
var args = [];
if(vid) {
args = args.concat(vid);
args.push(vid);
}
if(pid) {
args = args.concat(pid);
args.push(pid);
}

// Tack on our own callback that takes care of things
args = args.concat(function(err, devices) {

// We call the callback if they passed one
if(callback) {
callback.call(callback, err, devices);
}

// But also do the promise stuff
if(err) {
reject(err);
return;
}
resolve(devices);
});

// Fire off the `find` function that actually does all of the work
detection.find.apply(detection, args);
const devices = detection.findDevices.apply(detection, args);

// We call the callback if they passed one
if(callback) {
callback.call(callback, undefined, devices);
}

resolve(devices)
});
};

detection.registerAdded(function(device) {
function fireAdded(device) {
detector.emit('add:' + device.vendorId + ':' + device.productId, device);
detector.emit('insert:' + device.vendorId + ':' + device.productId, device);
detector.emit('add:' + device.vendorId, device);
Expand All @@ -72,35 +65,41 @@ if(global[index.name] && global[index.name].version === index.version) {
detector.emit('change:' + device.vendorId + ':' + device.productId, device);
detector.emit('change:' + device.vendorId, device);
detector.emit('change', device);
});
}

detection.registerRemoved(function(device) {
function fireRemoved(device) {
detector.emit('remove:' + device.vendorId + ':' + device.productId, device);
detector.emit('remove:' + device.vendorId, device);
detector.emit('remove', device);

detector.emit('change:' + device.vendorId + ':' + device.productId, device);
detector.emit('change:' + device.vendorId, device);
detector.emit('change', device);
});
}

function fireEvent(type, device) {
switch (type) {
case 'add':
fireAdded(device);
break;
case 'remove':
fireRemoved(device);
break;
default:
// Ignore
break;
}
}

var started = false;
detector.isMonitoring = function() {
return detection.isMonitoring();
};

detector.startMonitoring = function() {
if(started) {
return;
}

started = true;
detection.startMonitoring();
detection.startMonitoring(fireEvent);
};

detector.stopMonitoring = function() {
if(!started) {
return;
}

started = false;
detection.stopMonitoring();
};

Expand Down
Loading