tonic icon indicating copy to clipboard operation
tonic copied to clipboard

Enable transport over WebSocket (with support of wasm)

Open boxdot opened this issue 5 years ago • 17 comments
trafficstars

I have an experimental implementation of a Connector which allows to tunnel gRPC communication over a WebSocket. This makes it possible to implement a gRPC-over-WebSocket server and more importantly also a client. With small patches of h2 and tower-buffer the client also runs in wasm32.

  • Implementation incl. examples: https://github.com/boxdot/tonic-ws-transport
  • Patch of tonic: https://github.com/boxdot/tonic/commit/b06a97dc563eb41f3ff7f4399befd7d872dae090
  • Patch of h2: https://github.com/boxdot/h2/commit/03838652b2b2a40c46df44a8299ebc1a9236939c
  • Path of tower-buffer: https://github.com/boxdot/tower/commit/1091340a3eb106da844348bc1b1ef7ce7b4a763d

If you find this useful and my approach as suitable, I would like to discuss how to move forward from here.

Feature Request

Crates

  • tonic (transport module)
  • h2
  • tower-buffer

Motivation

Run gRPC in browser.

Proposal

(High level)

  • Expose the client parts that are independent of TCP and work in wasm as a separate feature.
  • Use this new feature and the new tonic-ws-transport crate to enable implementations of wasm clients.

I am not sure if this should become a separate feature of tonic crate though, or we could do it differently. Due to this bug in cargo (https://github.com/rust-lang/cargo/issues/2524), we might run into problems if we choose conditional compilation based on wasm32 target arch.

Notes:

  • Implementation and patches are based on tokio 0.2 branch.
  • https://github.com/rust-lang/cargo/issues/2524
  • Examples are not part of the experimental crate due to another cargo bug: https://github.com/rust-lang/cargo/issues/1796

boxdot avatar Nov 12 '20 09:11 boxdot

Sorry for the delayed response on this!

Is there a spec for gRPC over WS? Beyond gRPC web?

LucioFranco avatar Nov 27 '20 15:11 LucioFranco

Sorry for the delayed response on this!

Is there a spec for gRPC over WS? Beyond gRPC web?

I don't think so. The idea was just to use websocket as a tunnel for the TCP transport in environments where TCP is not available but websocket is (e.g. browsers). Since gRPC runs on top of HTTP2, and HTTP2 on top of TCP, and my crate allows TCP to run on top of a websocket, it is completely transparent to gRPC.

Actually, I am now also using the tonic-ws-transport crate for an implementation of a websocket->Http2 reverse proxy. Just used the WsConnector in hyper::Server. So, I guess a better name for the crate would be just websocket-tcp-transport.

boxdot avatar Nov 27 '20 15:11 boxdot

Yeah, lets put this on hold to get into tonic, but I want to circle back once I write the new transport and maybe we can get things to fit in so its easy to write this as an external crate.

LucioFranco avatar Nov 27 '20 19:11 LucioFranco

Sure. Would it be possible to expose the parts of transport that are wasm32 compatible under a feature flag? At least this would allow to use the client in wasm. See https://github.com/boxdot/tonic/commit/b06a97dc563eb41f3ff7f4399befd7d872dae090.

boxdot avatar Nov 27 '20 19:11 boxdot

Potentially, I plan to basically extract all the transport stuff so the tonic crate is just a grpc impl. That should make it much easier to get WASM things working with it.

LucioFranco avatar Nov 27 '20 20:11 LucioFranco

Is there any open branch that's solving this?

leobragaz avatar Mar 09 '21 13:03 leobragaz

@bragaz don't think so 😕

davidpdrsn avatar Mar 09 '21 14:03 davidpdrsn

I did some work to rebase the branches on top of tokio 1.0 and the latest release of tonic. There is no need for tower's buffer patch anymore, since it is possible to spawn the buffer on any executor (in particular, also on wasm_bindgen_futures) by using this api: https://docs.rs/tower/0.4.6/tower/buffer/struct.Buffer.html#method.pair.

  • Working branch: https://github.com/boxdot/tonic-ws-transport/tree/tokio-1.0
  • Tonic patch: https://github.com/boxdot/tonic/commit/38817a9
  • h2 patch: https://github.com/boxdot/h2/commit/f6ae28c3

The above implementation is used in the browser with a backend gateway passing websocket streams to a grpc backend for a while already without any problems so far.

I also tried to upstream h2, but there is not much progress there: https://github.com/hyperium/h2/issues/511

boxdot avatar Mar 09 '21 21:03 boxdot

@boxdot this seems reasonable maybe we can try getting into h2 first I see you have an issue but maybe we can talk with @seanmonstar again about it?

LucioFranco avatar Apr 14 '21 19:04 LucioFranco

@LucioFranco Yes, it makes sense to start with h2, since it is a tiny patch. We just need to figure out how to make it least intrusive. I will pick up the issue there again. Thanks.

boxdot avatar Apr 14 '21 21:04 boxdot

Changes for this have been upstreamed to hyper and h2. How should the discussion proceed to make this a reality in tonic?

kalcutter avatar Jun 08 '21 10:06 kalcutter

Changes for this have been upstreamed to hyper and h2. How should the discussion proceed to make this a reality in tonic?

I will upgrade my repository and integrate the latest tonic changes. Then we will hopefully see which minimal changes are needed to tonic.

boxdot avatar Jun 10 '21 17:06 boxdot

Do you have a link to those upstream changes?

LucioFranco avatar Jun 11 '21 17:06 LucioFranco

h2 got an option to configure the max concurrent reset streams. The non-wasm compatible Instant::now is now only used when it is configured to be > 0. More details here: https://github.com/hyperium/h2/issues/511

The same configuration was exposed in hyper: https://github.com/hyperium/hyper/pull/2535

About my patch of tonic: I introduced a feature flag, which disabled all non-client and os-specific code in transport s.t. it compiles and runs on wasm32-unknown-unknown. This was done before the above patches were merged on version 0.3 of tonic.

boxdot avatar Jun 11 '21 17:06 boxdot

I ported my patch to the latest master of tonic: https://github.com/boxdot/tonic/commit/1da79d033b50ab08495ccbdfe287278a6192921e. It adds a feature flag to tonic which disables all wasm non-compatible parts of transports and enables compilation of generated tonic clients to wasm32. It also avoids using any browser incompatible runtime features.

@LucioFranco If you think that this approach is suitable, I can open a PR.

With this patch it is possible to tunnel any tonic client through a websocket in a browser. Cf. https://github.com/boxdot/tonic-ws-transport/tree/1400e63d578044d1399fb63fa591c52c0502b6d0/examples

boxdot avatar Jun 16 '21 20:06 boxdot

@boxdot Yeah, can you open a PR? I'd like to give this a review (I quickly looked over the code you posted).

LucioFranco avatar Jun 21 '21 15:06 LucioFranco

Since Google updated their plan to only support grpc over WebTransport this issue should maybe closed/reworked?

It would be good for tonic to support WebTransport as an optional transport layer for the server at least. A client implementation could be useful as well tho.

domlen2003 avatar Feb 24 '24 14:02 domlen2003