firefly icon indicating copy to clipboard operation
firefly copied to clipboard

Distribution from browser to host

Open KronicDeth opened this issue 6 years ago • 4 comments

To be able to support the community debugging tools, specifically Observer, we'll need to be able to expose the Lumen runtime running in a browser tab to the host. Because the host wants to connect to nodes it can find by first talking to EPMD, we will need a proxy that shows up as another node on the host, but then gets forwarded to the browser.

  • [ ] Make the distribution transport pluggable in lumen_runtime. This may be the same interface as net_kernel or something specific to Lumen using Rust fn similar to the time source.
    • [ ] Use @mobileoverlord's phoenix_client to connect to the HOST
      • [ ] Use wrapper around Lumen.Web.WebSocket to connect to HOST in place of websocket_client that phoenix_client uses by default.
  • [ ] A Lumen.BeamSplitter Elixir project that runs on the HOST
    • [ ] A dedicated socket, similar to how phoenix_live_reload is on a separate socket prefix from the app's default one
    • [ ] Bind a port on the host that can act as a secondary node on the host (PROXY_PORT)
    • [ ] Negotiate with EPMD so it thinks PROXY_PORT is another node.
    • [ ] Pass messages received on PROXY_PORT to the Phoenix Channel

With this setup it should be possible for :observer.start() launched from iex -S mix phx.server on HOST to then connect to the localhost:PROXY_PORT and talk to the Lumen runtime in the browser tab.

Alternatives

net_kernel on HOST

Overriding net_kernel on HOST so that it natively understand websockets, similar to how other developers have overridden net_kernel on Heroku and other restricted environments.

Raw WebSockets

Instead of going over Phoenix Channels, we could use a raw websocket. This makes it easier to talk to things that aren't Phoenix, but makes it hard to integrate with Phoenix as we couldn't use the Endpoint socket DSL.

KronicDeth avatar Oct 17 '19 01:10 KronicDeth

I’m a bit confused by the hang up on EPMD, with BEAM it is possible to provide your own EPMD backend, this is often used to remove the dependency on EPMD from environments where it is not supported. This combined with a custom distribution transport should allow avoiding EPMD entirely. See epmdless as an example.

bitwalker avatar Oct 17 '19 01:10 bitwalker

I get you can go without EPMD, but I want to support still having EPMD so that potentially this could run in a normal host project, similar to how Phoenix Live Reload does for Phoenix project and not need to enforce going EPMDless on the entire project.

KronicDeth avatar Oct 17 '19 03:10 KronicDeth

I'd like to understand the benefit of supporting EPMD here, at least initially. I'm not super convinced that there is anything to be gained.

We definitely can't support remote shells in non-local/non-dev settings (for the browser target), since it would absolutely overwhelm distribution, so the general case of wanting the app to use EPMD in production isn't relevant. So we're really talking specifically about getting a remote shell node to connect via a single host node, to a single client-side node. In that setting we don't have a need for EPMD, and removing it as a requirement involves less moving parts, as far as I can tell.

To give you the idea of how I see it working:

  • Start the app, this is configured to use the custom WebSocket distribution transport and a EPMD backend that is aware of the client-side node; as the client-side Lumen node is connected via WebSockets to the app. The client-side node uses a special node name that is always the same (e.g. [email protected]). The EPMD backend hosts a WebSocket server which relays messages to the client-side node.
  • Start local debug node with [email protected] EPMD_MODE=client iex -S mix --erl="-proto_dist websocket_dist -epmd_module custom_epmd" --hidden --cookie foo --name [email protected] --remsh [email protected]

The debug node is running the same EPMD backend, but configured to run as a client rather than server. It connects to the [email protected] name by connecting to the node in $EPMD_APP_NODE as a WebSocket proxy.

NOTE: The invocation of iex above wouldn't actually need all of those flags since it would already be provided as part of app configuration, it is more to illustrate what's needed.

To be clear, I'm not saying your solution isn't viable, or unacceptable, I think it is both; I'm just hoping that there is a simpler solution possible. If what I'm suggesting above isn't simpler, or if there are other reasons it isn't viable or less than ideal, that's fine, I don't see any reason why your proposal isn't viable.

bitwalker avatar Oct 17 '19 03:10 bitwalker

Note to reassess if the WASM debug support is good enough to replace this effort

bcardarella avatar Dec 09 '20 15:12 bcardarella