hyperium / tonic

A native gRPC client & server implementation with async/await support.
https://docs.rs/tonic
MIT License
9.65k stars 982 forks source link

Enable transport over WebSocket (with support of wasm) #491

Open boxdot opened 3 years ago

boxdot commented 3 years ago

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.

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

Feature Request

Crates

Motivation

Run gRPC in browser.

Proposal

(High level)

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:

LucioFranco commented 3 years ago

Sorry for the delayed response on this!

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

boxdot commented 3 years ago

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.

LucioFranco commented 3 years ago

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.

boxdot commented 3 years ago

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.

LucioFranco commented 3 years ago

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.

leobragaz commented 3 years ago

Is there any open branch that's solving this?

davidpdrsn commented 3 years ago

@bragaz don't think so 😕

boxdot commented 3 years ago

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.

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

LucioFranco commented 3 years ago

@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?

boxdot commented 3 years ago

@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.

kalcutter commented 3 years ago

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

boxdot commented 3 years ago

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.

LucioFranco commented 3 years ago

Do you have a link to those upstream changes?

boxdot commented 3 years ago

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 commented 3 years ago

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

LucioFranco commented 3 years ago

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

domlen2003 commented 6 months ago

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.