WICG / webusb

Connecting hardware to the web.
https://wicg.github.io/webusb/
Other
1.31k stars 130 forks source link

Define WebUSB in Shared Workers #73

Open reillyeon opened 7 years ago

reillyeon commented 7 years ago

Driving a USB device from a worker allows processing to be moved off of the main event loop. Moving device access to a Shared Worker also allows multiple tabs of the same application to coordinate access to a single device as unique ownership of an interface is enforced by both the WebUSB API and underlying operating systems.

Unlike defining WebUSB in Service Workers there are likely no additional security and privacy considerations here.

karelbilek commented 7 years ago

I was trying to make some inter-tab sharing of information about connecting/disconnecting with BroadcastChannel and it's really hard to do it correctly.

webusb in shared worker would be great.

odejesush commented 6 years ago

Hi @karel-3d, could you elaborate on what kind of application you were trying to build that required this sharing of information from the USB device? There is currently on going discussion on whether WebUSB should be implemented on shared workers, since shared workers could be deprecated. If you like, you could follow the discussion on the blink-dev Google group (https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/MReOVYgRpKk). Learning about the use cases for this feature could help in figuring out how to approach this problem. Thank you!

karelbilek commented 6 years ago

I will reply here and post link to the group.

We are makers of this cryptographic device - https://trezor.io/ - which is used mostly for safely storing cryptocurrencies.

Explained simply - the device keeps private keys, can give the PC public keys on request and can sign messages on request, which the user has to confirm on the device. Private keys don't leave the device.

On the PC side, we have a web app (web wallet) that connects directly to Trezor, from the browser, via a variety of transports:

Our webapp has a following "flow":

We also want two things that seem to go against each other:

We have a concept of "session" and somehow cooperative multitasking - since the actions are usually rather short, we tell to the transport layer (the desktop daemon or the chrome app) "I am working with the device now - ok now it's free" and the web app works with that, so more tabs can work with a device that is otherwise exclusive.

We are doing that with webusb, too, with sharedworker. Once user selects a device in the Chrome GUI box, the permission is remembered and next time does not require the box, in all tabs on the domain. We use SharedWorked for cooperation between tabs for the "multitasking".

In the end we did not need to use webusb in the sharedworked directly, but we send messages to the worker and the worker "orchestrates" who can and cannot read to/from the device, even when in the end the web pages read the device directly. I originally wanted the access to happen only in the sharedworker and the messages would be the data read from the device, but we worked around that.

For example. We send messages like "acquire intent" from page to the worker, then after worker "allows" that, we send message "acquire done" or "acquire failed" - acquire meaning both open + claim interface. After that, only the one tab can communicate, until the tab sends "release" back to the worker, etc.

You can look at the code here

https://github.com/trezor/trezor-link/blob/master/src/lowlevel/withSharedConnections.js#L48

https://github.com/trezor/trezor-link/blob/master/src/lowlevel/sharedConnectionWorker.js https://github.com/trezor/trezor-link/blob/master/src/lowlevel/webusb.js

If shared worker will indeed be deprecated (which is news to me :(( ), we can work around that with perhaps localStorage APIs somehow, but that feels a little hacky,

inexorabletash commented 6 years ago

Thanks, @karel-3d !

It sounds like you could use my proposed Web Locks API (https://github.com/inexorabletash/web-locks) to achieve this coordination. Can you take a look at that proposal and see if it would satisfy your use cases for coordinating? The Locks API is implemented in Chrome and available as an Origin Trial (read more about the trial and sign up here)

karelbilek commented 6 years ago

Hello.

That looks interesting, first time I see that.

What I like about shared worker is that it also stores information. WebLocks API seems interesting, but it cannot share information directly, only with some additional mechanisms.

I guess we could use weblocks + localstorage for the same use as we currently use shared worker.

odejesush commented 6 years ago

Yes, thank you @karel-3d !

I would also like to add that I have a section in my design document for WebUSB on Workers with an example of how WebUSB, Web Locks, Dedicated Workers, and BroadcastChannel could potentially be used together to achieve similar functionality to WebUSB on Shared Workers.

karelbilek commented 6 years ago

Thanks. Yes that could be used; however, the sharedworker is currently written and tested and I don't want to touch that for a while :)

(we are still solving windows issues with webusb and drivers; the WDI thread here helped a lot but there are still little issues, mostly with Window 7. But that is beyond the scope of this thread)

odejesush commented 6 years ago

No need to worry about modifying anything yet; we're still figuring out how to best facilitate the use of USB devices across pages. Thank you for providing us with your specific use case because it gives us a developer's perspective on the issue that we can use a reference in figuring this out.

gregjhogan commented 5 years ago

I am trying to write an application that flashes firmware on a non-usb device via an off-the-shelf USB device

Here is what the setup looks like:

Web Browser (sends firmware) <---> USB device (translates to a serial protocol) <---> non-USB device (receives firmware)

I have two problems:

I started out using a dedicated web worker, and while this works if I keep the tab focused during the entire process, switching tabs in the middle of the process seems to suspend the dedicated web worker and causes the above two problems.

I believe that if shared workers had been implemented I would have an easy solution to my problems. I tried enabling chrome experimental flags and using a shared worker and it didn't work because navigator.usb === null.

Am I missing some other clean way to handle this? Is there some other feature (other than shared workers) that I should be looking at?

odejesush commented 5 years ago

Hi gregjhogan,

Unfortunately, WebUSB on shared workers in Chrome is not going to be implemented anytime soon because the future of shared workers is uncertain. See https://github.com/whatwg/html/issues/315 for some context.

There is an intent to implement and ship the throttling of background dedicated workers, which will throttle dedicated workers by default. However, there is a proposal to allow users to opt-out of the throttling (see the design doc). This could potentially solve your problem with the process becoming suspended when switching tabs.

Please file a bug at https://crbug.com with the Blink>USB component so that we can track the issue.