icerpc / icerpc-csharp

A C# RPC framework built for QUIC, with bidirectional streaming, first-class async/await, and Protobuf support.
https://docs.icerpc.dev
Apache License 2.0
108 stars 13 forks source link

Reimplement WSConnection using System.Net.WebSockets #389

Closed bernardnormier closed 3 years ago

bernardnormier commented 3 years ago

We should reimplement WSConnection using System.Net.WebSockets, the sooner the better.

I expect the switch to System.Net.WebSockets to have a number of ripple effects on the Transports classes:

bernardnormier commented 3 years ago

It would be good to put this WebSocket support in a separate assembly, IceRpc.WebSockets.dll.

It makes sense because it brings-in extra dependencies: https://docs.microsoft.com/en-us/dotnet/api/system.net.websockets.websocket?view=net-5.0

It is also a good way to demonstrate our Transports API allows users to implement a socket-based transport outside the IceRpc assembly.

bentoi commented 3 years ago

Removing WSConnection sounds good. I'm not convinced we should re-implement WebSocket as a transport though. The .NET HttpListener API is deprecated in favor of Kestrel. To me, it would be simpler to just implement a Kestrel middleware that forwards the raw Ice2/Slic data to an IceRPC server.

We also need to consider the client side: which protocol an IceRPC client running in the browser should use? There are several options:

  1. Ice2 -> Slic -> WebSocket
  2. Ice2 -> Slic -> over an Http/2 or Http/3 stream (feasibility needs to be investigated however... it's not clear if it's a good idea to keep a long lived Http stream)
  3. Http/2 or Http/3

The first two options allow to implement callbacks. With the third option, it's more difficult to implement callbacks (but perhaps possible using a dedicated stream used for pulling callbacks...).

There's also the question of whether or not WebSocket will still be supported in the future... discussions about whether or not it would die started when Http/2 was introduced. The only reason why it's still useful today is that it allows the server to push data to the client (which is why it's easy to support callbacks).

pepone commented 3 years ago

To me, it would be simpler to just implement a Kestrel middleware that forwards the raw Ice2/Slic data to an IceRPC server.

I think that is a good idea

We also need to consider the client side:

At this point I think the best option is WebSocket, the future replacement is WebTransport but it is still in Draft

bernardnormier commented 3 years ago

To me, it would be simpler to just implement a Kestrel middleware that forwards the raw Ice2/Slic data to an IceRPC server.

Can you describe your idea in more details? Naturally it would be nice to support Ice 3.7 JavaScript clients running in a browser.

For the server-side ws support in C#, we would use ASP.NET + Kestrel + our own middleware that handles ws requests for sub-protocols ice.zeroc.com (=ice1) and ice2 (=ice2) by forwarding the requests to an IceRPC server with a coloc endpoint?

Sounds a bit odd. We could probably just use a Dispacher - no need for a Server.

What about C# ws client? How do you see that?

bentoi commented 3 years ago

Can you describe your idea in more details? Naturally it would be nice to support Ice 3.7 JavaScript clients running in a browser.

We provide a Kestrel middleware implementation that process a web socket connect request. It forwards the bi-directional raw bytes read/written from/to the System.Net.WebSocket object to a TCP connection established to an IceRPC server. The IceRPC server endpoint that the middleware connects to is a configuration of the middleware. The middleware doesn't interpret the data that is forwarded from the WebSocket (the data is the Slic protocol).

If we really want to allow collocating the IceRPC server with Kestrel, we could support creating an IceRPC/Slic connection from a WebSocket object directly (or possibly support creating an IceRPC/Slic connection with a System.IO.Stream and wrap the WebSocket object with a System.IO.Stream).

What about C# ws client? How do you see that?

We don't support it. I don't see a use case for WS client support with C# or any languages other than languages supported by web browsers (JavaScript/TypeScript).

pepone commented 3 years ago

Maybe we can provide this functionality with the upcoming proxy server, the proxy can forward the data received over WS and later over WebTransport, I agree that client-side should be limited to browser applications.

bentoi commented 3 years ago

We could also just implement an ASP.NET HTTP proxy server that just provides WebSocket termination using the middleware I proposed above... it would be quite easy to implement.

bernardnormier commented 3 years ago

So for now we just remove ws from IceRpc?

bentoi commented 3 years ago

Sounds reasonable to me.

bernardnormier commented 3 years ago

We could also just implement an ASP.NET HTTP proxy server that just provides WebSocket termination using the middleware I proposed above... it would be quite easy to implement.

What about just using websockify? Or would your ASP.NET Kestrel middleware would do more than websockify?

It would be nice to check that Ice 3.7 works with icejs:ws[s] client -> websockify -> ice:tcp server

bentoi commented 3 years ago

Websockify would work as well but it's yet an additional proxy component that might consume CPU. The advantage of the Kestrel middleware implementation is that it's integrated and it will likely better perform than a separate component, it also doesn't require specific deployment. That said, it's less useful if you don't use ASP.NET.