webusb icon indicating copy to clipboard operation
webusb copied to clipboard

Define WebUSB in Shared Workers

Open reillyeon opened this issue 9 years ago • 10 comments

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.

reillyeon avatar Jan 08 '17 10:01 reillyeon

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.

karelbilek avatar Jan 13 '17 13:01 karelbilek

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!

odejesush avatar May 31 '18 00:05 odejesush

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:

  • we have a small daemon that user has to install, or
  • a small helper chrome app (that will soon be gone due to Google cutting Chrome apps), or
  • WebUSB, for the new models (and soon-ish the old models with new FW).

Our webapp has a following "flow":

  • user opens a website
  • user plugs in the device
  • website automatically starts communicating with the device, asking about its name, asking for the public keys, and starts working with them in some way, sometimes asking about more keys. The web app can detect connections and disconnections and react to them.

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

  • We want the action in the web app to be immediate - immediately after connecting the device, show the user some info
  • We also want the web app to work in multiple tabs in browser

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,

karelbilek avatar Jun 07 '18 01:06 karelbilek

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)

inexorabletash avatar Jun 07 '18 11:06 inexorabletash

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.

karelbilek avatar Jun 07 '18 13:06 karelbilek

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.

odejesush avatar Jun 07 '18 15:06 odejesush

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)

karelbilek avatar Jun 07 '18 20:06 karelbilek

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.

odejesush avatar Jun 07 '18 20:06 odejesush

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:

  • Once a programming session is established with the non-USB device I have to periodically send a message to maintain the programming session
  • Flashing of firmware should not get interrupted from start to finish

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?

gregjhogan avatar Dec 23 '18 22:12 gregjhogan

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.

odejesush avatar Jan 08 '19 21:01 odejesush