DEV Community

loading...

Phoenix umbrella proxy application.

Alexandr K
Working hard, sleeping well
・2 min read

Hey everyone!

It's really long time to take me to start writing again. I was really busy trying to make the games as part of my free time company balconygames :) Good progress but it's not so good enough for the market because of the user acquisition is so expensive.

Today I've decided to share the example of the proxy application for umbrella Phoenix, probably it would be useful for someone who has the same issues like code reloading, websocket support. It has 4 apps inside of apps/, proxy, web(phoenix), admin(phoenix), db(shared ecto project). No more words, going to share::

defmodule YourApp.Proxy.Application do
  @moduledoc false
  use Application

  alias Phoenix.LiveReloader.Socket, as: LiveReloadSocket

  require Logger

  def start(_type, _args) do
    import Supervisor.Spec, warn: false

    require_code_reloading?(:your_app_web, YourAppWeb.Endpoint)

    opts = [strategy: :one_for_one, name: YourApp.Proxy.Supervisor]
    Supervisor.start_link(children(Mix.env()), opts)
  end

  def children(:test), do: []

  def children(_) do
    proxy_children = [
      {
        Plug.Cowboy,
        scheme: :http,
        plug: YourApp.Proxy.Builder,
        port: port(),
        dispatch: [
          {:_,
           [
             # your_app_web
             web_phoenix_live_reload(),
             web_phoenix_live_view(),
             web_websocket(),
             # your_app_admin
             admin_phoenix_live_reload(),
             admin_phoenix_live_view(),
             admin_websocket(),
             # proxy
             master_proxy()
           ]}
        ]
      }
    ]

    # - proxy endpoints
    #    - /api endpoints
    #    - /dev/admin pages
    # - web watchers for webpacker and code reloading
    # - admin watchers for webpacker and code reloading
    children =
      proxy_children ++
        watcher_children(
          :your_app_web,
          YourAppWeb.Endpoint
        ) ++
        watcher_children(
          :your_app_admin_web,
          YourAppAdminWeb.Endpoint
        )

    children
  end

  defp watcher_children(otp_app, mod) do
    conf = Application.get_env(otp_app, mod)

    unless Mix.env() == :test do
      Enum.map(conf[:watchers], fn {cmd, args} ->
        {Phoenix.Endpoint.Watcher, watcher_args(cmd, args)}
      end)
    else
      []
    end
  end

  defp watcher_args(cmd, cmd_args) do
    {args, opts} = Enum.split_while(cmd_args, &is_binary(&1))
    {cmd, args, opts}
  end

  def port do
    (System.get_env("PORT") || "4000") |> String.to_integer()
  end

  def web_phoenix_live_reload do
    websocket_handler(
      "/phoenix/live_reload/socket/websocket",
      YourAppWeb.Endpoint,
      {LiveReloadSocket, :websocket}
    )
  end

  def web_phoenix_live_view do
    websocket_handler(
      "/live",
      YourAppWeb.Endpoint,
      {Phoenix.LiveView.Socket, :websocket}
    )
  end

  def web_websocket do
    websocket_handler(
      "/cable/websocket",
      YourAppWeb.Endpoint,
      {YourAppWeb.UserSocket, websocket: true}
    )
  end

  def admin_phoenix_live_reload do
    websocket_handler(
      "/dev/admin/phoenix/live_reload/socket/websocket",
      YourAppAdminWeb.Endpoint,
      {LiveReloadSocket, :websocket}
    )
  end

  def admin_phoenix_live_view do
    websocket_handler(
      "/dev/admin/live",
      YourAppAdminWeb.Endpoint,
      {Phoenix.LiveView.Socket, :websocket}
    )
  end

  def admin_websocket do
    websocket_handler(
      "/dev/admin/websocket",
      YourAppAdminWeb.Endpoint,
      {YourAppAdminWeb.UserSocket, websocket: true}
    )
  end

  def master_proxy do
    {:_, Plug.Cowboy.Handler, {YourApp.Proxy.Plug, []}}
  end

  defp websocket_handler(path, endpoint, options) do
    {path, Phoenix.Endpoint.Cowboy2Handler, {endpoint, options}}
  end

  defp require_code_reloading?(otp_app, mod) do
    conf = Application.get_env(otp_app, mod)

    if conf[:code_reloader] do
      Phoenix.CodeReloader.Server.check_symlinks()
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

That's it

Discussion (0)