summaryrefslogblamecommitdiff
path: root/lib/lsg_web/controllers/irc_auth_sse_controller.ex
blob: f370d97b5709690cadcef309266cc043860872c2 (plain) (tree)



























                                                            
                                                                    




































                                                                       
defmodule LSGWeb.IrcAuthSseController do
  use LSGWeb, :controller
  require Logger

  @ping_interval 20_000
  @expire_delay :timer.minutes(3)

  def sse(conn, params) do
    perks = if uri = Map.get(params, "redirect_to") do
      {:redirect, uri}
    else
      nil
    end
    token = String.downcase(EntropyString.random_string(65))
    conn
    |> assign(:token, token)
    |> assign(:perks, perks)
    |> put_resp_header("X-Accel-Buffering", "no")
    |> put_resp_header("content-type", "text/event-stream")
    |> send_chunked(200)
    |> subscribe()
    |> send_sse_message("token", token)
    |> sse_loop
  end

  def subscribe(conn) do
    :timer.send_interval(@ping_interval, {:event, :ping})
    :timer.send_after(@expire_delay, {:event, :expire})
    {:ok, _} = Registry.register(IRC.PubSub, "messages:private", [])
    conn
  end

  def sse_loop(conn) do
    {type, event, exit} = receive do
      {:event, :ping} -> {"ping", "ping", false}
      {:event, :expire} -> {"expire", "expire", true}
      {:irc, :text, %{account: account, text: token} = m} ->
        if String.downcase(String.trim(token)) == conn.assigns.token do
          path = LSG.AuthToken.new_path(account.id, conn.assigns.perks)
          m.replyfun.("ok!")
          {"authenticated", path, true}
        else
          {nil, nil, false}
        end
      _ -> {nil, nil, false}
    end

    conn = if type do
      send_sse_message(conn, type, event)
    else
      conn
    end

    if exit do
      conn
    else
      sse_loop(conn)
    end
  end

  defp send_sse_message(conn, type, data) do
    {:ok, conn} = chunk(conn, "event: #{type}\ndata: #{data}\n\n")
    conn
  end

end